diff options
author | saturneric <[email protected]> | 2024-07-28 15:08:48 +0000 |
---|---|---|
committer | saturneric <[email protected]> | 2024-07-28 15:08:56 +0000 |
commit | 4e0db9ef4bf329d5698b31bd93601004305f71dc (patch) | |
tree | 94a22cfab394456ff89392831d3e146a76413118 | |
parent | fix: remove invalid parameters from the SDK (diff) | |
download | GpgFrontend-4e0db9ef4bf329d5698b31bd93601004305f71dc.tar.gz GpgFrontend-4e0db9ef4bf329d5698b31bd93601004305f71dc.zip |
feat: add paper key module support
-rw-r--r-- | src/core/GpgConstants.h | 9 | ||||
-rw-r--r-- | src/ui/dialog/controller/ModuleControllerDialog.cpp | 8 | ||||
-rw-r--r-- | src/ui/dialog/keypair_details/KeyPairOperaTab.cpp | 166 | ||||
-rw-r--r-- | src/ui/dialog/keypair_details/KeyPairOperaTab.h | 12 | ||||
-rw-r--r-- | ui/ModuleControllerDialog.ui | 2 |
5 files changed, 189 insertions, 8 deletions
diff --git a/src/core/GpgConstants.h b/src/core/GpgConstants.h index 1c514703..1165db78 100644 --- a/src/core/GpgConstants.h +++ b/src/core/GpgConstants.h @@ -53,10 +53,13 @@ constexpr const char* PGP_PRIVATE_KEY_BEGIN = "-----BEGIN PGP PRIVATE KEY BLOCK-----"; ///< // MODULE ID -const QString kGnuPGInfoGatheringModuleID = +constexpr const char* kGnuPGInfoGatheringModuleID = "com.bktus.gpgfrontend.module.gnupg_info_gathering"; -const QString kVersionCheckingModuleID = +constexpr const char* kVersionCheckingModuleID = "com.bktus.gpgfrontend.module.version_checking"; -const QString kPinentryModuleID = "com.bktus.gpgfrontend.module.pinentry"; +constexpr const char* kPinentryModuleID = + "com.bktus.gpgfrontend.module.pinentry"; +constexpr const char* kPaperKeyModuleID = + "com.bktus.gpgfrontend.module.paper_key"; } // namespace GpgFrontend diff --git a/src/ui/dialog/controller/ModuleControllerDialog.cpp b/src/ui/dialog/controller/ModuleControllerDialog.cpp index 8f1df81c..aa69eb5a 100644 --- a/src/ui/dialog/controller/ModuleControllerDialog.cpp +++ b/src/ui/dialog/controller/ModuleControllerDialog.cpp @@ -62,14 +62,14 @@ ModuleControllerDialog::ModuleControllerDialog(QWidget* parent) connect(ui_->moduleListView, &ModuleListView::SignalSelectModule, this, &ModuleControllerDialog::slot_load_module_details); - connect(ui_->activateOrDeactiveButton, &QPushButton::clicked, this, [=]() { + connect(ui_->activateOrDeactivateButton, &QPushButton::clicked, this, [=]() { auto module_id = ui_->moduleListView->GetCurrentModuleID(); if (module_id.isEmpty()) return; if (!module_manager_->IsModuleActivated(module_id)) { module_manager_->ActiveModule(module_id); } else { - module_manager_->DeactiveModule(module_id); + module_manager_->DeactivateModule(module_id); } QTimer::singleShot(1000, [=]() { slot_load_module_details(module_id); }); @@ -178,8 +178,8 @@ void ModuleControllerDialog::slot_load_module_details( } ui_->moduleInfoTextBrowser->setText(buffer); - ui_->activateOrDeactiveButton->setText(if_activated ? tr("Deactivate") - : tr("Activate")); + ui_->activateOrDeactivateButton->setText(if_activated ? tr("Deactivate") + : tr("Activate")); ui_->autoActivateButton->setText(module_so.auto_activate ? tr("Disable Auto Activate") : tr("Enable Auto Activate")); diff --git a/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp index 10a1ac00..34b03cd9 100644 --- a/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp @@ -34,6 +34,7 @@ #include "core/function/gpg/GpgKeyImportExporter.h" #include "core/function/gpg/GpgKeyOpera.h" #include "core/model/GpgKey.h" +#include "core/module/ModuleManager.h" #include "core/typedef/GpgTypedef.h" #include "core/utils/GpgUtils.h" #include "core/utils/IOUtils.h" @@ -96,6 +97,16 @@ KeyPairOperaTab::KeyPairOperaTab(const QString& key_id, QWidget* parent) key_server_opera_button->setDisabled(forbid_all_gnupg_connection); advance_h_box_layout->addWidget(key_server_opera_button); + if (!Module::IsModuleActivate(kPaperKeyModuleID)) { + if (!m_key_.IsPrivateKey() || !m_key_.IsHasMasterKey()) { + auto* import_paper_key_button = new QPushButton(tr("Import A Paper Key")); + import_paper_key_button->setStyleSheet("text-align:center;"); + connect(import_paper_key_button, &QPushButton::clicked, this, + &KeyPairOperaTab::slot_import_paper_key); + vbox_p_k->addWidget(import_paper_key_button); + } + } + if (m_key_.IsPrivateKey() && m_key_.IsHasMasterKey()) { auto* revoke_cert_opera_button = new QPushButton(tr("Revoke Certificate Operation")); @@ -168,6 +179,17 @@ void KeyPairOperaTab::CreateOperaMenu() { connect(export_shortest_secret_key, &QAction::triggered, this, &KeyPairOperaTab::slot_export_short_private_key); + if (!Module::IsModuleActivate(kPaperKeyModuleID)) { + auto* export_secret_key_as_paper_key = + new QAction(tr("Export Secret Key As A Paper Key"), this); + connect(export_secret_key_as_paper_key, &QAction::triggered, this, + &KeyPairOperaTab::slot_export_paper_key); + if (!m_key_.IsPrivateKey()) { + export_secret_key_as_paper_key->setDisabled(true); + } + secret_key_export_opera_menu_->addAction(export_secret_key_as_paper_key); + } + secret_key_export_opera_menu_->addAction(export_full_secret_key); secret_key_export_opera_menu_->addAction(export_shortest_secret_key); @@ -447,4 +469,148 @@ void KeyPairOperaTab::slot_import_revoke_cert() { emit UISignalStation::GetInstance() -> SignalKeyRevoked(m_key_.GetId()); CommonUtils::GetInstance()->SlotImportKeys(nullptr, rev_file.readAll()); } + +void KeyPairOperaTab::slot_export_paper_key() { + if (!Module::IsModuleActivate(kPaperKeyModuleID)) return; + + int ret = QMessageBox::information( + this, tr("Exporting private key as a Paper key"), + "<h3>" + tr("You are about to export your") + "<font color=\"red\">" + + tr(" PRIVATE KEY ") + "</font>!</h3>\n" + + tr("This is NOT your Public Key, so DON'T give it away.") + "<br />" + + tr("A PaperKey is a human-readable printout of your private key, " + "which can be used to recover your key if you lose access to " + "your " + "digital copy. ") + + "<br />" + tr("Keep it in a safe place.") + "<br />" + + tr("Do you REALLY want to export your PRIVATE KEY?"), + QMessageBox::Cancel | QMessageBox::Ok); + + // export key, if ok was clicked + if (ret == QMessageBox::Ok) { + auto [err, gf_buffer] = GpgKeyImportExporter::GetInstance().ExportKey( + m_key_, true, false, true); + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + CommonUtils::RaiseMessageBox(this, err); + return; + } + + // generate a file name +#ifndef WINDOWS + auto file_string = m_key_.GetName() + "<" + m_key_.GetEmail() + ">(" + + m_key_.GetId() + ")_paper_key.txt"; +#else + auto file_string = m_key_.GetName() + "[" + m_key_.GetEmail() + "](" + + m_key_.GetId() + ")_paper_key.txt"; +#endif + std::replace(file_string.begin(), file_string.end(), ' ', '_'); + + auto file_name = QFileDialog::getSaveFileName( + this, tr("Export Key To File"), file_string, + tr("Key Files") + " (*.txt);;All Files (*)"); + + if (file_name.isEmpty()) return; + + Module::TriggerEvent( + "REQUEST_TRANS_KEY_2_PAPER_KEY", + { + {"secret_key", QString(gf_buffer.ConvertToQByteArray().toBase64())}, + }, + [this, file_name](Module::EventIdentifier i, + Module::Event::ListenerIdentifier ei, + Module::Event::Params p) { + qCDebug(ui) << "REQUEST_TRANS_KEY_2_PAPER_KEY callback: " << i << ei; + + if (p["ret"] != "0" || p["paper_key"].isEmpty()) { + QMessageBox::critical(this, tr("Error"), + tr("An error occurred trying to recover the " + "Paper Key back to the private key.")); + return; + } + + if (!WriteFile(file_name, p["paper_key"].toLatin1())) { + QMessageBox::critical( + this, tr("Export Error"), + tr("Couldn't open %1 for writing").arg(file_name)); + return; + } + }); + } +} + +void KeyPairOperaTab::slot_import_paper_key() { + if (!Module::IsModuleActivate(kPaperKeyModuleID)) return; + + auto [err, gf_buffer] = + GpgKeyImportExporter::GetInstance().ExportKey(m_key_, false, false, true); + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + CommonUtils::RaiseMessageBox(this, err); + return; + } + + // generate a file name +#ifndef WINDOWS + auto file_string = m_key_.GetName() + "<" + m_key_.GetEmail() + ">(" + + m_key_.GetId() + ")_paper_key.txt"; +#else + auto file_string = m_key_.GetName() + "[" + m_key_.GetEmail() + "](" + + m_key_.GetId() + ")_paper_key.txt"; +#endif + std::replace(file_string.begin(), file_string.end(), ' ', '_'); + + auto file_name = QFileDialog::getOpenFileName( + this, tr("Import A Paper Key"), file_string, + tr("Paper Key File") + " (*.txt);;All Files (*)"); + + if (file_name.isEmpty()) return; + + QFileInfo file_info(file_name); + + if (!file_info.isFile() || !file_info.isReadable()) { + QMessageBox::critical( + this, tr("Error"), + tr("Cannot open this file. Please make sure that this " + "is a regular file and it's readable.")); + return; + } + + if (file_info.size() > static_cast<qint64>(1024 * 1024)) { + QMessageBox::critical( + this, tr("Error"), + tr("The target file is too large for a paper key keyring.")); + return; + } + + auto [succ, gf_in_buff] = ReadFileGFBuffer(file_name); + if (!succ) { + QMessageBox::critical( + this, tr("Error"), + tr("Cannot open this file. Please make sure that this " + "is a regular file and it's readable.")); + return; + } + + Module::TriggerEvent( + "REQUEST_TRANS_PAPER_KEY_2_KEY", + { + {"public_key", QString(gf_buffer.ConvertToQByteArray().toBase64())}, + {"paper_key_secrets", + QString(gf_in_buff.ConvertToQByteArray().toBase64())}, + }, + [this](Module::EventIdentifier i, Module::Event::ListenerIdentifier ei, + Module::Event::Params p) { + qCDebug(ui) << "REQUEST_TRANS_PAPER_KEY_2_KEY callback: " << i << ei; + + if (p["ret"] != "0" || p["secret_key"].isEmpty()) { + QMessageBox::critical(this, tr("Error"), + tr("An error occurred trying to recover the " + "Paper Key back to the private key.")); + return; + } + + CommonUtils::GetInstance()->SlotImportKeys( + this, QByteArray::fromBase64(p["secret_key"].toLatin1())); + }); +} + } // namespace GpgFrontend::UI diff --git a/src/ui/dialog/keypair_details/KeyPairOperaTab.h b/src/ui/dialog/keypair_details/KeyPairOperaTab.h index 22c94957..27bc7400 100644 --- a/src/ui/dialog/keypair_details/KeyPairOperaTab.h +++ b/src/ui/dialog/keypair_details/KeyPairOperaTab.h @@ -126,6 +126,18 @@ class KeyPairOperaTab : public QWidget { */ void slot_import_revoke_cert(); + /** + * @brief + * + */ + void slot_export_paper_key(); + + /** + * @brief + * + */ + void slot_import_paper_key(); + private: GpgKey m_key_; ///< QMenu* key_server_opera_menu_{}; ///< diff --git a/ui/ModuleControllerDialog.ui b/ui/ModuleControllerDialog.ui index 97dd1397..910a3de8 100644 --- a/ui/ModuleControllerDialog.ui +++ b/ui/ModuleControllerDialog.ui @@ -111,7 +111,7 @@ </property> <layout class="QVBoxLayout" name="verticalLayout_4"> <item> - <widget class="QPushButton" name="activateOrDeactiveButton"> + <widget class="QPushButton" name="activateOrDeactivateButton"> <property name="enabled"> <bool>true</bool> </property> |