diff --git a/src/crypto/gui/signencryptwizard.cpp b/src/crypto/gui/signencryptwizard.cpp index 8d9372857..f4f71e5e3 100644 --- a/src/crypto/gui/signencryptwizard.cpp +++ b/src/crypto/gui/signencryptwizard.cpp @@ -1,306 +1,306 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/signencryptwizard.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "signencryptwizard.h" #include "objectspage.h" #include "resolverecipientspage.h" #include "signerresolvepage.h" #include "resultpage.h" #include #include #include #include #include #include #include #include #include #include using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; using namespace GpgME; using namespace KMime::Types; class SignEncryptWizard::Private { friend class ::Kleo::Crypto::Gui::SignEncryptWizard; - SignEncryptWizard *q; + SignEncryptWizard *const q; public: explicit Private(SignEncryptWizard *qq); ~Private(); void setCommitPage(Page page); Gui::ResolveRecipientsPage *recipientResolvePage; // clashes with enum of same name SignerResolvePage *signerResolvePage; Gui::ObjectsPage *objectsPage; // clashes with enum of same name Gui::ResultPage *resultPage; // clashes with enum of same name }; SignEncryptWizard::Private::Private(SignEncryptWizard *qq) : q(qq), recipientResolvePage(new Gui::ResolveRecipientsPage), signerResolvePage(new SignerResolvePage), objectsPage(new Gui::ObjectsPage), resultPage(new Gui::ResultPage) { q->setPage(SignEncryptWizard::ResolveSignerPage, signerResolvePage); q->setPage(SignEncryptWizard::ObjectsPage, objectsPage); q->setPage(SignEncryptWizard::ResolveRecipientsPage, recipientResolvePage); q->setPage(SignEncryptWizard::ResultPage, resultPage); //TODO: move the RecipientPreferences creation out of here, don't create a new instance for each wizard recipientResolvePage->setRecipientPreferences(std::shared_ptr(new KConfigBasedRecipientPreferences(KSharedConfig::openConfig()))); signerResolvePage->setSigningPreferences(std::shared_ptr(new KConfigBasedSigningPreferences(KSharedConfig::openConfig()))); q->resize(QSize(640, 480).expandedTo(q->sizeHint())); } void SignEncryptWizard::onNext(int currentId) { if (currentId == ResolveRecipientsPage) { QTimer::singleShot(0, this, &SignEncryptWizard::recipientsResolved); } if (currentId == ResolveSignerPage) { //FIXME: Sign&Encrypt is only supported by OpenPGP. Remove this when we support this for CMS, too if (encryptionSelected() && signingSelected()) { setPresetProtocol(OpenPGP); } QTimer::singleShot(0, this, &SignEncryptWizard::signersResolved); } if (currentId == ObjectsPage) { QTimer::singleShot(0, this, &SignEncryptWizard::objectsResolved); } } SignEncryptWizard::Private::~Private() {} SignEncryptWizard::SignEncryptWizard(QWidget *p, Qt::WindowFlags f) : Wizard(p, f), d(new Private(this)) { } SignEncryptWizard::~SignEncryptWizard() {} void SignEncryptWizard::setCommitPage(Page page) { d->setCommitPage(page); } void SignEncryptWizard::Private::setCommitPage(Page page) { q->page(ResolveSignerPage)->setCommitPage(false); q->page(ResolveRecipientsPage)->setCommitPage(false); q->page(ObjectsPage)->setCommitPage(false); q->page(ResultPage)->setCommitPage(false); q->page(page)->setCommitPage(true); } void SignEncryptWizard::setPresetProtocol(Protocol proto) { d->signerResolvePage->setPresetProtocol(proto); d->signerResolvePage->setProtocolSelectionUserMutable(proto == UnknownProtocol); d->recipientResolvePage->setPresetProtocol(proto); } GpgME::Protocol SignEncryptWizard::selectedProtocol() const { return d->recipientResolvePage->selectedProtocol(); } GpgME::Protocol SignEncryptWizard::presetProtocol() const { return d->recipientResolvePage->presetProtocol(); } void SignEncryptWizard::setEncryptionSelected(bool selected) { d->signerResolvePage->setEncryptionSelected(selected); } void SignEncryptWizard::setSigningSelected(bool selected) { d->signerResolvePage->setSigningSelected(selected); } bool SignEncryptWizard::isSigningUserMutable() const { return d->signerResolvePage->isSigningUserMutable(); } void SignEncryptWizard::setSigningUserMutable(bool isMutable) { d->signerResolvePage->setSigningUserMutable(isMutable); } bool SignEncryptWizard::isEncryptionUserMutable() const { return d->signerResolvePage->isEncryptionUserMutable(); } bool SignEncryptWizard::isMultipleProtocolsAllowed() const { return d->recipientResolvePage->multipleProtocolsAllowed(); } void SignEncryptWizard::setMultipleProtocolsAllowed(bool allowed) { d->signerResolvePage->setMultipleProtocolsAllowed(allowed); d->recipientResolvePage->setMultipleProtocolsAllowed(allowed); } void SignEncryptWizard::setEncryptionUserMutable(bool isMutable) { d->signerResolvePage->setEncryptionUserMutable(isMutable); } void SignEncryptWizard::setFiles(const QStringList &files) { d->objectsPage->setFiles(files); } QFileInfoList SignEncryptWizard::resolvedFiles() const { const QStringList files = d->objectsPage->files(); QFileInfoList fileInfos; for (const QString &i : files) { fileInfos.push_back(QFileInfo(i)); } return fileInfos; } bool SignEncryptWizard::signingSelected() const { return d->signerResolvePage->signingSelected(); } bool SignEncryptWizard::encryptionSelected() const { return d->signerResolvePage->encryptionSelected(); } void SignEncryptWizard::setRecipients(const std::vector &recipients, const std::vector &encryptToSelfRecipients) { d->recipientResolvePage->setRecipients(recipients, encryptToSelfRecipients); } void SignEncryptWizard::setSignersAndCandidates(const std::vector &signers, const std::vector< std::vector > &keys) { d->signerResolvePage->setSignersAndCandidates(signers, keys); } void SignEncryptWizard::setTaskCollection(const std::shared_ptr &coll) { kleo_assert(coll); d->resultPage->setTaskCollection(coll); } std::vector SignEncryptWizard::resolvedCertificates() const { return d->recipientResolvePage->resolvedCertificates(); } std::vector SignEncryptWizard::resolvedSigners() const { return d->signerResolvePage->resolvedSigners(); } bool SignEncryptWizard::isAsciiArmorEnabled() const { return d->signerResolvePage->isAsciiArmorEnabled(); } void SignEncryptWizard::setAsciiArmorEnabled(bool enabled) { d->signerResolvePage->setAsciiArmorEnabled(enabled); } bool SignEncryptWizard::recipientsUserMutable() const { return d->recipientResolvePage->recipientsUserMutable(); } void SignEncryptWizard::setRecipientsUserMutable(bool isMutable) { d->recipientResolvePage->setRecipientsUserMutable(isMutable); } void SignEncryptWizard::setSignerResolvePageValidator(const std::shared_ptr &validator) { d->signerResolvePage->setValidator(validator); } Gui::SignerResolvePage *SignEncryptWizard::signerResolvePage() { return d->signerResolvePage; } const Gui::SignerResolvePage *SignEncryptWizard::signerResolvePage() const { return d->signerResolvePage; } Gui::ResolveRecipientsPage *SignEncryptWizard::resolveRecipientsPage() { return d->recipientResolvePage; } Gui::ObjectsPage *SignEncryptWizard::objectsPage() { return d->objectsPage; } Gui::ResultPage *SignEncryptWizard::resultPage() { return d->resultPage; } bool SignEncryptWizard::keepResultPageOpenWhenDone() const { return d->resultPage->keepOpenWhenDone(); } void SignEncryptWizard::setKeepResultPageOpenWhenDone(bool keep) { d->resultPage->setKeepOpenWhenDone(keep); } diff --git a/src/dialogs/addemaildialog.cpp b/src/dialogs/addemaildialog.cpp index 01d12b44c..2ea3913b6 100644 --- a/src/dialogs/addemaildialog.cpp +++ b/src/dialogs/addemaildialog.cpp @@ -1,127 +1,127 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/addemaildialog.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2019 g10 Code GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "addemaildialog.h" #include #include #include #include #include #include #include #include #include #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Dialogs; class AddEmailDialog::Private { public: Private(AddEmailDialog *qq): q(qq), mAdvancedSelected(false) { auto mainLay = new QVBoxLayout(q); auto btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); mOkButton = btnBox->button(QDialogButtonBox::Ok); QObject::connect (btnBox, &QDialogButtonBox::accepted, q, [this] () { q->accept(); }); QObject::connect (btnBox, &QDialogButtonBox::rejected, q, &QDialog::reject); btnBox->addButton(i18n("Advanced"), QDialogButtonBox::HelpRole); QObject::connect (btnBox, &QDialogButtonBox::helpRequested, q, [this] () { mAdvancedSelected = true; q->accept(); }); mainLay->addStretch(-1); auto emailLay = new QHBoxLayout; auto emailLbl = new QLabel(i18n("EMail") + QLatin1Char(':')); mEmailEdit = new QLineEdit(q); mEmailEdit->setValidator(Validation::email(mEmailEdit)); connect(mEmailEdit, &QLineEdit::textChanged, q, [this] () { mOkButton->setEnabled(!mEmailEdit->text().isEmpty() && mEmailEdit->hasAcceptableInput()); }); emailLbl->setBuddy(mEmailEdit); emailLay->addWidget(emailLbl); emailLay->addWidget(mEmailEdit); mainLay->addLayout(emailLay); mainLay->addWidget(btnBox); mOkButton->setEnabled(!mEmailEdit->text().isEmpty() && mEmailEdit->hasAcceptableInput()); } - AddEmailDialog *q; + AddEmailDialog *const q; QPushButton *mOkButton; QLineEdit *mEmailEdit; bool mAdvancedSelected; }; AddEmailDialog::AddEmailDialog(QWidget *parent): QDialog(parent), d(new Private(this)) { setWindowTitle(i18nc("@title:window", "Add New EMail")); } AddEmailDialog::~AddEmailDialog() { } void AddEmailDialog::setEmail(const QString &email) { return d->mEmailEdit->setText(email); } QString AddEmailDialog::email() const { return d->mEmailEdit->text().trimmed(); } bool AddEmailDialog::advancedSelected() { return d->mAdvancedSelected; } diff --git a/src/dialogs/certificatedetailswidget.cpp b/src/dialogs/certificatedetailswidget.cpp index ac526e53d..ef5696a1c 100644 --- a/src/dialogs/certificatedetailswidget.cpp +++ b/src/dialogs/certificatedetailswidget.cpp @@ -1,657 +1,657 @@ /* Copyright (c) 2016 Klarälvdalens Datakonsult AB 2017 Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "certificatedetailswidget.h" #include "ui_certificatedetailswidget.h" #include "kleopatra_debug.h" #include "exportdialog.h" #include "trustchainwidget.h" #include "subkeyswidget.h" #include "weboftrustdialog.h" #include "commands/changepassphrasecommand.h" #include "commands/changeexpirycommand.h" #include "commands/certifycertificatecommand.h" #include "commands/adduseridcommand.h" #include "commands/genrevokecommand.h" #include "commands/detailscommand.h" #include "commands/dumpcertificatecommand.h" #include "utils/remarks.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if GPGMEPP_VERSION >= 0x10E00 // 1.14.0 # define GPGME_HAS_REMARKS #endif #define HIDE_ROW(row) \ ui.row->setVisible(false); \ ui.row##Lbl->setVisible(false); Q_DECLARE_METATYPE(GpgME::UserID) using namespace Kleo; class CertificateDetailsWidget::Private { public: Private(CertificateDetailsWidget *parent) : updateInProgress (false), q(parent) {} void setupCommonProperties(); void setupPGPProperties(); void setupSMIMEProperties(); void revokeUID(const GpgME::UserID &uid); void genRevokeCert(); void certifyClicked(); void webOfTrustClicked(); void exportClicked(); void addUserID(); void changePassphrase(); void changeExpiration(); void keysMayHaveChanged(); void showTrustChainDialog(); void showMoreDetails(); void publishCertificate(); void userIDTableContextMenuRequested(const QPoint &p); QString tofuTooltipString(const GpgME::UserID &uid) const; void smimeLinkActivated(const QString &link); void setUpdatedKey(const GpgME::Key &key); void keyListDone(const GpgME::KeyListResult &, const std::vector &, const QString &, const GpgME::Error &); Ui::CertificateDetailsWidget ui; GpgME::Key key; bool updateInProgress; private: - CertificateDetailsWidget *q; + CertificateDetailsWidget *const q; }; void CertificateDetailsWidget::Private::setupCommonProperties() { // TODO: Enable once implemented HIDE_ROW(publishing) const bool hasSecret = key.hasSecret(); const bool isOpenPGP = key.protocol() == GpgME::OpenPGP; // TODO: Enable once implemented const bool canRevokeUID = false; // isOpenPGP && hasSecret ui.changePassphraseBtn->setVisible(hasSecret); ui.genRevokeBtn->setVisible(isOpenPGP && hasSecret); ui.certifyBtn->setVisible(isOpenPGP && !hasSecret); ui.changeExpirationBtn->setVisible(isOpenPGP && hasSecret); ui.addUserIDBtn->setVisible(hasSecret && isOpenPGP); ui.webOfTrustBtn->setVisible(isOpenPGP); ui.hboxLayout_1->addStretch(1); ui.validFrom->setText(Kleo::Formatting::creationDateString(key)); const QString expiry = Kleo::Formatting::expirationDateString(key); ui.expires->setText(expiry.isEmpty() ? i18nc("Expires", "never") : expiry); ui.type->setText(Kleo::Formatting::type(key)); ui.fingerprint->setText(Formatting::prettyID(key.primaryFingerprint())); if (Kleo::Formatting::complianceMode().isEmpty()) { HIDE_ROW(compliance) } else { ui.complianceLbl->setText(Kleo::Formatting::complianceStringForKey(key)); } ui.userIDTable->clear(); QStringList headers = { i18n("Email"), i18n("Name"), i18n("Trust Level"), i18n("Tags") }; if (canRevokeUID) { headers << QString(); } ui.userIDTable->setColumnCount(headers.count()); ui.userIDTable->setColumnWidth(0, 200); ui.userIDTable->setColumnWidth(1, 200); ui.userIDTable->setHeaderLabels(headers); const auto uids = key.userIDs(); for (unsigned int i = 0; i < uids.size(); ++i) { const auto &uid = uids[i]; auto item = new QTreeWidgetItem; const QString toolTip = tofuTooltipString(uid); item->setData(0, Qt::UserRole, QVariant::fromValue(uid)); auto pMail = Kleo::Formatting::prettyEMail(uid); auto pName = Kleo::Formatting::prettyName(uid); if (!isOpenPGP && pMail.isEmpty() && !pName.isEmpty()) { // S/MIME UserIDs are sometimes split, with one userID // containing the name another the Mail, we merge these // UID's into a single item. if (i + 1 < uids.size()) { pMail = Kleo::Formatting::prettyEMail(uids[i + 1]); // skip next uid ++i; } } if (!isOpenPGP && pMail.isEmpty() && pName.isEmpty()) { // S/MIME certificates sometimes contain urls where both // name and mail is empty. In that case we print whatever // the uid is as name. // // Can be ugly like (3:uri24:http://ca.intevation.org), but // this is better then showing an empty entry. pName = QString::fromLatin1(uid.id()); } item->setData(0, Qt::DisplayRole, pMail); item->setData(0, Qt::ToolTipRole, toolTip); item->setData(1, Qt::DisplayRole, pName); item->setData(1, Qt::ToolTipRole, toolTip); QIcon trustIcon; if (updateInProgress) { trustIcon = QIcon::fromTheme(QStringLiteral("emblem-question")); item->setData(2, Qt::DisplayRole, i18n("Updating...")); } else { switch (uid.validity()) { case GpgME::UserID::Unknown: case GpgME::UserID::Undefined: trustIcon = QIcon::fromTheme(QStringLiteral("emblem-question")); break; case GpgME::UserID::Never: trustIcon = QIcon::fromTheme(QStringLiteral("emblem-error")); break; case GpgME::UserID::Marginal: trustIcon = QIcon::fromTheme(QStringLiteral("emblem-warning")); break; case GpgME::UserID::Full: case GpgME::UserID::Ultimate: trustIcon = QIcon::fromTheme(QStringLiteral("emblem-success")); break; } item->setData(2, Qt::DisplayRole, Kleo::Formatting::validityShort(uid)); } item->setData(2, Qt::DecorationRole, trustIcon); item->setData(2, Qt::ToolTipRole, toolTip); GpgME::Error err; QStringList remarkList; #ifdef GPGME_HAS_REMARKS for (const auto &rem: uid.remarks(Remarks::remarkKeys(), err)) { remarkList << QString::fromStdString(rem); } #endif const auto remark = remarkList.join(QStringLiteral("; ")); item->setData(3, Qt::DisplayRole, remark); item->setData(3, Qt::ToolTipRole, toolTip); ui.userIDTable->addTopLevelItem(item); if (canRevokeUID) { auto button = new QPushButton; button->setIcon(QIcon::fromTheme(QStringLiteral("entry-delete"))); button->setToolTip(i18n("Revoke this User ID")); button->setMaximumWidth(32); QObject::connect(button, &QPushButton::clicked, q, [this, uid]() { revokeUID(uid); }); ui.userIDTable->setItemWidget(item, 4, button); } } if (!Remarks::remarksEnabled()) { ui.userIDTable->hideColumn(3); } } void CertificateDetailsWidget::Private::revokeUID(const GpgME::UserID &uid) { Q_UNUSED(uid); qCWarning(KLEOPATRA_LOG) << "Revoking UserID is not implemented. How did you even get here?!?!"; } void CertificateDetailsWidget::Private::changeExpiration() { auto cmd = new Kleo::Commands::ChangeExpiryCommand(key); QObject::connect(cmd, &Kleo::Commands::ChangeExpiryCommand::finished, q, [this]() { ui.changeExpirationBtn->setEnabled(true); }); ui.changeExpirationBtn->setEnabled(false); cmd->start(); } void CertificateDetailsWidget::Private::changePassphrase() { auto cmd = new Kleo::Commands::ChangePassphraseCommand(key); QObject::connect(cmd, &Kleo::Commands::ChangePassphraseCommand::finished, q, [this]() { ui.changePassphraseBtn->setEnabled(true); }); ui.changePassphraseBtn->setEnabled(false); cmd->start(); } void CertificateDetailsWidget::Private::genRevokeCert() { auto cmd = new Kleo::Commands::GenRevokeCommand(key); QObject::connect(cmd, &Kleo::Commands::GenRevokeCommand::finished, q, [this]() { ui.genRevokeBtn->setEnabled(true); }); ui.genRevokeBtn->setEnabled(false); cmd->start(); } void CertificateDetailsWidget::Private::certifyClicked() { auto cmd = new Kleo::Commands::CertifyCertificateCommand(key); QObject::connect(cmd, &Kleo::Commands::CertifyCertificateCommand::finished, q, [this]() { ui.certifyBtn->setEnabled(true); }); ui.certifyBtn->setEnabled(false); cmd->start(); } void CertificateDetailsWidget::Private::webOfTrustClicked() { QScopedPointer dlg(new WebOfTrustDialog(q)); dlg->setKey(key); dlg->exec(); } void CertificateDetailsWidget::Private::exportClicked() { QScopedPointer dlg(new ExportDialog(q)); dlg->setKey(key); dlg->exec(); } void CertificateDetailsWidget::Private::addUserID() { auto cmd = new Kleo::Commands::AddUserIDCommand(key); QObject::connect(cmd, &Kleo::Commands::AddUserIDCommand::finished, q, [this]() { ui.addUserIDBtn->setEnabled(true); key.update(); q->setKey(key); }); ui.addUserIDBtn->setEnabled(false); cmd->start(); } void CertificateDetailsWidget::Private::keysMayHaveChanged() { auto newKey = Kleo::KeyCache::instance()->findByFingerprint(key.primaryFingerprint()); if (!newKey.isNull()) { setUpdatedKey(newKey); } } void CertificateDetailsWidget::Private::showTrustChainDialog() { QScopedPointer dlg(new TrustChainDialog(q)); dlg->setKey(key); dlg->exec(); } void CertificateDetailsWidget::Private::publishCertificate() { qCWarning(KLEOPATRA_LOG) << "publishCertificateis not implemented."; //TODO } void CertificateDetailsWidget::Private::userIDTableContextMenuRequested(const QPoint &p) { auto item = ui.userIDTable->itemAt(p); if (!item) { return; } const auto userID = item->data(0, Qt::UserRole).value(); QMenu *menu = new QMenu(q); menu->addAction(QIcon::fromTheme(QStringLiteral("view-certificate-sign")), i18n("Certify ..."), q, [this, userID]() { auto cmd = new Kleo::Commands::CertifyCertificateCommand(userID); ui.userIDTable->setEnabled(false); connect(cmd, &Kleo::Commands::CertifyCertificateCommand::finished, q, [this]() { ui.userIDTable->setEnabled(true); // Trigger an update when done q->setKey(key); }); cmd->start(); }); connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ui.userIDTable->viewport()->mapToGlobal(p)); } void CertificateDetailsWidget::Private::showMoreDetails() { ui.moreDetailsBtn->setEnabled(false); if (key.protocol() == GpgME::CMS) { auto cmd = new Kleo::Commands::DumpCertificateCommand(key); connect(cmd, &Kleo::Commands::DumpCertificateCommand::finished, q, [this]() { ui.moreDetailsBtn->setEnabled(true); }); cmd->setUseDialog(true); cmd->start(); } else { QScopedPointer dlg(new SubKeysDialog(q)); dlg->setKey(key); dlg->exec(); ui.moreDetailsBtn->setEnabled(true); } } QString CertificateDetailsWidget::Private::tofuTooltipString(const GpgME::UserID &uid) const { const auto tofu = uid.tofuInfo(); if (tofu.isNull()) { return QString(); } QString html = QStringLiteral(""); const auto appendRow = [&html](const QString &lbl, const QString &val) { html += QStringLiteral("" "" "" "") .arg(lbl, val); }; const auto appendHeader = [this, &html](const QString &hdr) { html += QStringLiteral("") .arg(q->palette().highlight().color().name(), q->palette().highlightedText().color().name(), hdr); }; const auto dateTime = [](long ts) { QLocale l; return ts == 0 ? i18n("never") : l.toString(QDateTime::fromSecsSinceEpoch(ts), QLocale::ShortFormat); }; appendHeader(i18n("Signing")); appendRow(i18n("First message"), dateTime(tofu.signFirst())); appendRow(i18n("Last message"), dateTime(tofu.signLast())); appendRow(i18n("Message count"), QString::number(tofu.signCount())); appendHeader(i18n("Encryption")); appendRow(i18n("First message"), dateTime(tofu.encrFirst())); appendRow(i18n("Last message"), dateTime(tofu.encrLast())); appendRow(i18n("Message count"), QString::number(tofu.encrCount())); html += QStringLiteral("
%1:%2
%3
"); // Make sure the tooltip string is different for each UserID, even if the // data are the same, otherwise the tooltip is not updated and moved when // user moves mouse from one row to another. html += QStringLiteral("").arg(QString::fromUtf8(uid.id())); return html; } void CertificateDetailsWidget::Private::setupPGPProperties() { HIDE_ROW(smimeOwner) HIDE_ROW(smimeIssuer) ui.smimeRelatedAddresses->setVisible(false); ui.trustChainDetailsBtn->setVisible(false); ui.userIDTable->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui.userIDTable, &QAbstractItemView::customContextMenuRequested, q, [this](const QPoint &p) { userIDTableContextMenuRequested(p); }); } static QString formatDNToolTip(const Kleo::DN &dn) { QString html = QStringLiteral(""); const auto appendRow = [&html, dn](const QString &lbl, const QString &attr) { const QString val = dn[attr]; if (!val.isEmpty()) { html += QStringLiteral( "" "" "").arg(lbl, val); } }; appendRow(i18n("Common Name"), QStringLiteral("CN")); appendRow(i18n("Organization"), QStringLiteral("O")); appendRow(i18n("Street"), QStringLiteral("STREET")); appendRow(i18n("City"), QStringLiteral("L")); appendRow(i18n("State"), QStringLiteral("ST")); appendRow(i18n("Country"), QStringLiteral("C")); html += QStringLiteral("
%1:%2
"); return html; } void CertificateDetailsWidget::Private::setupSMIMEProperties() { HIDE_ROW(publishing) const auto ownerId = key.userID(0); const Kleo::DN dn(ownerId.id()); const QString cn = dn[QStringLiteral("CN")]; const QString o = dn[QStringLiteral("O")]; const QString dnEmail = dn[QStringLiteral("EMAIL")]; const QString name = cn.isEmpty() ? dnEmail : cn; QString owner; if (name.isEmpty()) { owner = dn.dn(); } else if (o.isEmpty()) { owner = name; } else { owner = i18nc(" of ", "%1 of %2", name, o); } ui.smimeOwner->setText(owner); ui.smimeOwner->setTextInteractionFlags(Qt::TextBrowserInteraction); const Kleo::DN issuerDN(key.issuerName()); const QString issuerCN = issuerDN[QStringLiteral("CN")]; const QString issuer = issuerCN.isEmpty() ? QString::fromUtf8(key.issuerName()) : issuerCN; ui.smimeIssuer->setText(QStringLiteral("%1").arg(issuer)); ui.smimeIssuer->setToolTip(formatDNToolTip(issuerDN)); ui.smimeOwner->setToolTip(formatDNToolTip(dn)); } void CertificateDetailsWidget::Private::smimeLinkActivated(const QString &link) { if (link == QLatin1String("#issuerDetails")) { const auto parentKey = KeyCache::instance()->findIssuers(key, KeyCache::NoOption); if (!parentKey.size()) { return; } auto cmd = new Kleo::Commands::DetailsCommand(parentKey[0], nullptr); cmd->setParentWidget(q); cmd->start(); return; } qCWarning(KLEOPATRA_LOG) << "Unknown link activated:" << link; } CertificateDetailsWidget::CertificateDetailsWidget(QWidget *parent) : QWidget(parent) , d(new Private(this)) { d->ui.setupUi(this); connect(d->ui.addUserIDBtn, &QPushButton::clicked, this, [this]() { d->addUserID(); }); connect(d->ui.changePassphraseBtn, &QPushButton::clicked, this, [this]() { d->changePassphrase(); }); connect(d->ui.genRevokeBtn, &QPushButton::clicked, this, [this]() { d->genRevokeCert(); }); connect(d->ui.changeExpirationBtn, &QPushButton::clicked, this, [this]() { d->changeExpiration(); }); connect(d->ui.smimeOwner, &QLabel::linkActivated, this, [this](const QString &link) { d->smimeLinkActivated(link); }); connect(d->ui.smimeIssuer, &QLabel::linkActivated, this, [this](const QString &link) { d->smimeLinkActivated(link); }); connect(d->ui.trustChainDetailsBtn, &QPushButton::pressed, this, [this]() { d->showTrustChainDialog(); }); connect(d->ui.moreDetailsBtn, &QPushButton::pressed, this, [this]() { d->showMoreDetails(); }); connect(d->ui.publishing, &QPushButton::pressed, this, [this]() { d->publishCertificate(); }); connect(d->ui.certifyBtn, &QPushButton::clicked, this, [this]() { d->certifyClicked(); }); connect(d->ui.webOfTrustBtn, &QPushButton::clicked, this, [this]() { d->webOfTrustClicked(); }); connect(d->ui.exportBtn, &QPushButton::clicked, this, [this]() { d->exportClicked(); }); connect(Kleo::KeyCache::instance().get(), &Kleo::KeyCache::keysMayHaveChanged, this, [this]() { d->keysMayHaveChanged(); }); } CertificateDetailsWidget::~CertificateDetailsWidget() { } void CertificateDetailsWidget::Private::keyListDone(const GpgME::KeyListResult &, const std::vector &keys, const QString &, const GpgME::Error &) { updateInProgress = false; if (keys.size() != 1) { qCWarning(KLEOPATRA_LOG) << "Invalid keylist result in update."; return; } // As we listen for keysmayhavechanged we get the update // after updating the keycache. KeyCache::mutableInstance()->insert(keys); } void CertificateDetailsWidget::Private::setUpdatedKey(const GpgME::Key &k) { key = k; setupCommonProperties(); if (key.protocol() == GpgME::OpenPGP) { setupPGPProperties(); } else { setupSMIMEProperties(); } } void CertificateDetailsWidget::setKey(const GpgME::Key &key) { if (key.protocol() == GpgME::CMS) { // For everything but S/MIME this should be quick // and we don't need to show another status. d->updateInProgress = true; } d->setUpdatedKey(key); // Run a keylistjob with full details (TOFU / Validate) QGpgME::KeyListJob *job = key.protocol() == GpgME::OpenPGP ? QGpgME::openpgp()->keyListJob(false, true, true) : QGpgME::smime()->keyListJob(false, true, true); auto ctx = QGpgME::Job::context(job); ctx->addKeyListMode(GpgME::WithTofu); ctx->addKeyListMode(GpgME::Signatures); ctx->addKeyListMode(GpgME::SignatureNotations); // Windows QGpgME new style connect problem makes this necessary. connect(job, SIGNAL(result(GpgME::KeyListResult,std::vector,QString,GpgME::Error)), this, SLOT(keyListDone(GpgME::KeyListResult,std::vector,QString,GpgME::Error))); job->start(QStringList() << QLatin1String(key.primaryFingerprint()), key.hasSecret()); } GpgME::Key CertificateDetailsWidget::key() const { return d->key; } CertificateDetailsDialog::CertificateDetailsDialog(QWidget *parent) : QDialog(parent) { setWindowTitle(i18nc("@title:window", "Certificate Details")); auto l = new QVBoxLayout(this); l->addWidget(new CertificateDetailsWidget(this)); auto bbox = new QDialogButtonBox(this); auto btn = bbox->addButton(QDialogButtonBox::Close); connect(btn, &QPushButton::pressed, this, &QDialog::accept); l->addWidget(bbox); readConfig(); } CertificateDetailsDialog::~CertificateDetailsDialog() { writeConfig(); } void CertificateDetailsDialog::readConfig() { KConfigGroup dialog(KSharedConfig::openConfig(), "CertificateDetailsDialog"); const QSize size = dialog.readEntry("Size", QSize(730, 280)); if (size.isValid()) { resize(size); } } void CertificateDetailsDialog::writeConfig() { KConfigGroup dialog(KSharedConfig::openConfig(), "CertificateDetailsDialog"); dialog.writeEntry("Size", size()); dialog.sync(); } void CertificateDetailsDialog::setKey(const GpgME::Key &key) { auto w = findChild(); Q_ASSERT(w); w->setKey(key); } GpgME::Key CertificateDetailsDialog::key() const { auto w = findChild(); Q_ASSERT(w); return w->key(); } #include "moc_certificatedetailswidget.cpp" diff --git a/src/dialogs/certifywidget.cpp b/src/dialogs/certifywidget.cpp index bd65021ab..73bdbfb30 100644 --- a/src/dialogs/certifywidget.cpp +++ b/src/dialogs/certifywidget.cpp @@ -1,492 +1,492 @@ /* dialogs/certifywidget.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2019 by g10code GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "certifywidget.h" #include "kleopatra_debug.h" #include "utils/remarks.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if GPGMEPP_VERSION >= 0x10E00 // 1.14.0 # define GPGME_HAS_REMARKS #endif using namespace Kleo; namespace { // Maybe move this in its own file // based on code from StackOverflow class AnimatedExpander: public QWidget { Q_OBJECT public: explicit AnimatedExpander(const QString &title = QString(), const int animationDuration = 300, QWidget *parent = nullptr); void setContentLayout(QLayout *contentLayout); private: QGridLayout mainLayout; QToolButton toggleButton; QFrame headerLine; QParallelAnimationGroup toggleAnimation; QScrollArea contentArea; int animationDuration{300}; }; AnimatedExpander::AnimatedExpander(const QString &title, const int animationDuration, QWidget *parent): QWidget(parent), animationDuration(animationDuration) { toggleButton.setStyleSheet(QStringLiteral("QToolButton { border: none; }")); toggleButton.setToolButtonStyle(Qt::ToolButtonTextBesideIcon); toggleButton.setArrowType(Qt::ArrowType::RightArrow); toggleButton.setText(title); toggleButton.setCheckable(true); toggleButton.setChecked(false); headerLine.setFrameShape(QFrame::HLine); headerLine.setFrameShadow(QFrame::Sunken); headerLine.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); contentArea.setStyleSheet(QStringLiteral("QScrollArea { border: none; }")); contentArea.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); // start out collapsed contentArea.setMaximumHeight(0); contentArea.setMinimumHeight(0); // let the entire widget grow and shrink with its content toggleAnimation.addAnimation(new QPropertyAnimation(this, "minimumHeight")); toggleAnimation.addAnimation(new QPropertyAnimation(this, "maximumHeight")); toggleAnimation.addAnimation(new QPropertyAnimation(&contentArea, "maximumHeight")); mainLayout.setVerticalSpacing(0); mainLayout.setContentsMargins(0, 0, 0, 0); int row = 0; mainLayout.addWidget(&toggleButton, row, 0, 1, 1, Qt::AlignLeft); mainLayout.addWidget(&headerLine, row++, 2, 1, 1); mainLayout.addWidget(&contentArea, row, 0, 1, 3); setLayout(&mainLayout); QObject::connect(&toggleButton, &QToolButton::clicked, [this](const bool checked) { toggleButton.setArrowType(checked ? Qt::ArrowType::DownArrow : Qt::ArrowType::RightArrow); toggleAnimation.setDirection(checked ? QAbstractAnimation::Forward : QAbstractAnimation::Backward); toggleAnimation.start(); }); } void AnimatedExpander::setContentLayout(QLayout *contentLayout) { delete contentArea.layout(); contentArea.setLayout(contentLayout); const auto collapsedHeight = sizeHint().height() - contentArea.maximumHeight(); auto contentHeight = contentLayout->sizeHint().height(); for (int i = 0; i < toggleAnimation.animationCount() - 1; ++i) { auto expanderAnimation = static_cast(toggleAnimation.animationAt(i)); expanderAnimation->setDuration(animationDuration); expanderAnimation->setStartValue(collapsedHeight); expanderAnimation->setEndValue(collapsedHeight + contentHeight); } auto contentAnimation = static_cast(toggleAnimation.animationAt(toggleAnimation.animationCount() - 1)); contentAnimation->setDuration(animationDuration); contentAnimation->setStartValue(0); contentAnimation->setEndValue(contentHeight); } class SecKeyFilter: public DefaultKeyFilter { public: SecKeyFilter() : DefaultKeyFilter() { setRevoked(DefaultKeyFilter::NotSet); setExpired(DefaultKeyFilter::NotSet); setHasSecret(DefaultKeyFilter::Set); setCanCertify(DefaultKeyFilter::Set); setIsOpenPGP(DefaultKeyFilter::Set); } }; class UserIDModel : public QStandardItemModel { Q_OBJECT public: enum Role { UserIDIndex = Qt::UserRole }; explicit UserIDModel(QObject *parent = nullptr) : QStandardItemModel(parent) {} GpgME::Key certificateToCertify() const { return m_key; } void setKey(const GpgME::Key &key) { m_key = key; clear(); const std::vector ids = key.userIDs(); int i = 0; for (const auto &uid: key.userIDs()) { if (uid.isRevoked() || uid.isInvalid()) { // Skip user ID's that cannot really be certified. i++; continue; } QStandardItem *const item = new QStandardItem; item->setText(Formatting::prettyUserID(uid)); item->setData(i, UserIDIndex); item->setCheckable(true); item->setEditable(false); item->setCheckState(Qt::Checked); appendRow(item); i++; } } void setCheckedUserIDs(const std::vector &uids) { std::vector sorted = uids; std::sort(sorted.begin(), sorted.end()); for (int i = 0, end = rowCount(); i != end; ++i) { item(i)->setCheckState(std::binary_search(sorted.begin(), sorted.end(), i) ? Qt::Checked : Qt::Unchecked); } } std::vector checkedUserIDs() const { std::vector ids; for (int i = 0; i < rowCount(); ++i) { if (item(i)->checkState() == Qt::Checked) { ids.push_back(item(i)->data(UserIDIndex).toUInt()); } } qCDebug(KLEOPATRA_LOG) << "Checked uids are: " << ids; return ids; } private: GpgME::Key m_key; }; static bool uidEqual(const GpgME::UserID &lhs, const GpgME::UserID &rhs) { return qstrcmp(lhs.parent().primaryFingerprint(), rhs.parent().primaryFingerprint()) == 0 && qstrcmp(lhs.id(), rhs.id()) == 0; } } // anonymous namespace // Use of pimpl as this might be moved to libkleo class CertifyWidget::Private { public: Private(CertifyWidget *qq) : q(qq), mFprLabel(new QLabel), remarkTextChanged(false) { QVBoxLayout *mainLay = new QVBoxLayout(q); mainLay->addWidget(mFprLabel); auto secKeyLay = new QHBoxLayout; secKeyLay->addWidget(new QLabel(i18n("Certify with:"))); mSecKeySelect = new KeySelectionCombo(true); mSecKeySelect->setKeyFilter(std::shared_ptr(new SecKeyFilter())); secKeyLay->addWidget(mSecKeySelect, 1); mainLay->addLayout(secKeyLay); auto splitLine = new QFrame; splitLine->setFrameShape(QFrame::HLine); splitLine->setFrameShadow(QFrame::Sunken); splitLine->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); mainLay->addWidget(splitLine); auto listView = new QListView; listView->setModel(&mUserIDModel); mainLay->addWidget(listView, 1); // Setup the advanced area auto expander = new AnimatedExpander(i18n("Advanced")); mainLay->addWidget(expander); auto advLay = new QVBoxLayout; mExportCB = new QCheckBox(i18n("Certify for everyone to see. (exportable)")); mPublishCB = new QCheckBox(i18n("Publish on keyserver afterwards.")); auto publishLay = new QHBoxLayout; publishLay->addSpacing(20); publishLay->addWidget(mPublishCB); mRemarkLE = new QLineEdit; mRemarkLE->setPlaceholderText(i18n("Tags")); auto infoBtn = new QPushButton; infoBtn->setIcon(QIcon::fromTheme(QStringLiteral("help-contextual"))); infoBtn->setFlat(true); connect(infoBtn, &QPushButton::clicked, q, [this, infoBtn] () { const QString msg = i18n("You can use this to add additional info to a " "certification.") + QStringLiteral("

