diff options
-rw-r--r-- | src/core/function/gpg/GpgCommandExecutor.cpp | 6 | ||||
-rw-r--r-- | src/core/function/gpg/GpgCommandExecutor.h | 6 | ||||
-rw-r--r-- | src/core/function/gpg/GpgKeyOpera.cpp | 22 | ||||
-rw-r--r-- | src/core/function/gpg/GpgKeyOpera.h | 4 | ||||
-rw-r--r-- | src/ui/dialog/RevocationOptionsDialog.cpp | 73 | ||||
-rw-r--r-- | src/ui/dialog/RevocationOptionsDialog.h | 57 | ||||
-rw-r--r-- | src/ui/dialog/keypair_details/KeyPairOperaTab.cpp | 41 | ||||
-rw-r--r-- | ui/RevocationOptionsDialog.ui | 107 |
8 files changed, 292 insertions, 24 deletions
diff --git a/src/core/function/gpg/GpgCommandExecutor.cpp b/src/core/function/gpg/GpgCommandExecutor.cpp index 74df1d5a..555c710d 100644 --- a/src/core/function/gpg/GpgCommandExecutor.cpp +++ b/src/core/function/gpg/GpgCommandExecutor.cpp @@ -66,7 +66,7 @@ auto BuildTaskFromExecCtx(const GpgCommandExecutor::ExecuteContext &context) FLOG_D("process runner called, data object size: %lu", data_object->GetObjectSize()); - if (!data_object->Check<QString, QStringList, GpgCommandExecutorInteractor, + if (!data_object->Check<QString, QStringList, GpgCommandExecutorInterator, GpgCommandExecutorCallback>()) { FLOG_W("data object checking failed"); return -1; @@ -76,7 +76,7 @@ auto BuildTaskFromExecCtx(const GpgCommandExecutor::ExecuteContext &context) auto cmd = ExtractParams<QString>(data_object, 0); auto arguments = ExtractParams<QStringList>(data_object, 1); auto interact_func = - ExtractParams<GpgCommandExecutorInteractor>(data_object, 2); + ExtractParams<GpgCommandExecutorInterator>(data_object, 2); auto callback = ExtractParams<GpgCommandExecutorCallback>(data_object, 3); const QString joined_argument = arguments.join(" "); @@ -225,7 +225,7 @@ void GpgCommandExecutor::ExecuteConcurrentlySync(ExecuteContexts contexts) { GpgCommandExecutor::ExecuteContext::ExecuteContext( QString cmd, QStringList arguments, GpgCommandExecutorCallback callback, - Module::TaskRunnerPtr task_runner, GpgCommandExecutorInteractor int_func) + Module::TaskRunnerPtr task_runner, GpgCommandExecutorInterator int_func) : cmd(std::move(cmd)), arguments(std::move(arguments)), cb_func(std::move(callback)), diff --git a/src/core/function/gpg/GpgCommandExecutor.h b/src/core/function/gpg/GpgCommandExecutor.h index e3b03c10..cb35e686 100644 --- a/src/core/function/gpg/GpgCommandExecutor.h +++ b/src/core/function/gpg/GpgCommandExecutor.h @@ -33,7 +33,7 @@ namespace GpgFrontend { using GpgCommandExecutorCallback = std::function<void(int, QString, QString)>; -using GpgCommandExecutorInteractor = std::function<void(QProcess *)>; +using GpgCommandExecutorInterator = std::function<void(QProcess *)>; /** * @brief Extra commands related to GPG @@ -45,7 +45,7 @@ class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor { QString cmd; QStringList arguments; GpgCommandExecutorCallback cb_func; - GpgCommandExecutorInteractor int_func; + GpgCommandExecutorInterator int_func; Module::TaskRunnerPtr task_runner = nullptr; ExecuteContext( @@ -53,7 +53,7 @@ class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor { GpgCommandExecutorCallback callback = [](int, const QString &, const QString &) {}, Module::TaskRunnerPtr task_runner = nullptr, - GpgCommandExecutorInteractor int_func = [](QProcess *) {}); + GpgCommandExecutorInterator int_func = [](QProcess *) {}); }; using ExecuteContexts = QList<ExecuteContext>; diff --git a/src/core/function/gpg/GpgKeyOpera.cpp b/src/core/function/gpg/GpgKeyOpera.cpp index 332ed1b3..0d84017f 100644 --- a/src/core/function/gpg/GpgKeyOpera.cpp +++ b/src/core/function/gpg/GpgKeyOpera.cpp @@ -103,7 +103,17 @@ auto GpgKeyOpera::SetExpire(const GpgKey& key, const SubkeyId& subkey_fpr, * @return the process doing this job */ void GpgKeyOpera::GenerateRevokeCert(const GpgKey& key, - const QString& output_path) { + const QString& output_path, + int revocation_reason_code, + const QString& revocation_reason_text) { + LOG_D() << "revoke code:" << revocation_reason_code + << "text:" << revocation_reason_text; + + // dealing with reason text + auto reason_text_lines = + GpgFrontend::SecureCreateSharedObject<QList<QString>>( + revocation_reason_text.split('\n', Qt::SkipEmptyParts).toVector()); + const auto app_path = Module::RetrieveRTValueTypedOrDefault<>( "core", "gpgme.ctx.app_path", QString{}); // get all components @@ -121,17 +131,23 @@ void GpgKeyOpera::GenerateRevokeCert(const GpgKey& key, } }, nullptr, - [](QProcess* proc) -> void { + [revocation_reason_code, reason_text_lines](QProcess* proc) -> void { // Code From Gpg4Win while (proc->canReadLine()) { const QString line = QString::fromUtf8(proc->readLine()).trimmed(); + LOG_D() << "gpg revoke proc line:" << line; + if (line == QLatin1String("[GNUPG:] GET_BOOL gen_revoke.okay")) { proc->write("y\n"); } else if (line == QLatin1String("[GNUPG:] GET_LINE " "ask_revocation_reason.code")) { - proc->write("0\n"); + proc->write( + QString("%1%\n").arg(revocation_reason_code).toLatin1()); } else if (line == QLatin1String("[GNUPG:] GET_LINE " "ask_revocation_reason.text")) { + if (!reason_text_lines->isEmpty()) { + proc->write(reason_text_lines->takeFirst().toUtf8()); + } proc->write("\n"); } else if (line == QLatin1String( diff --git a/src/core/function/gpg/GpgKeyOpera.h b/src/core/function/gpg/GpgKeyOpera.h index 0504ad93..7b8a01a1 100644 --- a/src/core/function/gpg/GpgKeyOpera.h +++ b/src/core/function/gpg/GpgKeyOpera.h @@ -86,7 +86,9 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyOpera * @param key * @param output_file_name */ - void GenerateRevokeCert(const GpgKey& key, const QString& output_path); + void GenerateRevokeCert(const GpgKey& key, const QString& output_path, + int revocation_reason_code, + const QString& revocation_reason_text); /** * @brief diff --git a/src/ui/dialog/RevocationOptionsDialog.cpp b/src/ui/dialog/RevocationOptionsDialog.cpp new file mode 100644 index 00000000..e2bbba00 --- /dev/null +++ b/src/ui/dialog/RevocationOptionsDialog.cpp @@ -0,0 +1,73 @@ +/** + * Copyright (C) 2021-2024 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "RevocationOptionsDialog.h" + +#include "core/utils/MemoryUtils.h" +#include "ui_RevocationOptionsDialog.h" + +GpgFrontend::UI::RevocationOptionsDialog::RevocationOptionsDialog( + QWidget *parent) + : GeneralDialog("RevocationOptionsDialog", parent), + ui_(GpgFrontend::SecureCreateSharedObject<Ui_RevocationOptionsDialog>()) { + ui_->setupUi(this); + + QStringList codes; + + codes << tr("0 -> No Reason.") << tr("1 -> This key is no more safe.") + << tr("2 -> Key is outdated.") << tr("3 -> Key is no longer used"); + + ui_->rRcodeComboBox->addItems(codes); + + ui_->revocationReasonCodeLabel->setText(tr("Revocation Reason (Code)")); + ui_->revocationReasonTextLabel->setText(tr("Revocation Reason (Text)")); + this->setWindowTitle(tr("Revocation Options")); + + connect(ui_->buttonBox, &QDialogButtonBox::accepted, this, + &RevocationOptionsDialog::slot_button_box_accepted); + connect(ui_->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(ui_->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + setAttribute(Qt::WA_DeleteOnClose); +} + +auto GpgFrontend::UI::RevocationOptionsDialog::Code() const -> int { + return code_; +} + +auto GpgFrontend::UI::RevocationOptionsDialog::Text() const -> QString { + return text_; +} + +void GpgFrontend::UI::RevocationOptionsDialog::slot_button_box_accepted() { + code_ = ui_->rRcodeComboBox->currentIndex(); + text_ = ui_->rRPlainTextEdit->toPlainText() + .trimmed() + .split('\n', Qt::SkipEmptyParts) + .join("\n"); + emit SignalRevokeOptionAccepted(code_, text_); +} diff --git a/src/ui/dialog/RevocationOptionsDialog.h b/src/ui/dialog/RevocationOptionsDialog.h new file mode 100644 index 00000000..0f404ca2 --- /dev/null +++ b/src/ui/dialog/RevocationOptionsDialog.h @@ -0,0 +1,57 @@ + +/** + * Copyright (C) 2021-2024 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "ui/dialog/GeneralDialog.h" + +class Ui_RevocationOptionsDialog; + +namespace GpgFrontend::UI { +class RevocationOptionsDialog : public GeneralDialog { + Q_OBJECT + public: + explicit RevocationOptionsDialog(QWidget *parent); + + [[nodiscard]] auto Code() const -> int; + + [[nodiscard]] auto Text() const -> QString; + + signals: + void SignalRevokeOptionAccepted(int code, QString text); + + private: + std::shared_ptr<Ui_RevocationOptionsDialog> ui_; ///< + int code_; + QString text_; + + void slot_button_box_accepted(); +}; + +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp index f2efb037..1f637b0e 100644 --- a/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp @@ -40,6 +40,7 @@ #include "core/utils/IOUtils.h" #include "ui/UISignalStation.h" #include "ui/UserInterfaceUtils.h" +#include "ui/dialog/RevocationOptionsDialog.h" #include "ui/dialog/import_export/KeyUploadDialog.h" #include "ui/function/SetOwnerTrustLevel.h" @@ -350,27 +351,39 @@ void KeyPairOperaTab::slot_update_key_from_server() { } void KeyPairOperaTab::slot_gen_revoke_cert() { - auto literal = QString("%1 (*.rev)").arg(tr("Revocation Certificates")); - QString m_output_file_name; + auto* revocation_options_dialog = new RevocationOptionsDialog(this); + + connect(revocation_options_dialog, + &RevocationOptionsDialog::SignalRevokeOptionAccepted, this, + [this](int code, const QString& text) { + auto literal = + QString("%1 (*.rev)").arg(tr("Revocation Certificates")); + QString m_output_file_name; #if defined(_WIN32) || defined(WIN32) - auto file_string = m_key_.GetName() + "[" + m_key_.GetEmail() + "](" + - m_key_.GetId() + ").rev"; + auto file_string = m_key_.GetName() + "[" + m_key_.GetEmail() + + "](" + m_key_.GetId() + ").rev"; #else - auto file_string = m_key_.GetName() + "<" + m_key_.GetEmail() + ">(" + - m_key_.GetId() + ").rev"; + auto file_string = m_key_.GetName() + "<" + m_key_.GetEmail() + + ">(" + m_key_.GetId() + ").rev"; #endif - QFileDialog dialog(this, tr("Generate revocation certificate"), file_string, - literal); - dialog.setDefaultSuffix(".rev"); - dialog.setAcceptMode(QFileDialog::AcceptSave); + QFileDialog dialog(this, tr("Generate revocation certificate"), + file_string, literal); + dialog.setDefaultSuffix(".rev"); + dialog.setAcceptMode(QFileDialog::AcceptSave); - if (dialog.exec() != 0) m_output_file_name = dialog.selectedFiles().front(); + if (dialog.exec() != QFileDialog::Reject) { + m_output_file_name = dialog.selectedFiles().front(); + } - if (!m_output_file_name.isEmpty()) { - GpgKeyOpera::GetInstance().GenerateRevokeCert(m_key_, m_output_file_name); - } + if (!m_output_file_name.isEmpty()) { + GpgKeyOpera::GetInstance().GenerateRevokeCert( + m_key_, m_output_file_name, code, text); + } + }); + + revocation_options_dialog->show(); } void KeyPairOperaTab::slot_modify_password() { diff --git a/ui/RevocationOptionsDialog.ui b/ui/RevocationOptionsDialog.ui new file mode 100644 index 00000000..050fa889 --- /dev/null +++ b/ui/RevocationOptionsDialog.ui @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>RevocationOptionsDialog</class> + <widget class="QDialog" name="RevocationOptionsDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>525</width> + <height>430</height> + </rect> + </property> + <property name="windowTitle"> + <string>Revocation Options</string> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="modal"> + <bool>false</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="revocationReasonCodeLabel"> + <property name="text"> + <string>Revocation Reason (Code)</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="rRcodeComboBox"/> + </item> + <item> + <widget class="QLabel" name="revocationReasonTextLabel"> + <property name="text"> + <string>Revocation Reason (Text)</string> + </property> + </widget> + </item> + <item> + <widget class="QPlainTextEdit" name="rRPlainTextEdit"/> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>RevocationOptionsDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>RevocationOptionsDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> |