diff --git a/src/dialogs/nameandemailwidget.cpp b/src/dialogs/nameandemailwidget.cpp index adfd58f58..d34e22b29 100644 --- a/src/dialogs/nameandemailwidget.cpp +++ b/src/dialogs/nameandemailwidget.cpp @@ -1,224 +1,252 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/nameandemailwidget.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2022 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "nameandemailwidget.h" #include "view/errorlabel.h" #include "view/formtextinput.h" #include #include #include #include #include #include "kleopatra_debug.h" using namespace Kleo; namespace { QString buildUserId(const QString &name, const QString &email) { if (name.isEmpty()) { return email; } else if (email.isEmpty()) { return name; } else { return QStringLiteral("%1 <%2>").arg(name, email); } } } class NameAndEmailWidget::Private { NameAndEmailWidget *const q; public: struct { std::unique_ptr> nameInput; std::unique_ptr> emailInput; } ui; explicit Private(NameAndEmailWidget *qq) : q{qq} { auto mainLayout = new QVBoxLayout{q}; { ui.nameInput = FormTextInput::create(q); ui.nameInput->setLabelText(i18nc("@label", "Name")); ui.nameInput->setValueRequiredErrorMessage(i18n("Enter a name.")); setNamePattern({}); mainLayout->addWidget(ui.nameInput->label()); mainLayout->addWidget(ui.nameInput->hintLabel()); mainLayout->addWidget(ui.nameInput->errorLabel()); mainLayout->addWidget(ui.nameInput->widget()); } connect(ui.nameInput->widget(), &QLineEdit::textChanged, q, [this]() { Q_EMIT q->userIDChanged(); }); { ui.emailInput = FormTextInput::create(q); ui.emailInput->setLabelText(i18nc("@label", "Email address")); ui.emailInput->setValueRequiredErrorMessage(i18n("Enter an email address.")); setEmailPattern({}); mainLayout->addWidget(ui.emailInput->label()); mainLayout->addWidget(ui.emailInput->hintLabel()); mainLayout->addWidget(ui.emailInput->errorLabel()); mainLayout->addWidget(ui.emailInput->widget()); } connect(ui.emailInput->widget(), &QLineEdit::textChanged, q, [this]() { Q_EMIT q->userIDChanged(); }); } void setNamePattern(const QString ®exp) { if (regexp.isEmpty()) { ui.nameInput->setValidator(Validation::simpleName(Validation::Optional)); ui.nameInput->setInvalidEntryErrorMessage( i18n("The name must not include <, >, and @."), i18nc("text for screen readers", "The name must not include less-than sign, greater-than sign, and at sign.")); } else { ui.nameInput->setValidator(Validation::simpleName(regexp, Validation::Optional)); ui.nameInput->setInvalidEntryErrorMessage( i18n("The name must be in the format required by your organization and " "it must not include <, >, and @."), i18nc("text for screen readers", "The name must be in the format required by your organization and " "it must not include less-than sign, greater-than sign, and at sign.")); } } void setEmailPattern(const QString ®exp) { if (regexp.isEmpty()) { ui.emailInput->setValidator(Validation::email(Validation::Optional)); ui.emailInput->setInvalidEntryErrorMessage(i18n( "Enter an email address in the correct format, like name@example.com.")); } else { ui.emailInput->setValidator(Validation::email(regexp, Validation::Optional)); ui.emailInput->setInvalidEntryErrorMessage(i18n( "Enter an email address in the correct format required by your organization.")); } } QString name() const { return ui.nameInput->widget()->text().trimmed(); } QString email() const { return ui.emailInput->widget()->text().trimmed(); } }; NameAndEmailWidget::NameAndEmailWidget(QWidget *parent, Qt::WindowFlags f) : QWidget{parent, f} , d(new Private{this}) { } NameAndEmailWidget::~NameAndEmailWidget() = default; void NameAndEmailWidget::setName(const QString &name) { d->ui.nameInput->widget()->setText(name); } QString NameAndEmailWidget::name() const { return d->name(); } void NameAndEmailWidget::setNameIsRequired(bool required) { d->ui.nameInput->setIsRequired(required); } bool NameAndEmailWidget::nameIsRequired() const { return d->ui.nameInput->isRequired(); } +void NameAndEmailWidget::setNameLabel(const QString &label) +{ + if (label.isEmpty()) { + d->ui.nameInput->setLabelText(i18nc("@label", "Name")); + } else { + d->ui.nameInput->setLabelText(label); + } +} + +QString NameAndEmailWidget::nameLabel() const +{ + return d->ui.nameInput->label()->text(); +} + void NameAndEmailWidget::setNameHint(const QString &hint) { d->ui.nameInput->setHint(hint); } QString NameAndEmailWidget::nameHint() const { return d->ui.nameInput->hintLabel()->text(); } void NameAndEmailWidget::setNamePattern(const QString &pattern) { d->setNamePattern(pattern); } QString NameAndEmailWidget::nameError() const { return d->ui.nameInput->currentError(); } void NameAndEmailWidget::setEmail(const QString &email) { d->ui.emailInput->widget()->setText(email); } QString NameAndEmailWidget::email() const { return d->email(); } void NameAndEmailWidget::setEmailIsRequired(bool required) { d->ui.emailInput->setIsRequired(required); } bool NameAndEmailWidget::emailIsRequired() const { return d->ui.emailInput->isRequired(); } +void NameAndEmailWidget::setEmailLabel(const QString &label) +{ + if (label.isEmpty()) { + d->ui.emailInput->setLabelText(i18nc("@label", "Email address")); + } else { + d->ui.emailInput->setLabelText(label); + } +} + +QString NameAndEmailWidget::emailLabel() const +{ + return d->ui.emailInput->label()->text(); +} + void NameAndEmailWidget::setEmailHint(const QString &hint) { d->ui.emailInput->setHint(hint); } QString NameAndEmailWidget::emailHint() const { return d->ui.emailInput->hintLabel()->text(); } void NameAndEmailWidget::setEmailPattern(const QString &pattern) { d->setEmailPattern(pattern); } QString NameAndEmailWidget::emailError() const { return d->ui.emailInput->currentError(); } QString NameAndEmailWidget::userID() const { return buildUserId(name(), email()); } diff --git a/src/dialogs/nameandemailwidget.h b/src/dialogs/nameandemailwidget.h index 8821037e0..bb3ce7b47 100644 --- a/src/dialogs/nameandemailwidget.h +++ b/src/dialogs/nameandemailwidget.h @@ -1,59 +1,63 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/nameandemailwidget.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2022 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include namespace Kleo { class NameAndEmailWidget : public QWidget { Q_OBJECT public: explicit NameAndEmailWidget(QWidget *parent = nullptr, Qt::WindowFlags f = {}); ~NameAndEmailWidget() override; void setName(const QString &name); QString name() const; void setNameIsRequired(bool required); bool nameIsRequired() const; + void setNameLabel(const QString &label); + QString nameLabel() const; void setNameHint(const QString &hint); QString nameHint() const; void setNamePattern(const QString &pattern); QString nameError() const; void setEmail(const QString &email); QString email() const; void setEmailIsRequired(bool required); bool emailIsRequired() const; + void setEmailLabel(const QString &label); + QString emailLabel() const; void setEmailHint(const QString &hint); QString emailHint() const; void setEmailPattern(const QString &pattern); QString emailError() const; /** * Returns the user ID built from the entered name and/or email address. */ QString userID() const; Q_SIGNALS: void userIDChanged() const; private: class Private; const std::unique_ptr d; }; } // namespace Kleo diff --git a/src/dialogs/newopenpgpcertificatedetailsdialog.cpp b/src/dialogs/newopenpgpcertificatedetailsdialog.cpp index 2eacc21f6..4f3149f34 100644 --- a/src/dialogs/newopenpgpcertificatedetailsdialog.cpp +++ b/src/dialogs/newopenpgpcertificatedetailsdialog.cpp @@ -1,326 +1,328 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/newopenpgpcertificatedetailsdialog.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2022 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "newopenpgpcertificatedetailsdialog.h" #include "nameandemailwidget.h" #include "newcertificatewizard/advancedsettingsdialog_p.h" #include "newcertificatewizard/keyalgo_p.h" #include "utils/keyparameters.h" #include "utils/keyusage.h" #include "utils/scrollarea.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::NewCertificateUi; class NewOpenPGPCertificateDetailsDialog::Private { friend class ::Kleo::NewOpenPGPCertificateDetailsDialog; NewOpenPGPCertificateDetailsDialog *const q; struct UI { QLabel *infoLabel; ScrollArea *scrollArea; NameAndEmailWidget *nameAndEmail; QCheckBox *withPassCheckBox; QPushButton *advancedButton; QDialogButtonBox *buttonBox; UI(QWidget *dialog) { auto mainLayout = new QVBoxLayout{dialog}; infoLabel = new QLabel{dialog}; infoLabel->setWordWrap(true); mainLayout->addWidget(infoLabel); mainLayout->addWidget(new KSeparator{Qt::Horizontal, dialog}); scrollArea = new ScrollArea{dialog}; scrollArea->setFocusPolicy(Qt::NoFocus); scrollArea->setFrameStyle(QFrame::NoFrame); scrollArea->setBackgroundRole(dialog->backgroundRole()); scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); scrollArea->setSizeAdjustPolicy(QScrollArea::AdjustToContents); auto scrollAreaLayout = qobject_cast(scrollArea->widget()->layout()); scrollAreaLayout->setContentsMargins(0, 0, 0, 0); nameAndEmail = new NameAndEmailWidget{dialog}; scrollAreaLayout->addWidget(nameAndEmail); withPassCheckBox = new QCheckBox{i18n("Protect the generated key with a passphrase."), dialog}; withPassCheckBox->setToolTip( i18n("Encrypts the secret key with an unrecoverable passphrase. You will be asked for the passphrase during key generation.")); scrollAreaLayout->addWidget(withPassCheckBox); { auto layout = new QHBoxLayout; advancedButton = new QPushButton{i18n("Advanced Settings..."), dialog}; advancedButton->setAutoDefault(false); layout->addStretch(1); layout->addWidget(advancedButton); scrollAreaLayout->addLayout(layout); } scrollAreaLayout->addStretch(1); mainLayout->addWidget(scrollArea); mainLayout->addWidget(new KSeparator{Qt::Horizontal, dialog}); buttonBox = new QDialogButtonBox{QDialogButtonBox::Ok | QDialogButtonBox::Cancel, dialog}; mainLayout->addWidget(buttonBox); } } ui; public: explicit Private(NewOpenPGPCertificateDetailsDialog *qq) : q{qq} , ui{qq} , advancedSettingsDlg{new AdvancedSettingsDialog{qq}} , technicalParameters{KeyParameters::OpenPGP} { q->setWindowTitle(i18nc("title:window", "Create OpenPGP Certificate")); const KConfigGroup config{KSharedConfig::openConfig(), "CertificateCreationWizard"}; const auto attrOrder = config.readEntry("OpenPGPAttributeOrder", QStringList{}); const auto nameIsRequired = attrOrder.contains(QLatin1String{"NAME!"}, Qt::CaseInsensitive); const auto emailIsRequired = attrOrder.contains(QLatin1String{"EMAIL!"}, Qt::CaseInsensitive); ui.infoLabel->setText(nameIsRequired || emailIsRequired // ? i18n("Enter a name and an email address to use for the certificate.") : i18n("Enter a name and/or an email address to use for the certificate.")); ui.nameAndEmail->setNameIsRequired(nameIsRequired); + ui.nameAndEmail->setNameLabel(config.readEntry("NAME_label")); ui.nameAndEmail->setNameHint(config.readEntry("NAME_hint", config.readEntry("NAME_placeholder"))); ui.nameAndEmail->setNamePattern(config.readEntry("NAME_regex")); ui.nameAndEmail->setEmailIsRequired(emailIsRequired); + ui.nameAndEmail->setEmailLabel(config.readEntry("EMAIL_label")); ui.nameAndEmail->setEmailHint(config.readEntry("EMAIL_hint", config.readEntry("EMAIL_placeholder"))); ui.nameAndEmail->setEmailPattern(config.readEntry("EMAIL_regex")); Settings settings; ui.advancedButton->setVisible(!settings.hideAdvanced()); const auto conf = QGpgME::cryptoConfig(); const auto entry = getCryptoConfigEntry(conf, "gpg-agent", "enforce-passphrase-constraints"); if (entry && entry->boolValue()) { qCDebug(KLEOPATRA_LOG) << "Disabling passphrase check box because of agent config."; ui.withPassCheckBox->setEnabled(false); ui.withPassCheckBox->setChecked(true); } else { ui.withPassCheckBox->setChecked(config.readEntry("WithPassphrase", false)); ui.withPassCheckBox->setEnabled(!config.isEntryImmutable("WithPassphrase")); } advancedSettingsDlg->setProtocol(GpgME::OpenPGP); updateTechnicalParameters(); // set key parameters to default values for OpenPGP connect(advancedSettingsDlg, &QDialog::accepted, q, [this]() { updateTechnicalParameters(); }); connect(ui.advancedButton, &QPushButton::clicked, q, [this]() { advancedSettingsDlg->open(); }); connect(ui.buttonBox, &QDialogButtonBox::accepted, q, [this]() { checkAccept(); }); connect(ui.buttonBox, &QDialogButtonBox::rejected, q, &QDialog::reject); } private: KeyUsage keyUsage() const { KeyUsage usage; if (advancedSettingsDlg->signingAllowed()) { usage.setCanSign(true); } if (advancedSettingsDlg->encryptionAllowed() // && !is_ecdh(advancedSettingsDlg->subkeyType()) && !is_dsa(advancedSettingsDlg->keyType()) && !is_rsa(advancedSettingsDlg->subkeyType())) { usage.setCanEncrypt(true); } if (advancedSettingsDlg->authenticationAllowed()) { usage.setCanAuthenticate(true); } if (advancedSettingsDlg->certificationAllowed()) { usage.setCanCertify(true); } return usage; } KeyUsage subkeyUsage() const { KeyUsage usage; if (advancedSettingsDlg->encryptionAllowed() && (is_dsa(advancedSettingsDlg->keyType()) || is_rsa(advancedSettingsDlg->subkeyType()) || is_ecdh(advancedSettingsDlg->subkeyType()))) { Q_ASSERT(advancedSettingsDlg->subkeyType()); usage.setCanEncrypt(true); } return usage; } void updateTechnicalParameters() { technicalParameters = KeyParameters{KeyParameters::OpenPGP}; const auto keyType = advancedSettingsDlg->keyType(); technicalParameters.setKeyType(keyType); if (is_ecdsa(keyType) || is_eddsa(keyType)) { technicalParameters.setKeyCurve(advancedSettingsDlg->keyCurve()); } else if (const unsigned int strength = advancedSettingsDlg->keyStrength()) { technicalParameters.setKeyLength(strength); } technicalParameters.setKeyUsage(keyUsage()); const auto subkeyType = advancedSettingsDlg->subkeyType(); if (subkeyType) { technicalParameters.setSubkeyType(subkeyType); if (is_ecdh(subkeyType)) { technicalParameters.setSubkeyCurve(advancedSettingsDlg->subkeyCurve()); } else if (const unsigned int strength = advancedSettingsDlg->subkeyStrength()) { technicalParameters.setSubkeyLength(strength); } technicalParameters.setSubkeyUsage(subkeyUsage()); } if (advancedSettingsDlg->expiryDate().isValid()) { technicalParameters.setExpirationDate(advancedSettingsDlg->expiryDate()); } // name and email are set later } void setTechnicalParameters(const KeyParameters ¶meters) { advancedSettingsDlg->setKeyType(parameters.keyType()); advancedSettingsDlg->setKeyStrength(parameters.keyLength()); advancedSettingsDlg->setKeyCurve(parameters.keyCurve()); advancedSettingsDlg->setSubkeyType(parameters.subkeyType()); advancedSettingsDlg->setSubkeyStrength(parameters.subkeyLength()); advancedSettingsDlg->setSubkeyCurve(parameters.subkeyCurve()); advancedSettingsDlg->setSigningAllowed(parameters.keyUsage().canSign() || parameters.subkeyUsage().canSign()); advancedSettingsDlg->setEncryptionAllowed(parameters.keyUsage().canEncrypt() || parameters.subkeyUsage().canEncrypt()); advancedSettingsDlg->setCertificationAllowed(parameters.keyUsage().canCertify() || parameters.subkeyUsage().canCertify()); advancedSettingsDlg->setAuthenticationAllowed(parameters.keyUsage().canAuthenticate() || parameters.subkeyUsage().canAuthenticate()); advancedSettingsDlg->setExpiryDate(parameters.expirationDate()); } void checkAccept() { QStringList errors; if (ui.nameAndEmail->userID().isEmpty() && !ui.nameAndEmail->nameIsRequired() && !ui.nameAndEmail->emailIsRequired()) { errors.push_back(i18n("Enter a name or an email address.")); } const auto nameError = ui.nameAndEmail->nameError(); if (!nameError.isEmpty()) { errors.push_back(nameError); } const auto emailError = ui.nameAndEmail->emailError(); if (!emailError.isEmpty()) { errors.push_back(emailError); } if (errors.size() > 1) { KMessageBox::errorList(q, i18n("There is a problem."), errors); } else if (!errors.empty()) { KMessageBox::error(q, errors.first()); } else { q->accept(); } } private: AdvancedSettingsDialog *const advancedSettingsDlg; KeyParameters technicalParameters; }; NewOpenPGPCertificateDetailsDialog::NewOpenPGPCertificateDetailsDialog(QWidget *parent, Qt::WindowFlags f) : QDialog{parent, f} , d(new Private{this}) { } NewOpenPGPCertificateDetailsDialog::~NewOpenPGPCertificateDetailsDialog() = default; void NewOpenPGPCertificateDetailsDialog::setName(const QString &name) { d->ui.nameAndEmail->setName(name); } QString NewOpenPGPCertificateDetailsDialog::name() const { return d->ui.nameAndEmail->name(); } void NewOpenPGPCertificateDetailsDialog::setEmail(const QString &email) { d->ui.nameAndEmail->setEmail(email); } QString NewOpenPGPCertificateDetailsDialog::email() const { return d->ui.nameAndEmail->email(); } void Kleo::NewOpenPGPCertificateDetailsDialog::setKeyParameters(const Kleo::KeyParameters ¶meters) { setName(parameters.name()); const auto emails = parameters.emails(); if (!emails.empty()) { setEmail(emails.front()); } d->setTechnicalParameters(parameters); } KeyParameters NewOpenPGPCertificateDetailsDialog::keyParameters() const { // set name and email on a copy of the technical parameters auto parameters = d->technicalParameters; if (!name().isEmpty()) { parameters.setName(name()); } if (!email().isEmpty()) { parameters.setEmail(email()); } return parameters; } void Kleo::NewOpenPGPCertificateDetailsDialog::setProtectKeyWithPassword(bool protectKey) { d->ui.withPassCheckBox->setChecked(protectKey); } bool NewOpenPGPCertificateDetailsDialog::protectKeyWithPassword() const { return d->ui.withPassCheckBox->isChecked(); }