") + i18n("Tags created by anyone with full certification trust " "are shown in the keylist and can be searched."); QToolTip::showText(infoBtn->mapToGlobal(QPoint()) + QPoint(infoBtn->width(), 0), msg, infoBtn, QRect(), 30000); }); auto remarkLay = new QHBoxLayout; remarkLay->addWidget(infoBtn); remarkLay->addWidget(mRemarkLE); advLay->addWidget(mExportCB); advLay->addLayout(publishLay); advLay->addLayout(remarkLay); #ifndef GPGME_HAS_REMARKS // Hide it if we do not have remark support mRemarkLE->setVisible(false); infoBtn->setVisible(false); #endif expander->setContentLayout(advLay); mPublishCB->setEnabled(false); connect(mExportCB, &QCheckBox::toggled, [this] (bool on) { mPublishCB->setEnabled(on); }); connect(mSecKeySelect, &KeySelectionCombo::currentKeyChanged, [this] (const GpgME::Key &) { #ifdef GPGME_HAS_REMARKS updateRemark(); #endif }); loadConfig(); } ~Private() { } void loadConfig() { const KConfigGroup conf(KSharedConfig::openConfig(), "CertifySettings"); mSecKeySelect->setDefaultKey(conf.readEntry("LastKey", QString())); mExportCB->setChecked(conf.readEntry("ExportCheckState", false)); mPublishCB->setChecked(conf.readEntry("PublishCheckState", false)); } void updateRemark() { if (mRemarkLE->isModified()) { return; } #ifdef GPGME_HAS_REMARKS GpgME::Key remarkKey = mSecKeySelect->currentKey(); if (!remarkKey.isNull()) { std::vector uidsWithRemark; QString remark; for (const auto &uid: mTarget.userIDs()) { GpgME::Error err; const char *c_remark = uid.remark(remarkKey, err); if (c_remark) { const QString candidate = QString::fromUtf8(c_remark); if (candidate != remark) { qCDebug(KLEOPATRA_LOG) << "Different remarks on user ids. Taking last."; remark = candidate; uidsWithRemark.clear(); } uidsWithRemark.push_back(uid); } } // Only select the user ids with the correct remark if (!remark.isEmpty()) { selectUserIDs(uidsWithRemark); } mRemarkLE->setText(remark); } #endif } void setTarget(const GpgME::Key &key) { mFprLabel->setText(i18n("Fingerprint: %1", Formatting::prettyID(key.primaryFingerprint())) + QStringLiteral("
") + i18n("Only the fingerprint clearly identifies the key and its owner.")); mUserIDModel.setKey(key); mTarget = key; updateRemark(); } GpgME::Key secKey() const { return mSecKeySelect->currentKey(); } void selectUserIDs(const std::vector &uids) { const auto all = mTarget.userIDs(); std::vector indexes; indexes.reserve(uids.size()); for (const auto &uid: uids) { const unsigned int idx = std::distance(all.cbegin(), std::find_if(all.cbegin(), all.cend(), [uid](const GpgME::UserID &other) { return uidEqual(uid, other); })); if (idx < all.size()) { indexes.push_back(idx); } } mUserIDModel.setCheckedUserIDs(indexes); } std::vector selectedUserIDs() const { return mUserIDModel.checkedUserIDs(); } bool exportableSelected() const { return mExportCB->isChecked(); } bool publishSelected() const { return mPublishCB->isChecked(); } QString remarks() const { return mRemarkLE->text().trimmed(); } GpgME::Key target() const { return mTarget; } private: - CertifyWidget *q; + CertifyWidget *const q; QLabel *mFprLabel; KeySelectionCombo *mSecKeySelect; QCheckBox *mExportCB; QCheckBox *mPublishCB; QLineEdit *mRemarkLE; UserIDModel mUserIDModel; GpgME::Key mTarget; bool remarkTextChanged; }; CertifyWidget::CertifyWidget(QWidget *parent) : QWidget(parent), d(new Private(this)) { } void CertifyWidget::setTarget(const GpgME::Key &key) { d->setTarget(key); } GpgME::Key CertifyWidget::target() const { return d->target(); } void CertifyWidget::selectUserIDs(const std::vector &uids) { d->selectUserIDs(uids); } std::vector CertifyWidget::selectedUserIDs() const { return d->selectedUserIDs(); } GpgME::Key CertifyWidget::secKey() const { return d->secKey(); } bool CertifyWidget::exportableSelected() const { return d->exportableSelected(); } QString CertifyWidget::remarks() const { return d->remarks(); } bool CertifyWidget::publishSelected() const { return d->publishSelected(); } // For UserID model #include "certifywidget.moc" diff --git a/src/dialogs/exportdialog.cpp b/src/dialogs/exportdialog.cpp index af973e66b..7b56264af 100644 --- a/src/dialogs/exportdialog.cpp +++ b/src/dialogs/exportdialog.cpp @@ -1,199 +1,199 @@ /* Copyright (c) 2017 Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "exportdialog.h" #include "kleopatra_debug.h" #include "view/waitwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace Kleo; class ExportWidget::Private { public: Private(ExportWidget *qq) : q(qq) {} void setupUi(); GpgME::Key key; QTextEdit *textEdit; WaitWidget *waitWidget; private: - ExportWidget *q; + ExportWidget *const q; }; void ExportWidget::Private::setupUi() { auto vlay = new QVBoxLayout(q); vlay->setContentsMargins(0, 0, 0, 0); textEdit = new QTextEdit; textEdit->setVisible(false); textEdit->setReadOnly(true); auto fixedFont = QFont(QStringLiteral("Monospace")); fixedFont.setStyleHint(QFont::TypeWriter); textEdit->setFont(fixedFont); textEdit->setReadOnly(true); vlay->addWidget(textEdit); waitWidget = new WaitWidget; waitWidget->setText(i18n("Exporting ...")); vlay->addWidget(waitWidget); } ExportWidget::ExportWidget(QWidget *parent) : QWidget(parent) , d(new Private(this)) { d->setupUi(); } ExportWidget::~ExportWidget() { } static QString injectComments(const GpgME::Key &key, const QByteArray &data) { QString ret = QString::fromUtf8(data); if (key.protocol() != GpgME::OpenPGP) { return ret; } auto overView = Formatting::toolTip(key, Formatting::Fingerprint | Formatting::UserIDs | Formatting::Issuer | Formatting::Subject | Formatting::ExpiryDates | Formatting::CertificateType | Formatting::CertificateUsage); // Fixup the HTML coming from the toolTip for our own format. overView.remove(QLatin1String("")); overView.replace(QLatin1String(""), QLatin1String("\t")); overView.replace(QLatin1String(""), QLatin1String("\n")); overView.remove(QLatin1String("")); overView.remove(QLatin1String("\n
")); overView.replace(QLatin1String("<"), QLatin1String("<")); overView.replace(QLatin1String(">"), QLatin1String(">")); auto overViewLines = overView.split(QLatin1Char('\n')); // Format comments so that they fit for RFC 4880 auto comments = QStringLiteral("Comment: "); comments += overViewLines.join(QLatin1String("\nComment: ")) + QLatin1Char('\n'); ret.insert(37 /* -----BEGIN PGP PUBLIC KEY BLOCK-----\n */, comments); return ret; } void ExportWidget::exportResult(const GpgME::Error &err, const QByteArray &data) { d->waitWidget->setVisible(false); d->textEdit->setVisible(true); if (err) { /* Should not happen. But well,.. */ d->textEdit->setText(i18nc("%1 is error message", "Failed to export: '%1'", QString::fromLatin1(err.asString()))); } d->textEdit->setText(injectComments(d->key, data)); } void ExportWidget::setKey(const GpgME::Key &key) { d->waitWidget->setVisible(true); d->textEdit->setVisible(false); d->key = key; auto protocol = key.protocol() == GpgME::CMS ? QGpgME::smime() : QGpgME::openpgp(); auto job = protocol->publicKeyExportJob(true); /* New style connect does not work on Windows. */ connect(job, &QGpgME::ExportJob::result, this, &ExportWidget::exportResult); job->start(QStringList() << QLatin1String(key.primaryFingerprint())); } GpgME::Key ExportWidget::key() const { return d->key; } ExportDialog::ExportDialog(QWidget *parent) : QDialog(parent), mWidget(new ExportWidget(this)) { KConfigGroup dialog(KSharedConfig::openConfig(), "ExportDialog"); const auto size = dialog.readEntry("Size", QSize(600, 800)); if (size.isValid()) { resize(size); } setWindowTitle(i18nc("@title:window", "Export")); auto l = new QVBoxLayout(this); l->addWidget(mWidget); auto bbox = new QDialogButtonBox(this); auto btn = bbox->addButton(QDialogButtonBox::Close); connect(btn, &QPushButton::pressed, this, &QDialog::accept); l->addWidget(bbox); } ExportDialog::~ExportDialog() { KConfigGroup dialog(KSharedConfig::openConfig(), "ExportDialog"); dialog.writeEntry("Size", size()); dialog.sync(); } void ExportDialog::setKey(const GpgME::Key &key) { mWidget->setKey(key); } GpgME::Key ExportDialog::key() const { return mWidget->key(); } diff --git a/src/dialogs/gencardkeydialog.cpp b/src/dialogs/gencardkeydialog.cpp index d4131896e..6d5e36a13 100644 --- a/src/dialogs/gencardkeydialog.cpp +++ b/src/dialogs/gencardkeydialog.cpp @@ -1,169 +1,169 @@ /* dialogs/gencardkeydialog.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2017 by Bundesamt für Sicherheit in der Informationstechnik Software engineering by Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "gencardkeydialog.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace Kleo; class GenCardKeyDialog::Private { public: Private(GenCardKeyDialog *qq): q(qq) { auto *vBox = new QVBoxLayout(q); auto *grid = new QGridLayout; vBox->addLayout(grid); auto bbox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, qq); mOkButton = bbox->button(QDialogButtonBox::Ok); mOkButton->setDefault(true); mOkButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(bbox, &QDialogButtonBox::rejected, q, [this]() {q->reject();}); connect(bbox, &QDialogButtonBox::accepted, q, [this]() {accept();}); vBox->addWidget(bbox); const KEMailSettings e; mNameEdit = new QLineEdit(e.getSetting(KEMailSettings::RealName)); mEmailEdit = new QLineEdit(e.getSetting(KEMailSettings::EmailAddress)); connect(mEmailEdit, &QLineEdit::textChanged, q, [this]() {checkAcceptable();}); auto nameLabel = new QLabel(i18n("Name:")); auto mailLabel = new QLabel(i18n("EMail:")); mInvalidEmailLabel = new QLabel(QStringLiteral("%2").arg( KColorScheme(QPalette::Active, KColorScheme::View).foreground(KColorScheme::NegativeText).color().name(), i18n("Invalid EMail"))); int row = 0; grid->addWidget(nameLabel, row, 0); grid->addWidget(mNameEdit, row++, 1); grid->addWidget(mailLabel, row, 0); grid->addWidget(mEmailEdit, row++, 1); grid->addWidget(mInvalidEmailLabel, row++, 1); // In the future GnuPG may support more algos but for now // (2.1.18) we are stuck with RSA for on card generation. auto rsaLabel = new QLabel(i18n("RSA Keysize:")); mKeySizeCombo = new QComboBox; grid->addWidget(rsaLabel, row, 0); grid->addWidget(mKeySizeCombo, row++, 1); mBackupCheckBox = new QCheckBox(i18n("Backup encryption key")); mBackupCheckBox->setToolTip(i18n("Backup the encryption key in a file.") + QStringLiteral("
") + i18n("You will be asked for a passphrase to protect that file during key generation.")); mBackupCheckBox->setChecked(true); grid->addWidget(mBackupCheckBox, row++, 0, 1, 2); q->setMinimumWidth(400); checkAcceptable(); } void accept() { params.name = mNameEdit->text(); params.email = mEmailEdit->text(); params.keysize = mKeySizeCombo->currentText().toInt(); params.algo = GpgME::Subkey::AlgoRSA; params.backup = mBackupCheckBox->isChecked(); q->accept(); } void setSupportedSizes(const std::vector &sizes) { mKeySizeCombo->clear(); for (auto size: sizes) { mKeySizeCombo->addItem(QString::number(size)); } mKeySizeCombo->setCurrentIndex(mKeySizeCombo->findText(QStringLiteral("2048"))); } void checkAcceptable() { // We only require a valid mail address const QString mail = mEmailEdit->text(); if (!mail.isEmpty() && KEmailAddress::isValidSimpleAddress(mail)) { mOkButton->setEnabled(true); mInvalidEmailLabel->hide(); return; } if (!mail.isEmpty()) { mInvalidEmailLabel->show(); } else { mInvalidEmailLabel->hide(); } mOkButton->setEnabled(false); } - GenCardKeyDialog *q; + GenCardKeyDialog *const q; KeyParams params; QPushButton *mOkButton; QLineEdit *mNameEdit; QLineEdit *mEmailEdit; QLabel *mInvalidEmailLabel; QComboBox *mKeySizeCombo; QCheckBox *mBackupCheckBox; }; GenCardKeyDialog::GenCardKeyDialog(QWidget *parent) : QDialog(parent), d(new Private(this)) { } void GenCardKeyDialog::setSupportedSizes(const std::vector &sizes) { d->setSupportedSizes(sizes); } GenCardKeyDialog::KeyParams GenCardKeyDialog::getKeyParams() const { return d->params; } diff --git a/src/dialogs/ownertrustdialog.cpp b/src/dialogs/ownertrustdialog.cpp index c28eb0cbe..5faa1d7b6 100644 --- a/src/dialogs/ownertrustdialog.cpp +++ b/src/dialogs/ownertrustdialog.cpp @@ -1,209 +1,209 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/ownertrustdialog.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "ownertrustdialog.h" #include "ui_ownertrustdialog.h" #include #include #include #include #include using namespace Kleo; using namespace Kleo::Dialogs; using namespace GpgME; class OwnerTrustDialog::Private { friend class ::Kleo::Dialogs::OwnerTrustDialog; OwnerTrustDialog *const q; public: explicit Private(OwnerTrustDialog *qq) : q(qq), formattedCertificateName(i18n("(unknown certificate)")), originalTrust(Key::Undefined), hasSecret(false), advancedMode(false), ui(qq) { } private: void slotTrustLevelChanged() { enableDisableWidgets(); } void enableDisableWidgets(); private: QString formattedCertificateName; Key::OwnerTrust originalTrust; bool hasSecret : 1; bool advancedMode : 1; struct UI : public Ui::OwnerTrustDialog { explicit UI(Dialogs::OwnerTrustDialog *qq) : Ui::OwnerTrustDialog(), q(qq) { QWidget *mainWidget = new QWidget(q); setupUi(mainWidget); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QVBoxLayout *mainLayout = new QVBoxLayout(q); mainLayout->addWidget(mainWidget); okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); q->connect(buttonBox, &QDialogButtonBox::accepted, q, &QDialog::accept); q->connect(buttonBox, &QDialogButtonBox::rejected, q, &QDialog::reject); mainLayout->addWidget(buttonBox); } QPushButton *okPB() const { return okButton; } QPushButton *okButton; - Dialogs::OwnerTrustDialog *q; + Dialogs::OwnerTrustDialog *const q; } ui; }; OwnerTrustDialog::OwnerTrustDialog(QWidget *p) : QDialog(p), d(new Private(this)) { connect(d->ui.unknownRB, SIGNAL(toggled(bool)), this, SLOT(slotTrustLevelChanged())); connect(d->ui.neverRB, SIGNAL(toggled(bool)), this, SLOT(slotTrustLevelChanged())); connect(d->ui.marginalRB, SIGNAL(toggled(bool)), this, SLOT(slotTrustLevelChanged())); connect(d->ui.fullRB, SIGNAL(toggled(bool)), this, SLOT(slotTrustLevelChanged())); connect(d->ui.ultimateRB, SIGNAL(toggled(bool)), this, SLOT(slotTrustLevelChanged())); } OwnerTrustDialog::~OwnerTrustDialog() {} void OwnerTrustDialog::setFormattedCertificateName(const QString &formatted) { if (formatted.isEmpty()) { return; } d->formattedCertificateName = formatted; setWindowTitle(i18nc("@title:window", "Change Trust Level of %1", formatted)); d->ui.label->setText(i18nc("@info", "How much do you trust certifications made by %1 to correctly verify authenticity of certificates?", formatted)); } QString OwnerTrustDialog::formattedCertificateName() const { return d->formattedCertificateName; } void OwnerTrustDialog::setHasSecretKey(bool secret) { d->hasSecret = secret; d->enableDisableWidgets(); setOwnerTrust(ownerTrust()); } bool OwnerTrustDialog::hasSecretKey() const { return d->hasSecret; } void OwnerTrustDialog::setAdvancedMode(bool advanced) { d->advancedMode = advanced; d->enableDisableWidgets(); setOwnerTrust(ownerTrust()); } bool OwnerTrustDialog::isAdvancedMode() const { return d->advancedMode; } void OwnerTrustDialog::Private::enableDisableWidgets() { ui.unknownRB ->setEnabled(!hasSecret || advancedMode); ui.neverRB ->setEnabled(!hasSecret || advancedMode); ui.marginalRB->setEnabled(!hasSecret || advancedMode); ui.fullRB ->setEnabled(!hasSecret || advancedMode); ui.ultimateRB->setEnabled(hasSecret || advancedMode); ui.okPB()->setEnabled(q->ownerTrust() != Key::Undefined && q->ownerTrust() != originalTrust); } static void force_set_checked(QAbstractButton *b, bool on) { // work around Qt bug (tested: 4.1.4, 4.2.3, 4.3.4) const bool autoExclusive = b->autoExclusive(); b->setAutoExclusive(false); b->setChecked(b->isEnabled() && on); b->setAutoExclusive(autoExclusive); } void OwnerTrustDialog::setOwnerTrust(Key::OwnerTrust trust) { d->originalTrust = trust; force_set_checked(d->ui.unknownRB, trust == Key::Unknown); force_set_checked(d->ui.neverRB, trust == Key::Never); force_set_checked(d->ui.marginalRB, trust == Key::Marginal); force_set_checked(d->ui.fullRB, trust == Key::Full); force_set_checked(d->ui.ultimateRB, trust == Key::Ultimate); d->enableDisableWidgets(); } Key::OwnerTrust OwnerTrustDialog::ownerTrust() const { if (d->ui.unknownRB->isChecked()) { return Key::Unknown; } if (d->ui.neverRB->isChecked()) { return Key::Never; } if (d->ui.marginalRB->isChecked()) { return Key::Marginal; } if (d->ui.fullRB->isChecked()) { return Key::Full; } if (d->ui.ultimateRB->isChecked()) { return Key::Ultimate; } return Key::Undefined; } #include "moc_ownertrustdialog.cpp" diff --git a/src/dialogs/subkeyswidget.cpp b/src/dialogs/subkeyswidget.cpp index abc74933e..6a503c1b7 100644 --- a/src/dialogs/subkeyswidget.cpp +++ b/src/dialogs/subkeyswidget.cpp @@ -1,217 +1,217 @@ /* Copyright (c) 2016 Klarälvdalens Datakonsult AB 2017 by Bundesamt für Sicherheit in der Informationstechnik Software engineering by Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "subkeyswidget.h" #include "ui_subkeyswidget.h" #include "smartcard/readerstatus.h" #include "commands/keytocardcommand.h" #include "commands/importpaperkeycommand.h" #include #include #include #include #include #include #include #include Q_DECLARE_METATYPE(GpgME::Subkey) using namespace Kleo; class SubKeysWidget::Private { public: Private(SubKeysWidget *q) : q(q) { ui.setupUi(q); ui.subkeysTree->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui.subkeysTree, &QAbstractItemView::customContextMenuRequested, q, [this](const QPoint &p) { tableContextMenuRequested(p); }); } GpgME::Key key; Ui::SubKeysWidget ui; void tableContextMenuRequested(const QPoint &p); private: - SubKeysWidget *q; + SubKeysWidget *const q; }; void SubKeysWidget::Private::tableContextMenuRequested(const QPoint &p) { auto item = ui.subkeysTree->itemAt(p); if (!item) { return; } const auto subkey = item->data(0, Qt::UserRole).value(); QMenu *menu = new QMenu(q); connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); bool hasActions = false; if (!subkey.isSecret()) { hasActions = true; menu->addAction(QIcon::fromTheme(QStringLiteral("view-certificate-import")), i18n("Restore printed backup"), q, [this, subkey] () { auto cmd = new Kleo::Commands::ImportPaperKeyCommand(subkey.parent()); ui.subkeysTree->setEnabled(false); connect(cmd, &Kleo::Commands::ImportPaperKeyCommand::finished, q, [this]() { ui.subkeysTree->setEnabled(true); }); cmd->setParentWidget(q); cmd->start(); }); } if (subkey.isSecret() && Kleo::Commands::KeyToCardCommand::supported()) { const auto cards = SmartCard::ReaderStatus::instance()->getCards(); if (cards.size() && cards[0]->appType() == SmartCard::Card::OpenPGPApplication) { const auto card = cards[0]; if (!subkey.cardSerialNumber() || card->serialNumber() != subkey.cardSerialNumber()) { hasActions = true; menu->addAction(QIcon::fromTheme(QStringLiteral("send-to-symbolic")), i18n("Transfer to smartcard"), q, [this, subkey, card]() { auto cmd = new Kleo::Commands::KeyToCardCommand(subkey, card->serialNumber()); ui.subkeysTree->setEnabled(false); connect(cmd, &Kleo::Commands::KeyToCardCommand::finished, q, [this]() { ui.subkeysTree->setEnabled(true); }); cmd->setParentWidget(q); cmd->start(); }); } } } if (hasActions) { menu->popup(ui.subkeysTree->viewport()->mapToGlobal(p)); } else { delete menu; } } SubKeysWidget::SubKeysWidget(QWidget *parent) : QWidget(parent) , d(new Private(this)) { } SubKeysWidget::~SubKeysWidget() { } void SubKeysWidget::setKey(const GpgME::Key &key) { d->key = key; for (const auto &subkey : key.subkeys()) { auto item = new QTreeWidgetItem(); item->setData(0, Qt::DisplayRole, Formatting::prettyID(subkey.keyID())); item->setData(0, Qt::UserRole, QVariant::fromValue(subkey)); item->setData(1, Qt::DisplayRole, Kleo::Formatting::type(subkey)); item->setData(2, Qt::DisplayRole, Kleo::Formatting::creationDateString(subkey)); item->setData(3, Qt::DisplayRole, Kleo::Formatting::expirationDateString(subkey)); item->setData(4, Qt::DisplayRole, Kleo::Formatting::validityShort(subkey)); switch (subkey.publicKeyAlgorithm()) { case GpgME::Subkey::AlgoECDSA: case GpgME::Subkey::AlgoEDDSA: case GpgME::Subkey::AlgoECDH: item->setData(5, Qt::DisplayRole, QString::fromStdString(subkey.algoName())); break; default: item->setData(5, Qt::DisplayRole, QString::number(subkey.length())); } item->setData(6, Qt::DisplayRole, Kleo::Formatting::usageString(subkey)); item->setData(7, Qt::DisplayRole, subkey.keyID() == key.keyID() ? QStringLiteral("✓") : QString()); d->ui.subkeysTree->addTopLevelItem(item); } const auto subkey = key.subkey(0); if (const char *card = subkey.cardSerialNumber()) { d->ui.stored->setText(i18nc("stored...", "on SmartCard with serial no. %1", QString::fromUtf8(card))); } else { d->ui.stored->setText(i18nc("stored...", "on this computer")); } d->ui.subkeysTree->resizeColumnToContents(0); } GpgME::Key SubKeysWidget::key() const { return d->key; } SubKeysDialog::SubKeysDialog(QWidget *parent) : QDialog(parent) { setWindowTitle(i18nc("@title:window", "Subkeys Details")); auto l = new QVBoxLayout(this); l->addWidget(new SubKeysWidget(this)); auto bbox = new QDialogButtonBox(this); auto btn = bbox->addButton(QDialogButtonBox::Close); connect(btn, &QPushButton::clicked, this, &QDialog::accept); l->addWidget(bbox); readConfig(); } SubKeysDialog::~SubKeysDialog() { writeConfig(); } void SubKeysDialog::readConfig() { KConfigGroup dialog(KSharedConfig::openConfig(), "SubKeysDialog"); const QSize size = dialog.readEntry("Size", QSize(820, 280)); if (size.isValid()) { resize(size); } } void SubKeysDialog::writeConfig() { KConfigGroup dialog(KSharedConfig::openConfig(), "SubKeysDialog"); dialog.writeEntry("Size", size()); dialog.sync(); } void SubKeysDialog::setKey(const GpgME::Key &key) { auto w = findChild(); Q_ASSERT(w); w->setKey(key); } GpgME::Key SubKeysDialog::key() const { auto w = findChild(); Q_ASSERT(w); return w->key(); } diff --git a/src/dialogs/trustchainwidget.cpp b/src/dialogs/trustchainwidget.cpp index 287c0cc23..d553646a4 100644 --- a/src/dialogs/trustchainwidget.cpp +++ b/src/dialogs/trustchainwidget.cpp @@ -1,126 +1,126 @@ /* Copyright (c) 2016 Klarälvdalens Datakonsult AB Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "trustchainwidget.h" #include "ui_trustchainwidget.h" #include "kleopatra_debug.h" #include #include #include #include #include #include #include class TrustChainWidget::Private { public: Private(TrustChainWidget *qq) : q(qq) {} GpgME::Key key; Ui::TrustChainWidget ui; private: - TrustChainWidget *q; + TrustChainWidget *const q; }; TrustChainWidget::TrustChainWidget(QWidget *parent) : QWidget(parent) , d(new Private(this)) { d->ui.setupUi(this); } TrustChainWidget::~TrustChainWidget() { } void TrustChainWidget::setKey(const GpgME::Key &key) { if (key.protocol() != GpgME::CMS) { qCDebug(KLEOPATRA_LOG) << "Trust chain is only supported for CMS keys"; return; } d->key = key; d->ui.treeWidget->clear(); const auto chain = Kleo::KeyCache::instance()->findIssuers(key, Kleo::KeyCache::RecursiveSearch | Kleo::KeyCache::IncludeSubject); if (chain.empty()) { return; } QTreeWidgetItem *last = nullptr; if (!chain.back().isRoot()) { last = new QTreeWidgetItem(d->ui.treeWidget); last->setText(0, i18n("Issuer Certificate Not Found (%1)", Kleo::DN(chain.back().issuerName()).prettyDN())); const QBrush &fg = d->ui.treeWidget->palette().brush(QPalette::Disabled, QPalette::WindowText); last->setForeground(0, fg); } for (auto it = chain.rbegin(), end = chain.rend(); it != end; ++it) { last = last ? new QTreeWidgetItem(last) : new QTreeWidgetItem(d->ui.treeWidget); last->setText(0, Kleo::DN(it->userID(0).id()).prettyDN()); } d->ui.treeWidget->expandAll(); } GpgME::Key TrustChainWidget::key() const { return d->key; } TrustChainDialog::TrustChainDialog(QWidget *parent) : QDialog(parent) { resize(650, 330); setWindowTitle(i18nc("@title:window", "Trust Chain")); auto l = new QVBoxLayout(this); l->addWidget(new TrustChainWidget(this)); auto bbox = new QDialogButtonBox(this); auto btn = bbox->addButton(QDialogButtonBox::Close); connect(btn, &QPushButton::pressed, this, &QDialog::accept); l->addWidget(bbox); } TrustChainDialog::~TrustChainDialog() { } void TrustChainDialog::setKey(const GpgME::Key &key) { auto w = findChild(); Q_ASSERT(w); w->setKey(key); } GpgME::Key TrustChainDialog::key() const { auto w = findChild(); Q_ASSERT(w); return w->key(); } diff --git a/src/dialogs/weboftrustwidget.cpp b/src/dialogs/weboftrustwidget.cpp index 89343ea3a..0d2942fb3 100644 --- a/src/dialogs/weboftrustwidget.cpp +++ b/src/dialogs/weboftrustwidget.cpp @@ -1,168 +1,168 @@ /* Copyright (c) 2017 Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "weboftrustwidget.h" #include #include #include #include #include #include #include #include #include "kleopatra_debug.h" #include "commands/command.h" #include "utils/remarks.h" #include #include using namespace Kleo; class WebOfTrustWidget::Private { public: Private(WebOfTrustWidget *qq): keyListJob(nullptr), q(qq) { certificationsModel.enableRemarks(Remarks::remarksEnabled()); certificationsTV = new QTreeView; certificationsTV->setModel(&certificationsModel); certificationsTV->setAllColumnsShowFocus(true); certificationsTV->setSelectionMode(QAbstractItemView::ExtendedSelection); auto vLay = new QVBoxLayout(q); vLay->setContentsMargins(0, 0, 0, 0); vLay->addWidget(certificationsTV); connect(certificationsTV, &QAbstractItemView::doubleClicked, q, [this] (const QModelIndex &idx) { certificationDblClicked(idx); }); } void certificationDblClicked(const QModelIndex &idx) { if (!idx.isValid()) { return; } if (!idx.parent().isValid()) { // No parent -> root item. return; } // grab the keyid const auto query = certificationsModel.data(idx.sibling(idx.row(), 0)).toString(); // Show details widget or search auto cmd = Command::commandForQuery(query); cmd->setParentWId(q->winId()); cmd->start(); } void startSignatureListing() { if (keyListJob) { return; } QGpgME::KeyListJob *const job = QGpgME::openpgp()->keyListJob(/*remote*/false, /*includeSigs*/true, /*validate*/true); if (!job) { return; } if (Remarks::remarksEnabled()) { job->addMode(GpgME::SignatureNotations); } /* Old style connect here again as QGPGME newstyle connects with * default arguments don't work on windows. */ connect(job, &QGpgME::KeyListJob::result, q, &WebOfTrustWidget::signatureListingDone); connect(job, &QGpgME::KeyListJob::nextKey, q, &WebOfTrustWidget::signatureListingNextKey); job->start(QStringList(QString::fromLatin1(key.primaryFingerprint()))); keyListJob = job; } GpgME::Key key; UserIDListModel certificationsModel; QGpgME::KeyListJob *keyListJob; QTreeView *certificationsTV; private: - WebOfTrustWidget *q; + WebOfTrustWidget *const q; }; WebOfTrustWidget::WebOfTrustWidget(QWidget *parent) : QWidget(parent), d(new Private(this)) { } GpgME::Key WebOfTrustWidget::key() const { return d->key; } void WebOfTrustWidget::setKey(const GpgME::Key &key) { if (key.protocol() != GpgME::OpenPGP) { qCDebug(KLEOPATRA_LOG) << "Trust chain is only supported for CMS keys"; return; } d->key = key; d->certificationsModel.setKey(key); d->certificationsTV->expandAll(); d->certificationsTV->header()->resizeSections(QHeaderView::ResizeToContents); d->startSignatureListing(); } WebOfTrustWidget::~WebOfTrustWidget() { } void WebOfTrustWidget::signatureListingNextKey(const GpgME::Key &key) { GpgME::Key merged = key; merged.mergeWith(d->key); setKey(merged); } void WebOfTrustWidget::signatureListingDone(const GpgME::KeyListResult &result) { if (result.error()) { KMessageBox::information(this, xi18nc("@info", "An error occurred while loading the certifications: " "%1", QString::fromLocal8Bit(result.error().asString())), i18nc("@title", "Certifications Loading Failed")); } d->keyListJob = nullptr; } diff --git a/src/view/padwidget.cpp b/src/view/padwidget.cpp index c721295c8..89c5e12f6 100644 --- a/src/view/padwidget.cpp +++ b/src/view/padwidget.cpp @@ -1,529 +1,529 @@ /* -*- mode: c++; c-basic-offset:4 -*- padwidget.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2018 Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "padwidget.h" #include "kleopatra_debug.h" #include #include #include #include "crypto/gui/signencryptwidget.h" #include "crypto/gui/resultitemwidget.h" #include "crypto/signencrypttask.h" #include "crypto/decryptverifytask.h" #include "utils/gnupg-helper.h" #include "utils/input.h" #include "utils/output.h" #include "commands/importcertificatefromdatacommand.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; static GpgME::Protocol getProtocol(const std::shared_ptr &result) { const auto dvResult = dynamic_cast(result.get()); if (dvResult) { for (const auto &key: KeyCache::instance()->findRecipients(dvResult->decryptionResult())) { return key.protocol(); } for (const auto &key: KeyCache::instance()->findSigners(dvResult->verificationResult())) { return key.protocol(); } } return GpgME::UnknownProtocol; } class PadWidget::Private { public: Private(PadWidget *qq): q(qq), mEdit(new QTextEdit), mCryptBtn(new QPushButton(QIcon::fromTheme(QStringLiteral("document-edit-sign-encrypt")), i18n("Sign / Encrypt Notepad"))), mDecryptBtn(new QPushButton(QIcon::fromTheme(QStringLiteral("document-edit-decrypt-verify")), i18n("Decrypt / Verify Notepad"))), mRevertBtn(new QPushButton(QIcon::fromTheme(QStringLiteral("edit-undo")), i18n("Revert"))), mAdditionalInfoLabel(new QLabel), mSigEncWidget(new SignEncryptWidget(nullptr, true)), mProgressBar(new QProgressBar), mProgressLabel(new QLabel), mLastResultWidget(nullptr), mPGPRB(nullptr), mCMSRB(nullptr), mImportProto(GpgME::UnknownProtocol) { auto vLay = new QVBoxLayout(q); auto btnLay = new QHBoxLayout; vLay->addLayout(btnLay); btnLay->addWidget(mCryptBtn); btnLay->addWidget(mDecryptBtn); btnLay->addWidget(mRevertBtn); mRevertBtn->setVisible(false); btnLay->addWidget(mAdditionalInfoLabel); btnLay->addStretch(-1); mProgressBar->setRange(0, 0); mProgressBar->setVisible(false); mProgressLabel->setVisible(false); auto progLay = new QHBoxLayout; progLay->addWidget(mProgressLabel); progLay->addWidget(mProgressBar); mStatusLay = new QVBoxLayout; mStatusLay->addLayout(progLay); vLay->addLayout(mStatusLay, 0); auto tabWidget = new QTabWidget; vLay->addWidget(tabWidget, 1); tabWidget->addTab(mEdit, QIcon::fromTheme(QStringLiteral("edittext")), i18n("Notepad")); // The recipients area auto recipientsWidget = new QWidget; auto recipientsVLay = new QVBoxLayout(recipientsWidget); auto protocolSelectionLay = new QHBoxLayout; bool pgpOnly = KeyCache::instance()->pgpOnly(); if (!pgpOnly) { recipientsVLay->addLayout(protocolSelectionLay); } protocolSelectionLay->addWidget(new QLabel(i18n("

Protocol:

"))); protocolSelectionLay->addStretch(-1); // Once S/MIME is supported add radio for S/MIME here. recipientsVLay->addWidget(mSigEncWidget); tabWidget->addTab(recipientsWidget, QIcon::fromTheme(QStringLiteral("contact-new-symbolic")), i18n("Recipients")); mEdit->setPlaceholderText(i18n("Enter a message to encrypt or decrypt...")); auto fixedFont = QFont(QStringLiteral("Monospace")); fixedFont.setStyleHint(QFont::TypeWriter); // This does not work well // QFontDatabase::systemFont(QFontDatabase::FixedFont); mEdit->setFont(fixedFont); mEdit->setAcceptRichText(false); mEdit->setMinimumWidth(QFontMetrics(fixedFont).averageCharWidth() * 70); if (KeyCache::instance()->pgpOnly()) { mSigEncWidget->setProtocol(GpgME::OpenPGP); } else { auto grp = new QButtonGroup(q); auto mPGPRB = new QRadioButton(i18n("OpenPGP")); auto mCMSRB = new QRadioButton(i18n("S/MIME")); grp->addButton(mPGPRB); grp->addButton(mCMSRB); KConfigGroup config(KSharedConfig::openConfig(), "Notepad"); if (config.readEntry("wasCMS", false)) { mCMSRB->setChecked(true); mSigEncWidget->setProtocol(GpgME::CMS); } else { mPGPRB->setChecked(true); mSigEncWidget->setProtocol(GpgME::OpenPGP); } protocolSelectionLay->addWidget(mPGPRB); protocolSelectionLay->addWidget(mCMSRB); connect(mPGPRB, &QRadioButton::toggled, q, [this] (bool value) { if (value) { mSigEncWidget->setProtocol(GpgME::OpenPGP); } }); connect(mCMSRB, &QRadioButton::toggled, q, [this] (bool value) { if (value) { mSigEncWidget->setProtocol(GpgME::CMS); } }); } updateCommitButton(); connect(mEdit, &QTextEdit::textChanged, q, [this] () { updateCommitButton(); }); connect(mCryptBtn, &QPushButton::clicked, q, [this] () { if (mImportProto != GpgME::UnknownProtocol) { doImport(); } else { doEncryptSign(); } }); connect(mSigEncWidget, &SignEncryptWidget::operationChanged, q, [this] (const QString &) { updateCommitButton(); }); connect(mDecryptBtn, &QPushButton::clicked, q, [this] () { doDecryptVerify(); }); connect(mRevertBtn, &QPushButton::clicked, q, [this] () { revert(); }); } void revert() { mEdit->setPlainText(QString::fromUtf8(mInputData)); mRevertBtn->setVisible(false); } void updateRecipientsFromResult(const Kleo::Crypto::DecryptVerifyResult &result) { const auto decResult = result.decryptionResult(); for (const auto &recipient: decResult.recipients()) { if (!recipient.keyID()) { continue; } GpgME::Key key; if (strlen(recipient.keyID()) < 16) { key = KeyCache::instance()->findByShortKeyID(recipient.keyID()); } else { key = KeyCache::instance()->findByKeyIDOrFingerprint(recipient.keyID()); } if (key.isNull()) { std::vector subids; subids.push_back(std::string(recipient.keyID())); for (const auto &subkey: KeyCache::instance()->findSubkeysByKeyID(subids)) { key = subkey.parent(); break; } } if (key.isNull()) { qCDebug(KLEOPATRA_LOG) << "Unknown key" << recipient.keyID(); mSigEncWidget->addUnknownRecipient(recipient.keyID()); continue; } bool keyFound = false; for (const auto &existingKey: mSigEncWidget->recipients()) { if (existingKey.primaryFingerprint() && key.primaryFingerprint() && !strcmp (existingKey.primaryFingerprint(), key.primaryFingerprint())) { keyFound = true; break; } } if (!keyFound) { mSigEncWidget->addRecipient(key); } } } void cryptDone(const std::shared_ptr &result) { updateCommitButton(); mDecryptBtn->setEnabled(true); mProgressBar->setVisible(false); mProgressLabel->setVisible(false); mLastResultWidget = new ResultItemWidget(result); mLastResultWidget->showCloseButton(true); mStatusLay->addWidget(mLastResultWidget); connect(mLastResultWidget, &ResultItemWidget::closeButtonClicked, q, [this] () { removeLastResultItem(); }); // Check result protocol if (mPGPRB) { auto proto = getProtocol(result); if (proto == GpgME::UnknownProtocol) { proto = mPGPRB->isChecked() ? GpgME::OpenPGP : GpgME::CMS; } else if (proto == GpgME::OpenPGP) { mPGPRB->setChecked(true); } else if (proto == GpgME::CMS) { mCMSRB->setChecked(true); } KConfigGroup config(KSharedConfig::openConfig(), "Notepad"); config.writeEntry("wasCMS", proto == GpgME::CMS); } if (result->errorCode()) { if (!result->errorString().isEmpty()) { KMessageBox::error(q, result->errorString(), i18nc("@title", "Error in crypto action")); } return; } mEdit->setPlainText(QString::fromUtf8(mOutputData)); mOutputData.clear(); mRevertBtn->setVisible(true); const auto decryptVerifyResult = dynamic_cast(result.get()); if (decryptVerifyResult) { updateRecipientsFromResult(*decryptVerifyResult); } } void doDecryptVerify() { doCryptoCommon(); mSigEncWidget->clearAddedRecipients(); mProgressLabel->setText(i18n("Decrypt / Verify") + QStringLiteral("...")); auto input = Input::createFromByteArray(&mInputData, i18n("Notepad")); auto output = Output::createFromByteArray(&mOutputData, i18n("Notepad")); AbstractDecryptVerifyTask *task; auto classification = input->classification(); if (classification & Class::OpaqueSignature || classification & Class::ClearsignedMessage) { auto verifyTask = new VerifyOpaqueTask(); verifyTask->setInput(input); verifyTask->setOutput(output); task = verifyTask; } else { auto decTask = new DecryptVerifyTask(); decTask->setInput(input); decTask->setOutput(output); task = decTask; } try { task->autodetectProtocolFromInput(); } catch (const Kleo::Exception &e) { KMessageBox::error(q, e.message(), i18nc("@title", "Error in crypto action")); mCryptBtn->setEnabled(true); mDecryptBtn->setEnabled(true); mProgressBar->setVisible(false); mProgressLabel->setVisible(false); return; } connect (task, &Task::result, q, [this, task] (const std::shared_ptr &result) { qCDebug(KLEOPATRA_LOG) << "Decrypt / Verify done. Err:" << result->errorCode(); task->deleteLater(); cryptDone(result); }); task->start(); } void removeLastResultItem() { if (mLastResultWidget) { mStatusLay->removeWidget(mLastResultWidget); delete mLastResultWidget; mLastResultWidget = nullptr; } } void doCryptoCommon() { mCryptBtn->setEnabled(false); mDecryptBtn->setEnabled(false); mProgressBar->setVisible(true); mProgressLabel->setVisible(true); mInputData = mEdit->toPlainText().toUtf8(); removeLastResultItem(); } void doEncryptSign() { doCryptoCommon(); mProgressLabel->setText(mSigEncWidget->currentOp() + QStringLiteral("...")); auto input = Input::createFromByteArray(&mInputData, i18n("Notepad")); auto output = Output::createFromByteArray(&mOutputData, i18n("Notepad")); auto task = new SignEncryptTask(); task->setInput(input); task->setOutput(output); const auto sigKey = mSigEncWidget->signKey(); bool encrypt = mSigEncWidget->encryptSymmetric() || !mSigEncWidget->recipients().isEmpty(); bool sign = !sigKey.isNull(); if (sign) { task->setSign(true); std::vector signVector; signVector.push_back(sigKey); task->setSigners(signVector); } else { task->setSign(false); } task->setEncrypt(encrypt); task->setRecipients(mSigEncWidget->recipients().toStdVector()); task->setEncryptSymmetric(mSigEncWidget->encryptSymmetric()); task->setAsciiArmor(true); if (sign && !encrypt && sigKey.protocol() == GpgME::OpenPGP) { task->setClearsign(true); } connect (task, &Task::result, q, [this, task] (const std::shared_ptr &result) { qCDebug(KLEOPATRA_LOG) << "Encrypt / Sign done. Err:" << result->errorCode(); task->deleteLater(); cryptDone(result); }); task->start(); } void doImport() { doCryptoCommon(); mProgressLabel->setText(i18n("Importing...")); auto cmd = new Kleo::ImportCertificateFromDataCommand(mInputData, mImportProto); connect(cmd, &Kleo::ImportCertificatesCommand::finished, q, [this] () { mCryptBtn->setEnabled(true); mDecryptBtn->setEnabled(true); mProgressBar->setVisible(false); mProgressLabel->setVisible(false); updateCommitButton(); mRevertBtn->setVisible(true); mEdit->setPlainText(QString()); }); cmd->start(); } void checkImportProtocol() { QGpgME::QByteArrayDataProvider dp(mEdit->toPlainText().toUtf8()); GpgME::Data data(&dp); auto type = data.type(); if (type == GpgME::Data::PGPKey) { mImportProto = GpgME::OpenPGP; } else if (type == GpgME::Data::X509Cert || type == GpgME::Data::PKCS12) { mImportProto = GpgME::CMS; } else { mImportProto = GpgME::UnknownProtocol; } } void updateCommitButton() { mAdditionalInfoLabel->setVisible(false); checkImportProtocol(); if (mImportProto != GpgME::UnknownProtocol) { mCryptBtn->setText(i18nc("1 is an operation to apply to the notepad. " "Like Sign/Encrypt or just Encrypt.", "%1 Notepad", i18n("Import"))); mCryptBtn->setDisabled(false); return; } if (!mSigEncWidget->currentOp().isEmpty()) { mCryptBtn->setDisabled(false); mCryptBtn->setText(i18nc("1 is an operation to apply to the notepad. " "Like Sign/Encrypt or just Encrypt.", "%1 Notepad", mSigEncWidget->currentOp())); } else { mCryptBtn->setText(i18n("Sign / Encrypt Notepad")); mCryptBtn->setDisabled(true); } if (Kleo::gpgComplianceP("de-vs")) { bool de_vs = mSigEncWidget->isDeVsAndValid(); mCryptBtn->setIcon(QIcon::fromTheme(de_vs ? QStringLiteral("security-high") : QStringLiteral("security-medium"))); mCryptBtn->setStyleSheet(QStringLiteral("background-color: ") + (de_vs ? KColorScheme(QPalette::Active, KColorScheme::View).background(KColorScheme::PositiveBackground).color().name() : KColorScheme(QPalette::Active, KColorScheme::View).background(KColorScheme::NegativeBackground).color().name())); mAdditionalInfoLabel->setText(de_vs ? i18nc("VS-NfD-conforming is a German standard for restricted documents for which special restrictions about algorithms apply. The string states that all cryptographic operations necessary for the communication are compliant with that.", "VS-NfD-compliant communication possible.") : i18nc("VS-NfD-conforming is a German standard for restricted documents for which special restrictions about algorithms apply. The string states that all cryptographic operations necessary for the communication are compliant with that.", "VS-NfD-compliant communication not possible.")); mAdditionalInfoLabel->setVisible(true); } } private: - PadWidget *q; + PadWidget *const q; QTextEdit *mEdit; QPushButton *mCryptBtn; QPushButton *mDecryptBtn; QPushButton *mRevertBtn; QLabel *mAdditionalInfoLabel; QByteArray mInputData; QByteArray mOutputData; SignEncryptWidget *mSigEncWidget; QProgressBar *mProgressBar; QLabel *mProgressLabel; QVBoxLayout *mStatusLay; ResultItemWidget *mLastResultWidget; QList mAutoAddedKeys; QRadioButton *mPGPRB; QRadioButton *mCMSRB; GpgME::Protocol mImportProto; }; PadWidget::PadWidget(QWidget *parent): QWidget(parent), d(new Private(this)) { } diff --git a/src/view/smartcardwidget.cpp b/src/view/smartcardwidget.cpp index 9f7d5d708..7194bebc1 100644 --- a/src/view/smartcardwidget.cpp +++ b/src/view/smartcardwidget.cpp @@ -1,163 +1,163 @@ /* view/smartcardwidget.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2017 by Bundesamt für Sicherheit in der Informationstechnik Software engineering by Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "smartcardwidget.h" #include "smartcard/readerstatus.h" #include "smartcard/openpgpcard.h" #include "smartcard/netkeycard.h" #include "view/pgpcardwidget.h" #include "view/netkeywidget.h" #include "kleopatra_debug.h" #include #include #include #include #include #include using namespace Kleo; using namespace Kleo::SmartCard; namespace { class PlaceHolderWidget: public QWidget { Q_OBJECT public: explicit PlaceHolderWidget(QWidget *parent = nullptr) : QWidget(parent) { auto lay = new QVBoxLayout; lay->addStretch(-1); const QStringList supported = QStringList() << QStringLiteral("OpenPGP v2.0 - v3.3") << QStringLiteral("Gnuk") << QStringLiteral("NetKey v3"); lay->addWidget(new QLabel(QStringLiteral("\t\t

") + i18n("Please insert a compatible smartcard.") + QStringLiteral("

"), this)); lay->addSpacing(10); lay->addWidget(new QLabel(QStringLiteral("\t\t") + i18n("Kleopatra currently supports the following card types:") + QStringLiteral("
  • ") + supported.join(QLatin1String("
  • ")) + QStringLiteral("
"), this)); lay->addSpacing(10); lay->addWidget(new QLabel(i18n("Refresh the view (F5) to update the smartcard status."), this)); lay->addStretch(-1); auto hLay = new QHBoxLayout(this); hLay->addStretch(-1); hLay->addLayout(lay); hLay->addStretch(-1); lay->addStretch(-1); } }; } // namespace class SmartCardWidget::Private { public: Private(SmartCardWidget *qq) : q(qq) { QPushButton *backBtn = new QPushButton(QIcon::fromTheme(QStringLiteral("arrow-left")), i18n("Back")); QHBoxLayout *backH = new QHBoxLayout; backH->addWidget(backBtn); backH->addWidget(new QLabel(QStringLiteral("

") + i18n("Smartcard Management") + QStringLiteral("

"))); backH->addStretch(-1); QVBoxLayout *vLay = new QVBoxLayout(q); connect(backBtn, &QPushButton::clicked, q, [this] () {Q_EMIT q->backRequested();}); vLay->addLayout(backH); mStack = new QStackedWidget; vLay->addWidget(mStack); mPGPCardWidget = new PGPCardWidget(q); mStack->addWidget(mPGPCardWidget); mNetKeyWidget = new NetKeyWidget(q); mStack->addWidget(mNetKeyWidget); mPlaceHolderWidget = new PlaceHolderWidget(q); mStack->addWidget(mPlaceHolderWidget); mStack->setCurrentWidget(mPlaceHolderWidget); connect (ReaderStatus::instance(), &ReaderStatus::cardChanged, q, [this] (unsigned int /*slot*/) { const auto cards = ReaderStatus::instance()->getCards(); if (!cards.size()) { setCard(std::shared_ptr(new Card())); } else { // No support for multiple reader / cards currently setCard(cards[0]); } }); } void setCard(std::shared_ptr card) { if (card->appType() == Card::OpenPGPApplication) { mPGPCardWidget->setCard(static_cast (card.get())); mStack->setCurrentWidget(mPGPCardWidget); } else if (card->appType() == Card::NksApplication) { mNetKeyWidget->setCard(static_cast (card.get())); mStack->setCurrentWidget(mNetKeyWidget); } else { mStack->setCurrentWidget(mPlaceHolderWidget); } } private: - SmartCardWidget *q; + SmartCardWidget *const q; NetKeyWidget *mNetKeyWidget; PGPCardWidget *mPGPCardWidget; PlaceHolderWidget *mPlaceHolderWidget; QStackedWidget *mStack; }; SmartCardWidget::SmartCardWidget(QWidget *parent): QWidget(parent), d(new Private(this)) { } void SmartCardWidget::reload() { ReaderStatus::mutableInstance()->updateStatus(); } #include "smartcardwidget.moc" diff --git a/src/view/welcomewidget.cpp b/src/view/welcomewidget.cpp index 9925ed3bb..1e507129d 100644 --- a/src/view/welcomewidget.cpp +++ b/src/view/welcomewidget.cpp @@ -1,159 +1,159 @@ /* view/smartcardwidget.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2017 by Bundesamt für Sicherheit in der Informationstechnik Software engineering by Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "welcomewidget.h" #include #include #include #include #include #include #include "commands/importcertificatefromfilecommand.h" #include "commands/newcertificatecommand.h" #include static const QString templ = QStringLiteral( "

%1

" // Welcome "

%2

%3

" // Intro + Explanation "
  • %4
  • %5
" // "

%6

" // More info ""); using namespace Kleo; class WelcomeWidget::Private { public: Private(WelcomeWidget *qq): q(qq) { auto vLay = new QVBoxLayout(q); auto hLay = new QHBoxLayout; const QString welcome = i18nc("%1 is version", "Welcome to Kleopatra %1", QStringLiteral(KLEOPATRA_VERSION_STRING)); const QString introduction = i18n("Kleopatra is a front-end for the crypto software GnuPG."); const QString keyExplanation = i18n("For most actions you need either a public key (certificate) or your own private key."); const QString privateKeyExplanation = i18n("The private key is needed to decrypt or sign."); const QString publicKeyExplanation = i18n("The public key can be used by others to verify your identity or encrypt to you."); const QString wikiUrl = i18nc("More info about public key cryptography, please link to your local version of Wikipedia", "https://en.wikipedia.org/wiki/Public-key_cryptography"); const QString learnMore = i18nc("%1 is link a wiki article", "You can learn more about this on Wikipedia.", wikiUrl); auto label = new QLabel(templ.arg(welcome).arg(introduction).arg(keyExplanation).arg(privateKeyExplanation).arg(publicKeyExplanation).arg(learnMore)); label->setTextInteractionFlags(Qt::TextBrowserInteraction); label->setOpenExternalLinks(true); auto genKeyAction = new QAction(q); genKeyAction->setText(i18n("New Key Pair...")); genKeyAction->setIcon(QIcon::fromTheme(QStringLiteral("view-certificate-add"))); auto importAction = new QAction(q); importAction->setText(i18n("Import...")); importAction->setIcon(QIcon::fromTheme(QStringLiteral("view-certificate-import"))); connect(importAction, &QAction::triggered, q, [this] () { import(); }); connect(genKeyAction, &QAction::triggered, q, [this] () { generate(); }); mGenerateBtn = new QToolButton(); mGenerateBtn->setDefaultAction(genKeyAction); mGenerateBtn->setIconSize(QSize(64, 64)); mGenerateBtn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); mGenerateBtn->setToolTip(i18n("Create a new OpenPGP key pair") + QStringLiteral("
") + i18n("To create an S/MIME certificate request use \"New Key Pair\" from the 'File' Menu instead")); mImportBtn = new QToolButton(); mImportBtn->setDefaultAction(importAction); mImportBtn->setIconSize(QSize(64, 64)); mImportBtn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); mImportBtn->setToolTip(i18n("Import from a file.") + QStringLiteral("
") + i18n("To import from a public keyserver use \"Lookup on Server\" instead.")); auto btnLayout = new QHBoxLayout; btnLayout->addStretch(-1); btnLayout->addWidget(mGenerateBtn); btnLayout->addWidget(mImportBtn); btnLayout->addStretch(-1); vLay->addStretch(-1); vLay->addLayout(hLay); vLay->addLayout(btnLayout); vLay->addStretch(-1); hLay->addStretch(-1); hLay->addWidget(label); hLay->addStretch(-1); } void import() { mImportBtn->setEnabled(false); auto cmd = new Kleo::ImportCertificateFromFileCommand(); cmd->setParentWidget(q); QObject::connect(cmd, &Kleo::ImportCertificateFromFileCommand::finished, q, [this]() { mImportBtn->setEnabled(true); }); cmd->start(); } void generate() { mGenerateBtn->setEnabled(false); auto cmd = new Commands::NewCertificateCommand(); cmd->setProtocol(GpgME::OpenPGP); cmd->setParentWidget(q); QObject::connect(cmd, &Commands::NewCertificateCommand::finished, q, [this]() { mGenerateBtn->setEnabled(true); }); cmd->start(); } - WelcomeWidget *q; + WelcomeWidget *const q; QToolButton *mGenerateBtn; QToolButton *mImportBtn; }; WelcomeWidget::WelcomeWidget (QWidget *parent): QWidget(parent), d(new Private(this)) { }