diff options
author | saturneric <[email protected]> | 2024-11-28 16:19:46 +0000 |
---|---|---|
committer | saturneric <[email protected]> | 2024-11-28 16:19:46 +0000 |
commit | 564b8099189b20b9cf2fa78bfa2620d42f514b72 (patch) | |
tree | d35bd61198618ce6897ae4565a8470597e896983 | |
parent | feat: support encrypting email (diff) | |
download | GpgFrontend-564b8099189b20b9cf2fa78bfa2620d42f514b72.tar.gz GpgFrontend-564b8099189b20b9cf2fa78bfa2620d42f514b72.zip |
feat: support decrypt & verify email
m--------- | modules | 0 | ||||
-rw-r--r-- | src/core/model/GpgSignResult.cpp | 1 | ||||
-rw-r--r-- | src/sdk/GFSDKGpg.cpp | 63 | ||||
-rw-r--r-- | src/sdk/GFSDKGpg.h | 34 | ||||
-rw-r--r-- | src/ui/UIModuleManager.cpp | 10 | ||||
-rw-r--r-- | src/ui/UIModuleManager.h | 17 | ||||
-rw-r--r-- | src/ui/dialog/SignersPicker.cpp | 10 | ||||
-rw-r--r-- | src/ui/dialog/SignersPicker.h | 6 | ||||
-rw-r--r-- | src/ui/main_window/MainWindow.h | 12 | ||||
-rw-r--r-- | src/ui/main_window/MainWindowSlotFunction.cpp | 443 | ||||
-rw-r--r-- | src/ui/main_window/MainWindowSlotUI.cpp | 11 |
11 files changed, 523 insertions, 84 deletions
diff --git a/modules b/modules -Subproject da105c4ae189f63b74e4f2df96031caffba68af +Subproject 3d5d465219ec95bf4f213186e0522e0185e1326 diff --git a/src/core/model/GpgSignResult.cpp b/src/core/model/GpgSignResult.cpp index b7fd2e45..59c402dd 100644 --- a/src/core/model/GpgSignResult.cpp +++ b/src/core/model/GpgSignResult.cpp @@ -27,7 +27,6 @@ */ #include "GpgSignResult.h" - namespace GpgFrontend { GpgSignResult::GpgSignResult(gpgme_sign_result_t r) : result_ref_(std::shared_ptr<struct _gpgme_op_sign_result>( diff --git a/src/sdk/GFSDKGpg.cpp b/src/sdk/GFSDKGpg.cpp index 638c8aa1..4dd23417 100644 --- a/src/sdk/GFSDKGpg.cpp +++ b/src/sdk/GFSDKGpg.cpp @@ -33,12 +33,15 @@ #include "core/function/gpg/GpgKeyGetter.h" #include "core/function/gpg/GpgKeyImportExporter.h" #include "core/model/DataObject.h" +#include "core/model/GpgDecryptResult.h" #include "core/model/GpgEncryptResult.h" #include "core/model/GpgSignResult.h" +#include "core/model/GpgVerifyResult.h" #include "core/typedef/GpgTypedef.h" +#include "core/utils/GpgUtils.h" +#include "ui/UIModuleManager.h" // -#include "core/utils/GpgUtils.h" #include "private/GFSDKPrivat.h" auto GPGFRONTEND_MODULE_SDK_EXPORT GFGpgSignData(int channel, char** key_ids, @@ -72,11 +75,15 @@ auto GPGFRONTEND_MODULE_SDK_EXPORT GFGpgSignData(int channel, char** key_ids, auto out_buffer = GpgFrontend::ExtractParams<GpgFrontend::GFBuffer>(data_object, 1); + auto capsule_id = + GpgFrontend::UI::UIModuleManager::GetInstance().MakeCapsule(result); + *ps = static_cast<GFGpgSignResult*>(GFAllocateMemory(sizeof(GFGpgSignResult))); auto* s = *ps; s->signature = GFStrDup(out_buffer.ConvertToQByteArray()); s->hash_algo = GFStrDup(result.HashAlgo()); + s->capsule_id = GFStrDup(capsule_id); return 0; } @@ -142,9 +149,63 @@ GFGpgEncryptData(int channel, char** key_ids, int key_ids_size, char* data, auto out_buffer = GpgFrontend::ExtractParams<GpgFrontend::GFBuffer>(data_object, 1); + auto capsule_id = + GpgFrontend::UI::UIModuleManager::GetInstance().MakeCapsule(result); + *ps = static_cast<GFGpgEncryptionResult*>( GFAllocateMemory(sizeof(GFGpgEncryptionResult))); auto* s = *ps; s->encrypted_data = GFStrDup(out_buffer.ConvertToQByteArray()); + s->capsule_id = GFStrDup(capsule_id); + return 0; +} + +auto GPGFRONTEND_MODULE_SDK_EXPORT +GFGpgDecryptData(int channel, char* data, GFGpgDecryptResult** ps) -> int { + auto in_buffer = GpgFrontend::GFBuffer(GFUnStrDup(data).toUtf8()); + + auto [err, data_object] = + GpgFrontend::GpgBasicOperator::GetInstance(channel).DecryptSync( + in_buffer); + + if (GpgFrontend::CheckGpgError(err) != GPG_ERR_NO_ERROR) return -1; + + auto result = + GpgFrontend::ExtractParams<GpgFrontend::GpgDecryptResult>(data_object, 0); + auto out_buffer = + GpgFrontend::ExtractParams<GpgFrontend::GFBuffer>(data_object, 1); + + auto capsule_id = + GpgFrontend::UI::UIModuleManager::GetInstance().MakeCapsule(result); + + *ps = static_cast<GFGpgDecryptResult*>( + GFAllocateMemory(sizeof(GFGpgDecryptResult))); + auto* s = *ps; + s->decrypted_data = GFStrDup(out_buffer.ConvertToQByteArray()); + s->capsule_id = GFStrDup(capsule_id); + return 0; +} + +auto GPGFRONTEND_MODULE_SDK_EXPORT GFGpgVerifyData( + int channel, char* data, char* signature, GFGpgVerifyResult** ps) -> int { + auto in_buffer = GpgFrontend::GFBuffer(GFUnStrDup(data).toUtf8()); + auto sig_buffer = GpgFrontend::GFBuffer(GFUnStrDup(signature).toUtf8()); + + auto [err, data_object] = + GpgFrontend::GpgBasicOperator::GetInstance(channel).VerifySync( + in_buffer, sig_buffer); + + if (GpgFrontend::CheckGpgError(err) != GPG_ERR_NO_ERROR) return -1; + + auto result = + GpgFrontend::ExtractParams<GpgFrontend::GpgVerifyResult>(data_object, 0); + + auto capsule_id = + GpgFrontend::UI::UIModuleManager::GetInstance().MakeCapsule(result); + + *ps = static_cast<GFGpgVerifyResult*>( + GFAllocateMemory(sizeof(GFGpgVerifyResult))); + auto* s = *ps; + s->capsule_id = GFStrDup(capsule_id); return 0; } diff --git a/src/sdk/GFSDKGpg.h b/src/sdk/GFSDKGpg.h index fa7325fc..ac166a54 100644 --- a/src/sdk/GFSDKGpg.h +++ b/src/sdk/GFSDKGpg.h @@ -35,10 +35,21 @@ extern "C" { struct GFGpgSignResult { char* signature; char* hash_algo; + char* capsule_id; }; struct GFGpgEncryptionResult { char* encrypted_data; + char* capsule_id; +}; + +struct GFGpgDecryptResult { + char* decrypted_data; + char* capsule_id; +}; + +struct GFGpgVerifyResult { + char* capsule_id; }; struct GFGpgKeyUID { @@ -82,6 +93,29 @@ GFGpgEncryptData(int channel, char** key_ids, int key_ids_size, char* data, * @param mode * @return const char* */ +auto GPGFRONTEND_MODULE_SDK_EXPORT +GFGpgDecryptData(int channel, char* data, GFGpgDecryptResult**) -> int; + +/** + * @brief + * + * @param key_id + * @param data + * @param mode + * @return const char* + */ +auto GPGFRONTEND_MODULE_SDK_EXPORT GFGpgVerifyData(int channel, char* data, + char* signature, + GFGpgVerifyResult**) -> int; + +/** + * @brief + * + * @param key_id + * @param data + * @param mode + * @return const char* + */ auto GPGFRONTEND_MODULE_SDK_EXPORT GFGpgPublicKey(int channel, char* key_id, int ascii) -> char*; diff --git a/src/ui/UIModuleManager.cpp b/src/ui/UIModuleManager.cpp index ba6172a4..89621f9c 100644 --- a/src/ui/UIModuleManager.cpp +++ b/src/ui/UIModuleManager.cpp @@ -187,4 +187,14 @@ auto UIModuleManager::GetQObject(const QString& id) -> QObject* { return registered_qobjects_.value(id, nullptr); } +auto UIModuleManager::GetCapsule(const QString& uuid) -> std::any { + return capsule_.take(uuid); +} + +auto UIModuleManager::MakeCapsule(std::any v) -> QString { + auto uuid = QUuid::createUuid().toString(); + capsule_[uuid] = std::move(v); + return uuid; +} + } // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/UIModuleManager.h b/src/ui/UIModuleManager.h index 7f23fc78..2388dc71 100644 --- a/src/ui/UIModuleManager.h +++ b/src/ui/UIModuleManager.h @@ -129,6 +129,22 @@ class GPGFRONTEND_UI_EXPORT UIModuleManager /** * @brief * + * @param id + * @return auto + */ + auto MakeCapsule(std::any) -> QString; + + /** + * @brief + * + * @param id + * @return auto + */ + auto GetCapsule(const QString& uuid) -> std::any; + + /** + * @brief + * */ void RegisterAllModuleTranslators(); @@ -145,6 +161,7 @@ class GPGFRONTEND_UI_EXPORT UIModuleManager QList<QTranslator*> registered_translators_; QList<QByteArray> read_translator_data_list_; QMap<QString, QPointer<QObject>> registered_qobjects_; + QMap<QString, std::any> capsule_; }; } // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/dialog/SignersPicker.cpp b/src/ui/dialog/SignersPicker.cpp index 507ee467..dcd23a6b 100644 --- a/src/ui/dialog/SignersPicker.cpp +++ b/src/ui/dialog/SignersPicker.cpp @@ -82,6 +82,16 @@ auto SignersPicker::GetCheckedSigners() -> GpgFrontend::KeyIdArgsListPtr { return key_list_->GetCheckedPrivateKey(); } +auto SignersPicker::GetCheckedSignerKeyIds() -> QStringList { + auto priv_keys = key_list_->GetCheckedPrivateKey(); + + QStringList r; + for (const auto& priv_key : *priv_keys) { + r.append(priv_key); + } + return r; +} + auto SignersPicker::GetStatus() const -> bool { return this->accepted_; } } // namespace GpgFrontend::UI diff --git a/src/ui/dialog/SignersPicker.h b/src/ui/dialog/SignersPicker.h index 0b1b7cb9..accf6952 100644 --- a/src/ui/dialog/SignersPicker.h +++ b/src/ui/dialog/SignersPicker.h @@ -59,6 +59,12 @@ class SignersPicker : public GeneralDialog { auto GetCheckedSigners() -> KeyIdArgsListPtr; /** + * @brief Get the Checked Signer Key Ids object + * + * @return QStringList + */ + auto GetCheckedSignerKeyIds() -> QStringList; + /** * * @return */ diff --git a/src/ui/main_window/MainWindow.h b/src/ui/main_window/MainWindow.h index cd0babd3..49fe7a1a 100644 --- a/src/ui/main_window/MainWindow.h +++ b/src/ui/main_window/MainWindow.h @@ -189,6 +189,18 @@ class MainWindow : public GeneralMainWindow { void SlotEncryptEML(); /** + * @brief + * + */ + void SlotEncryptSignEML(); + + /** + * @brief + * + */ + void SlotDecryptVerifyEML(); + + /** * @details decrypt and verify the text of currently active textedit-page * with the currently checked keys */ diff --git a/src/ui/main_window/MainWindowSlotFunction.cpp b/src/ui/main_window/MainWindowSlotFunction.cpp index e3225d6c..8d4611ac 100644 --- a/src/ui/main_window/MainWindowSlotFunction.cpp +++ b/src/ui/main_window/MainWindowSlotFunction.cpp @@ -31,12 +31,18 @@ #include "core/function/gpg/GpgKeyGetter.h" #include "core/function/gpg/GpgKeyImportExporter.h" #include "core/function/result_analyse/GpgDecryptResultAnalyse.h" +#include "core/function/result_analyse/GpgEncryptResultAnalyse.h" +#include "core/function/result_analyse/GpgSignResultAnalyse.h" #include "core/model/GpgDecryptResult.h" +#include "core/model/GpgEncryptResult.h" +#include "core/model/GpgSignResult.h" #include "core/module/ModuleManager.h" #include "core/typedef/GpgTypedef.h" #include "core/utils/CommonUtils.h" #include "core/utils/GpgUtils.h" +#include "ui/UIModuleManager.h" #include "ui/UserInterfaceUtils.h" +#include "ui/dialog/SignersPicker.h" #include "ui/dialog/help/AboutDialog.h" #include "ui/dialog/import_export/KeyUploadDialog.h" #include "ui/dialog/keypair_details/KeyDetailsDialog.h" @@ -354,6 +360,8 @@ void MainWindow::slot_verify_email_by_eml_data(const QByteArray& buffer) { "EMAIL_VERIFY_EML_DATA", { {"eml_data", QString::fromLatin1(buffer.toBase64())}, + {"channel", + QString::number(m_key_list_->GetCurrentGpgContextChannel())}, }, [=](Module::EventIdentifier i, Module::Event::ListenerIdentifier ei, Module::Event::Params p) { @@ -405,6 +413,8 @@ void MainWindow::slot_decrypt_email_by_eml_data(const QByteArray& buffer) { "EMAIL_DECRYPT_EML_DATA", { {"eml_data", QString::fromLatin1(buffer.toBase64())}, + {"channel", + QString::number(m_key_list_->GetCurrentGpgContextChannel())}, }, [=](Module::EventIdentifier i, Module::Event::ListenerIdentifier ei, Module::Event::Params p) { @@ -443,7 +453,7 @@ void MainWindow::slot_decrypt_email_by_eml_data(const QByteArray& buffer) { return; } - if (p.contains("encrypted")) { + if (p.contains("eml_data")) { slot_decrypt_email_by_eml_data_result_helper(p); } @@ -540,50 +550,25 @@ void MainWindow::slot_verify_email_by_eml_data_result_helper( .arg(prm_micalg_value)); email_info.append("\n"); - // set input buffer - auto raw_data_buffer = GFBuffer(mime); - auto signature_buffer = GFBuffer(signature); - - CommonUtils::WaitForOpera( - this, tr("Verifying"), - [this, email_info, raw_data_buffer, - signature_buffer](const OperaWaitingHd& hd) { - GpgFrontend::GpgBasicOperator::GetInstance( - m_key_list_->GetCurrentGpgContextChannel()) - .Verify( - raw_data_buffer, signature_buffer, - [this, email_info, hd](GpgError err, - const DataObjectPtr& data_obj) { - // stop waiting - hd(); - - if (CheckGpgError(err) == GPG_ERR_USER_1 || - data_obj == nullptr || - !data_obj->Check<GpgVerifyResult>()) { - QMessageBox::critical(this, tr("Error"), - tr("Unknown error occurred")); - return; - } - auto verify_result = - ExtractParams<GpgVerifyResult>(data_obj, 0); - - // analyse result - auto result_analyse = GpgVerifyResultAnalyse( - m_key_list_->GetCurrentGpgContextChannel(), err, - verify_result); - result_analyse.Analyse(); - auto verify_result_report = result_analyse.GetResultReport(); - - slot_refresh_info_board(result_analyse.GetStatus(), - email_info + verify_result_report); - - if (!result_analyse.GetUnknownSignatures().isEmpty() && - Module::IsModuleActivate(kKeyServerSyncModuleID)) { - slot_verifying_unknown_signature_helper(result_analyse); - return; - } - }); - }); + if (!p["capsule_id"].isEmpty()) { + auto v = + UIModuleManager::GetInstance().GetCapsule(p.value("capsule_id", "")); + + try { + auto sign_result = std::any_cast<GpgVerifyResult>(v); + auto result_analyse = + GpgVerifyResultAnalyse(m_key_list_->GetCurrentGpgContextChannel(), + GPG_ERR_NO_ERROR, sign_result); + result_analyse.Analyse(); + + slot_refresh_info_board(result_analyse.GetStatus(), + email_info + result_analyse.GetResultReport()); + + } catch (const std::bad_any_cast& e) { + LOG_E() << "capsule" << p["capsule_id"] << "convert to real type failed" + << e.what(); + } + } } void MainWindow::slot_eml_verify_show_helper(const QString& email_info, @@ -628,14 +613,15 @@ void MainWindow::SlotDecryptEML() { void MainWindow::slot_decrypt_email_by_eml_data_result_helper( const QMap<QString, QString>& p) { - const auto encrypted = QByteArray::fromBase64(p["encrypted"].toLatin1()); - auto timestamp = p.value("datetime", "-1").toLongLong(); auto datetime = tr("None"); if (timestamp > 0) { datetime = QLocale().toString(QDateTime::fromMSecsSinceEpoch(timestamp)); } + const auto eml_data = QByteArray::fromBase64(p["eml_data"].toLatin1()); + edit_->SlotFillTextEditWithText(eml_data); + QString email_info; email_info.append("# E-Mail Information\n\n"); email_info.append(QString("- %1: %2\n") @@ -654,39 +640,25 @@ void MainWindow::slot_decrypt_email_by_eml_data_result_helper( email_info.append("\n"); - // data to transfer into task - auto buffer = GFBuffer(encrypted); - - CommonUtils::WaitForOpera( - this, tr("Decrypting"), [this, buffer](const OperaWaitingHd& hd) { - GpgFrontend::GpgBasicOperator::GetInstance( - m_key_list_->GetCurrentGpgContextChannel()) - .Decrypt(buffer, [this, hd](GpgError err, - const DataObjectPtr& data_obj) { - // stop waiting - hd(); - - if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || - !data_obj->Check<GpgDecryptResult, GFBuffer>()) { - QMessageBox::critical(this, tr("Error"), - tr("Unknown error occurred")); - return; - } - auto decrypt_result = - ExtractParams<GpgDecryptResult>(data_obj, 0); - auto out_buffer = ExtractParams<GFBuffer>(data_obj, 1); - auto result_analyse = GpgDecryptResultAnalyse( - m_key_list_->GetCurrentGpgContextChannel(), err, - decrypt_result); - result_analyse.Analyse(); - slot_result_analyse_show_helper(result_analyse); - - if (CheckGpgError(err) == GPG_ERR_NO_ERROR) { - edit_->SlotFillTextEditWithText( - out_buffer.ConvertToQByteArray()); - } - }); - }); + if (!p["capsule_id"].isEmpty()) { + auto v = + UIModuleManager::GetInstance().GetCapsule(p.value("capsule_id", "")); + + try { + auto sign_result = std::any_cast<GpgDecryptResult>(v); + auto result_analyse = + GpgDecryptResultAnalyse(m_key_list_->GetCurrentGpgContextChannel(), + GPG_ERR_NO_ERROR, sign_result); + result_analyse.Analyse(); + + slot_refresh_info_board(result_analyse.GetStatus(), + email_info + result_analyse.GetResultReport()); + + } catch (const std::bad_any_cast& e) { + LOG_E() << "capsule" << p["capsule_id"] << "convert to real type failed" + << e.what(); + } + } } void MainWindow::SlotEncryptEML() { @@ -710,7 +682,7 @@ void MainWindow::SlotEncryptEML() { }, [=](Module::EventIdentifier i, Module::Event::ListenerIdentifier ei, Module::Event::Params p) { - LOG_D() << "EMAIL_DECRYPT_EML_DATA callback: " << i << ei; + LOG_D() << "EMAIL_ENCRYPT_EML_DATA callback: " << i << ei; if (p["ret"] != "0" || !p["err"].isEmpty()) { LOG_E() << "An error occurred trying to decrypt email, " << "error message: " << p["err"]; @@ -722,6 +694,24 @@ void MainWindow::SlotEncryptEML() { edit_->SlotSetText2CurEMailPage(p.value("eml_data", "")); } + if (!p["capsule_id"].isEmpty()) { + auto v = UIModuleManager::GetInstance().GetCapsule( + p.value("capsule_id", "")); + + try { + auto encr_result = std::any_cast<GpgEncryptResult>(v); + auto result_analyse = GpgEncryptResultAnalyse( + m_key_list_->GetCurrentGpgContextChannel(), GPG_ERR_NO_ERROR, + encr_result); + result_analyse.Analyse(); + slot_result_analyse_show_helper(result_analyse); + + } catch (const std::bad_any_cast& e) { + LOG_E() << "capsule" << p["capsule_id"] + << "convert to real type failed" << e.what(); + } + } + LOG_E() << "mime or signature data is missing"; }); } @@ -754,7 +744,114 @@ void MainWindow::SlotSignEML() { }, [=](Module::EventIdentifier i, Module::Event::ListenerIdentifier ei, Module::Event::Params p) { - LOG_D() << "EMAIL_DECRYPT_EML_DATA callback: " << i << ei; + LOG_D() << "EMAIL_SIGN_EML_DATA callback: " << i << ei; + if (p["ret"] != "0" || !p["err"].isEmpty()) { + LOG_E() << "An error occurred trying to decrypt email, " + << "error message: " << p["err"]; + + return; + } + + if (p["ret"] == "-2") { + QString detailed_error = p["err"]; + + QString info = + tr("# EML Data Error\n\n" + "The provided EML data does not conform to the " + "structure described in RFC 3156 and cannot be " + "validated.\n\n" + "Details: %1\n\n" + "What is EML Data?\n" + "EML is a file format used to represent email messages. " + "It typically contains the entire contents of an email, " + "including headers, " + "body text, attachments, and metadata. In order to validate " + "the email properly, it is necessary to provide the " + "complete, original EML " + "data.\n\n" + "For more information about the expected EML structure, " + "please refer to the RFC 3156 standard:\n" + "%2\n\n" + "Please ensure the EML data follows the standard and try " + "again.") + .arg(detailed_error) + .arg("https://www.rfc-editor.org/rfc/rfc3156.txt"); + slot_refresh_info_board(-2, info); + } + + if (!p["eml_data"].isEmpty()) { + edit_->SlotSetText2CurEMailPage(p.value("eml_data", "")); + } + + if (!p["capsule_id"].isEmpty()) { + auto v = UIModuleManager::GetInstance().GetCapsule( + p.value("capsule_id", "")); + + try { + auto sign_result = std::any_cast<GpgSignResult>(v); + auto result_analyse = + GpgSignResultAnalyse(m_key_list_->GetCurrentGpgContextChannel(), + GPG_ERR_NO_ERROR, sign_result); + result_analyse.Analyse(); + slot_result_analyse_show_helper(result_analyse); + + } catch (const std::bad_any_cast& e) { + LOG_E() << "capsule" << p["capsule_id"] + << "convert to real type failed" << e.what(); + } + } + + LOG_E() << "mime or signature data is missing"; + }); +} + +void MainWindow::SlotEncryptSignEML() { + if (edit_->TabCount() == 0 || edit_->CurEMailPage() == nullptr) return; + auto checked_keys = m_key_list_->GetCheckedKeys(); + + if (checked_keys.isEmpty()) { + QMessageBox::warning(this, tr("No Key Selected"), + tr("Please select a key for encrypt the EML.")); + return; + } + + auto* signers_picker = + new SignersPicker(m_key_list_->GetCurrentGpgContextChannel(), this); + QEventLoop loop; + connect(signers_picker, &SignersPicker::finished, &loop, &QEventLoop::quit); + loop.exec(); + + // return when canceled + if (!signers_picker->GetStatus()) return; + + auto signer_keys = signers_picker->GetCheckedSignerKeyIds(); + + if (signer_keys.isEmpty()) { + QMessageBox::warning(this, tr("No Key Selected"), + tr("Please select a key for signing the EML.")); + return; + } + + if (signer_keys.size() > 1) { + QMessageBox::warning(this, tr("Multiple Keys Selected"), + tr("Please select only one key to sign the EML.")); + return; + } + + auto buffer = edit_->CurPlainText().toUtf8(); + + Module::TriggerEvent( + "EMAIL_ENCRYPT_SIGN_EML_DATA", + { + {"body_data", QString::fromLatin1(buffer.toBase64())}, + {"channel", + QString::number(m_key_list_->GetCurrentGpgContextChannel())}, + {"sign_key", signer_keys.front()}, + {"encrypt_keys", checked_keys.front()}, + }, + [=](Module::EventIdentifier i, Module::Event::ListenerIdentifier ei, + Module::Event::Params p) { + LOG_D() << "EMAIL_ENCRYPT_SIGN_EML_DATA callback: " << i << ei; if (p["ret"] != "0" || !p["err"].isEmpty()) { LOG_E() << "An error occurred trying to decrypt email, " << "error message: " << p["err"]; @@ -762,10 +859,192 @@ void MainWindow::SlotSignEML() { return; } + if (p["ret"] == "-2") { + QString detailed_error = p["err"]; + + QString info = + tr("# EML Data Error\n\n" + "The provided EML data does not conform to the " + "structure described in RFC 3156 and cannot be " + "validated.\n\n" + "Details: %1\n\n" + "What is EML Data?\n" + "EML is a file format used to represent email messages. " + "It typically contains the entire contents of an email, " + "including headers, " + "body text, attachments, and metadata. In order to validate " + "the email properly, it is necessary to provide the " + "complete, original EML " + "data.\n\n" + "For more information about the expected EML structure, " + "please refer to the RFC 3156 standard:\n" + "%2\n\n" + "Please ensure the EML data follows the standard and try " + "again.") + .arg(detailed_error) + .arg("https://www.rfc-editor.org/rfc/rfc3156.txt"); + slot_refresh_info_board(-2, info); + } + if (!p["eml_data"].isEmpty()) { edit_->SlotSetText2CurEMailPage(p.value("eml_data", "")); } + if (!p["sign_capsule_id"].isEmpty() && + !p["encr_capsule_id"].isEmpty()) { + auto v1 = UIModuleManager::GetInstance().GetCapsule( + p.value("sign_capsule_id", "")); + auto v2 = UIModuleManager::GetInstance().GetCapsule( + p.value("encr_capsule_id", "")); + + try { + auto sign_result = std::any_cast<GpgSignResult>(v1); + auto encr_result = std::any_cast<GpgSignResult>(v1); + auto sign_result_analyse = + GpgSignResultAnalyse(m_key_list_->GetCurrentGpgContextChannel(), + GPG_ERR_NO_ERROR, sign_result); + auto encr_result_analyse = + GpgSignResultAnalyse(m_key_list_->GetCurrentGpgContextChannel(), + GPG_ERR_NO_ERROR, sign_result); + + sign_result_analyse.Analyse(); + encr_result_analyse.Analyse(); + slot_result_analyse_show_helper(sign_result_analyse, + encr_result_analyse); + + } catch (const std::bad_any_cast& e) { + LOG_E() << "capsule" << p["capsule_id"] + << "convert to real type failed" << e.what(); + } + } + + LOG_E() << "mime or signature data is missing"; + }); +} + +void MainWindow::SlotDecryptVerifyEML() { + if (edit_->TabCount() == 0 || edit_->CurEMailPage() == nullptr) return; + + auto buffer = edit_->CurPlainText().toUtf8(); + + Module::TriggerEvent( + "EMAIL_DECRYPT_VERIFY_EML_DATA", + { + {"eml_data", QString::fromLatin1(buffer.toBase64())}, + {"channel", + QString::number(m_key_list_->GetCurrentGpgContextChannel())}, + }, + [=](Module::EventIdentifier i, Module::Event::ListenerIdentifier ei, + Module::Event::Params p) { + LOG_D() << "EMAIL_DECRYPT_VERIFY_EML_DATA callback: " << i << ei; + if (p["ret"] != "0" || !p["err"].isEmpty()) { + LOG_E() << "An error occurred trying to decrypt email, " + << "error message: " << p["err"]; + + return; + } + + if (p["ret"] == "-2") { + QString detailed_error = p["err"]; + + QString info = + tr("# EML Data Error\n\n" + "The provided EML data does not conform to the " + "structure described in RFC 3156 and cannot be " + "validated.\n\n" + "Details: %1\n\n" + "What is EML Data?\n" + "EML is a file format used to represent email messages. " + "It typically contains the entire contents of an email, " + "including headers, " + "body text, attachments, and metadata. In order to validate " + "the email properly, it is necessary to provide the " + "complete, original EML " + "data.\n\n" + "For more information about the expected EML structure, " + "please refer to the RFC 3156 standard:\n" + "%2\n\n" + "Please ensure the EML data follows the standard and try " + "again.") + .arg(detailed_error) + .arg("https://www.rfc-editor.org/rfc/rfc3156.txt"); + slot_refresh_info_board(-2, info); + } + + edit_->SlotSetText2CurEMailPage(p.value("eml_data", "")); + + const auto mime = QByteArray::fromBase64(p["mime"].toLatin1()); + const auto signature = + QByteArray::fromBase64(p["signature"].toLatin1()); + const auto part_mime_content_hash = p["mime_hash"]; + const auto prm_micalg_value = p["micalg"]; + + auto timestamp = p.value("datetime", "-1").toLongLong(); + auto datetime = tr("None"); + if (timestamp > 0) { + datetime = + QLocale().toString(QDateTime::fromMSecsSinceEpoch(timestamp)); + } + + QString email_info; + email_info.append("# E-Mail Information\n\n"); + email_info.append(QString("- %1: %2\n") + .arg(tr("From")) + .arg(p.value("from", tr("Unknown")))); + email_info.append(QString("- %1: %2\n") + .arg(tr("To")) + .arg(p.value("to", tr("Unknown")))); + email_info.append(QString("- %1: %2\n") + .arg(tr("Subject")) + .arg(p.value("subject", tr("None")))); + email_info.append( + QString("- %1: %2\n").arg(tr("CC")).arg(p.value("cc", tr("None")))); + email_info.append(QString("- %1: %2\n") + .arg(tr("BCC")) + .arg(p.value("bcc", tr("None")))); + email_info.append(QString("- %1: %2\n").arg(tr("Date")).arg(datetime)); + + email_info.append("\n"); + email_info.append("# OpenPGP Information\n\n"); + email_info.append(QString("- %1: %2\n") + .arg(tr("Signed EML Data Hash (SHA1)")) + .arg(part_mime_content_hash)); + email_info.append(QString("- %1: %2\n") + .arg(tr("Message Integrity Check Algorithm")) + .arg(prm_micalg_value)); + email_info.append("\n"); + + if (!p["decr_capsule_id"].isEmpty() && + !p["verify_capsule_id"].isEmpty()) { + auto v1 = UIModuleManager::GetInstance().GetCapsule( + p.value("decr_capsule_id", "")); + auto v2 = UIModuleManager::GetInstance().GetCapsule( + p.value("verify_capsule_id", "")); + + try { + auto decr_result = std::any_cast<GpgDecryptResult>(v1); + auto verify_result = std::any_cast<GpgVerifyResult>(v2); + auto decr_result_analyse = GpgDecryptResultAnalyse( + m_key_list_->GetCurrentGpgContextChannel(), GPG_ERR_NO_ERROR, + decr_result); + auto verify_result_analyse = GpgVerifyResultAnalyse( + m_key_list_->GetCurrentGpgContextChannel(), GPG_ERR_NO_ERROR, + verify_result); + + decr_result_analyse.Analyse(); + verify_result_analyse.Analyse(); + slot_refresh_info_board( + std::min(decr_result_analyse.GetStatus(), + verify_result_analyse.GetStatus()), + email_info + decr_result_analyse.GetResultReport() + + verify_result_analyse.GetResultReport()); + + } catch (const std::bad_any_cast& e) { + LOG_E() << "capsule" << p["capsule_id"] + << "convert to real type failed" << e.what(); + } + } + LOG_E() << "mime or signature data is missing"; }); } diff --git a/src/ui/main_window/MainWindowSlotUI.cpp b/src/ui/main_window/MainWindowSlotUI.cpp index 576700bc..53fa29a4 100644 --- a/src/ui/main_window/MainWindowSlotUI.cpp +++ b/src/ui/main_window/MainWindowSlotUI.cpp @@ -301,6 +301,12 @@ void MainWindow::SlotGeneralEncryptSign(bool) { this->SlotDirectoryEncryptSign(path); } } + + if (edit_->CurEMailPage() != nullptr) { + this->SlotEncryptSignEML(); + return; + } + if (edit_->SlotCurPageTextEdit() != nullptr) { this->SlotEncryptSign(); } @@ -323,6 +329,11 @@ void MainWindow::SlotGeneralDecryptVerify(bool) { } } + if (edit_->CurEMailPage() != nullptr) { + this->SlotDecryptVerifyEML(); + return; + } + if (edit_->SlotCurPageTextEdit() != nullptr) { this->SlotDecryptVerify(); } |