diff options
author | Saturneric <[email protected]> | 2021-08-10 15:24:07 +0000 |
---|---|---|
committer | Saturneric <[email protected]> | 2021-08-10 15:24:07 +0000 |
commit | 98c5bb40d139fcb7a7600bdeb1f28d4f94b9f49a (patch) | |
tree | 33b2629f98bf038fe88efc7a99ca94ed74e7269b | |
parent | Add Functions: (diff) | |
download | GpgFrontend-98c5bb40d139fcb7a7600bdeb1f28d4f94b9f49a.tar.gz GpgFrontend-98c5bb40d139fcb7a7600bdeb1f28d4f94b9f49a.zip |
Split some source files that are too large.
26 files changed, 2515 insertions, 2013 deletions
diff --git a/include/gpg/result_analyse/DecryptResultAnalyse.h b/include/gpg/result_analyse/DecryptResultAnalyse.h index 6ec7d3be..51cfbd5f 100644 --- a/include/gpg/result_analyse/DecryptResultAnalyse.h +++ b/include/gpg/result_analyse/DecryptResultAnalyse.h @@ -1,6 +1,26 @@ -// -// Created by eric on 2021/6/9. -// +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ #ifndef GPGFRONTEND_DECRYPTRESULTANALYSE_H #define GPGFRONTEND_DECRYPTRESULTANALYSE_H diff --git a/include/gpg/result_analyse/EncryptResultAnalyse.h b/include/gpg/result_analyse/EncryptResultAnalyse.h index 4717728b..c47b5835 100644 --- a/include/gpg/result_analyse/EncryptResultAnalyse.h +++ b/include/gpg/result_analyse/EncryptResultAnalyse.h @@ -1,6 +1,26 @@ -// -// Created by eric on 2021/6/9. -// +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ #ifndef GPGFRONTEND_ENCRYPTRESULTANALYSE_H #define GPGFRONTEND_ENCRYPTRESULTANALYSE_H diff --git a/include/gpg/result_analyse/ResultAnalyse.h b/include/gpg/result_analyse/ResultAnalyse.h index debfb71a..7b506e95 100644 --- a/include/gpg/result_analyse/ResultAnalyse.h +++ b/include/gpg/result_analyse/ResultAnalyse.h @@ -1,7 +1,26 @@ -// -// Created by eric on 2021/6/8. -// - +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ #ifndef GPGFRONTEND_RESULTANALYSE_H #define GPGFRONTEND_RESULTANALYSE_H diff --git a/include/gpg/result_analyse/SignResultAnalyse.h b/include/gpg/result_analyse/SignResultAnalyse.h index e837140d..a353a2f8 100644 --- a/include/gpg/result_analyse/SignResultAnalyse.h +++ b/include/gpg/result_analyse/SignResultAnalyse.h @@ -1,6 +1,26 @@ -// -// Created by eric on 2021/6/8. -// +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ #ifndef GPGFRONTEND_SIGNRESULTANALYSE_H #define GPGFRONTEND_SIGNRESULTANALYSE_H diff --git a/include/gpg/result_analyse/VerifyResultAnalyse.h b/include/gpg/result_analyse/VerifyResultAnalyse.h index 2041940b..c009741a 100644 --- a/include/gpg/result_analyse/VerifyResultAnalyse.h +++ b/include/gpg/result_analyse/VerifyResultAnalyse.h @@ -1,6 +1,26 @@ -// -// Created by eric on 2021/6/7. -// +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ #ifndef GPGFRONTEND_VERIFYRESULTANALYSE_H #define GPGFRONTEND_VERIFYRESULTANALYSE_H diff --git a/include/ui/ShowCopyDialog.h b/include/ui/ShowCopyDialog.h index 04ea4bab..cca6e67f 100644 --- a/include/ui/ShowCopyDialog.h +++ b/include/ui/ShowCopyDialog.h @@ -1,6 +1,26 @@ -// -// Created by Administrator on 2021/7/21. -// +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ #ifndef GPGFRONTEND_ZH_CN_TS_SHOWCOPYDIALOG_H #define GPGFRONTEND_ZH_CN_TS_SHOWCOPYDIALOG_H diff --git a/include/ui/help/VersionCheckThread.h b/include/ui/help/VersionCheckThread.h index 10c9da87..7ee90077 100644 --- a/include/ui/help/VersionCheckThread.h +++ b/include/ui/help/VersionCheckThread.h @@ -1,6 +1,26 @@ -// -// Created by Administrator on 2021/7/12. -// +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ #ifndef GPGFRONTEND_VERSIONCHECKTHREAD_H #define GPGFRONTEND_VERSIONCHECKTHREAD_H diff --git a/include/ui/keypair_details/EditSubKeyDialog.h b/include/ui/keypair_details/EditSubKeyDialog.h index be926be7..6577d382 100644 --- a/include/ui/keypair_details/EditSubKeyDialog.h +++ b/include/ui/keypair_details/EditSubKeyDialog.h @@ -1,6 +1,26 @@ -// -// Created by eric on 2021/6/2. -// +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ #ifndef GPGFRONTEND_EDITSUBKEY_H #define GPGFRONTEND_EDITSUBKEY_H diff --git a/src/gpg/CMakeLists.txt b/src/gpg/CMakeLists.txt index 49e98b23..2bcacade 100644 --- a/src/gpg/CMakeLists.txt +++ b/src/gpg/CMakeLists.txt @@ -1,4 +1,5 @@ aux_source_directory(./result_analyse GPG_SOURCE) +aux_source_directory(./gpg_context GPG_SOURCE) aux_source_directory(. GPG_SOURCE) add_library(gpg STATIC ${GPG_SOURCE}) diff --git a/src/gpg/GpgContext.cpp b/src/gpg/GpgContext.cpp deleted file mode 100644 index ff32edd8..00000000 --- a/src/gpg/GpgContext.cpp +++ /dev/null @@ -1,1227 +0,0 @@ -/** - * 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. - * - * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from gpg4usb-team. - * Their source code version also complies with GNU General Public License. - * - * The source code version of this software was modified and released - * by Saturneric<[email protected]> starting on May 12, 2021. - * - */ - -#include "gpg/GpgContext.h" - -#include <functional> -#include <unistd.h> /* contains read/write */ - -#ifdef _WIN32 - -#include <windows.h> - -#endif - -#define INT2VOIDP(i) (void*)(uintptr_t)(i) - -namespace GpgME { - -/** Constructor - * Set up gpgme-context, set paths to app-run path - */ - GpgContext::GpgContext() { - /** get application path */ - QString appPath = qApp->applicationDirPath(); - - /** The function `gpgme_check_version' must be called before any other - * function in the library, because it initializes the thread support - * subsystem in GPGME. (from the info page) */ - gpgme_check_version(nullptr); - - // the locale set here is used for the other setlocale calls which have nullptr - // -> nullptr means use default, which is configured here - setlocale(LC_ALL, settings.value("int/lang").toLocale().name().toUtf8().constData()); - - /** set locale, because tests do also */ - gpgme_set_locale(nullptr, LC_CTYPE, setlocale(LC_CTYPE, nullptr)); - //qDebug() << "Locale set to" << LC_CTYPE << " - " << setlocale(LC_CTYPE, nullptr); -#ifndef _WIN32 - gpgme_set_locale(nullptr, LC_MESSAGES, setlocale(LC_MESSAGES, nullptr)); -#endif - - err = gpgme_new(&mCtx); - checkErr(err); - - gpgme_engine_info_t engineInfo; - engineInfo = gpgme_ctx_get_engine_info(mCtx); - - // Check ENV before running - bool check_pass = false, find_openpgp = false, find_gpgconf = false, find_assuan = false, find_cms = false; - while (engineInfo != nullptr) { - qDebug() << gpgme_get_protocol_name(engineInfo->protocol) << engineInfo->file_name << engineInfo->protocol - << engineInfo->home_dir << engineInfo->version; - if (engineInfo->protocol == GPGME_PROTOCOL_GPGCONF && strcmp(engineInfo->version, "1.0.0") != 0) - find_gpgconf = true; - if (engineInfo->protocol == GPGME_PROTOCOL_OpenPGP && strcmp(engineInfo->version, "1.0.0") != 0) { - gpgExec = engineInfo->file_name; - find_openpgp = true; - } - if (engineInfo->protocol == GPGME_PROTOCOL_CMS && strcmp(engineInfo->version, "1.0.0") != 0) - find_cms = true; - if (engineInfo->protocol == GPGME_PROTOCOL_ASSUAN) - find_assuan = true; - - engineInfo = engineInfo->next; - } - - if (find_gpgconf && find_openpgp && find_cms && find_assuan) - check_pass = true; - - if (!check_pass) { - good = false; - return; - } else good = true; - - - /** Setting the output type must be done at the beginning */ - /** think this means ascii-armor --> ? */ - gpgme_set_armor(mCtx, 1); - /** passphrase-callback */ - gpgme_set_passphrase_cb(mCtx, passphraseCb, this); - - /** check if app is called with -d from command line */ - if (qApp->arguments().contains("-d")) { - qDebug() << "gpgme_data_t debug on"; - debug = true; - } else { - debug = false; - } - - connect(this, SIGNAL(signalKeyDBChanged()), - this, SLOT(slotRefreshKeyList()), Qt::DirectConnection); - connect(this, SIGNAL(signalKeyUpdated(QString)), - this, SLOT(slotUpdateKeyList(QString)), Qt::DirectConnection); - slotRefreshKeyList(); - } - -/** Destructor - * Release gpgme-context - */ - GpgContext::~GpgContext() { - if (mCtx) gpgme_release(mCtx); - mCtx = nullptr; - } - - bool GpgContext::isGood() const { - return good; - } - -/** Import Key from QByteArray - * - */ - GpgImportInformation GpgContext::importKey(QByteArray inBuffer) { - auto *importInformation = new GpgImportInformation(); - err = gpgme_data_new_from_mem(&in, inBuffer.data(), inBuffer.size(), 1); - checkErr(err); - err = gpgme_op_import(mCtx, in); - gpgme_import_result_t result; - - result = gpgme_op_import_result(mCtx); - if (result->unchanged) { - importInformation->unchanged = result->unchanged; - } - if (result->considered) { - importInformation->considered = result->considered; - } - if (result->no_user_id) { - importInformation->no_user_id = result->no_user_id; - } - if (result->imported) { - importInformation->imported = result->imported; - } - if (result->imported_rsa) { - importInformation->imported_rsa = result->imported_rsa; - } - if (result->unchanged) { - importInformation->unchanged = result->unchanged; - } - if (result->new_user_ids) { - importInformation->new_user_ids = result->new_user_ids; - } - if (result->new_sub_keys) { - importInformation->new_sub_keys = result->new_sub_keys; - } - if (result->new_signatures) { - importInformation->new_signatures = result->new_signatures; - } - if (result->new_revocations) { - importInformation->new_revocations = result->new_revocations; - } - if (result->secret_read) { - importInformation->secret_read = result->secret_read; - } - if (result->secret_imported) { - importInformation->secret_imported = result->secret_imported; - } - if (result->secret_unchanged) { - importInformation->secret_unchanged = result->secret_unchanged; - } - if (result->not_imported) { - importInformation->not_imported = result->not_imported; - } - gpgme_import_status_t status = result->imports; - while (status != nullptr) { - GpgImportedKey key; - key.importStatus = static_cast<int>(status->status); - key.fpr = status->fpr; - importInformation->importedKeys.emplace_back(key); - status = status->next; - } - checkErr(err); - emit signalKeyDBChanged(); - gpgme_data_release(in); - return *importInformation; - } - -/** Generate New Key with values params - * - */ - gpgme_error_t GpgContext::generateKey(GenKeyInfo *params) { - - auto userid_utf8 = params->getUserid().toUtf8(); - const char *userid = userid_utf8.constData(); - auto algo_utf8 = (params->getAlgo() + params->getKeySizeStr()).toUtf8(); - const char *algo = algo_utf8.constData(); - unsigned long expires = QDateTime::currentDateTime().secsTo(params->getExpired()); - unsigned int flags = 0; - - if (!params->isSubKey()) { - flags |= GPGME_CREATE_CERT; - } - - if (params->isAllowEncryption()) { - flags |= GPGME_CREATE_ENCR; - } - - if (params->isAllowSigning()) { - flags |= GPGME_CREATE_SIGN; - } - - if (params->isAllowAuthentication()) { - flags |= GPGME_CREATE_AUTH; - } - - if (params->isNonExpired()) { - flags |= GPGME_CREATE_NOEXPIRE; - } - - if (params->isNoPassPhrase()) { - flags |= GPGME_CREATE_NOPASSWD; - } - - err = gpgme_op_createkey(mCtx, userid, algo, 0, expires, nullptr, flags); - - if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) { - checkErr(err); - return err; - } else { - emit signalKeyDBChanged(); - return err; - } - } - -/** Export Key to QByteArray - * - */ - bool GpgContext::exportKeys(QStringList *uidList, QByteArray *outBuffer) { - size_t read_bytes; - gpgme_data_t dataOut = nullptr; - outBuffer->resize(0); - - if (uidList->count() == 0) { - QMessageBox::critical(nullptr, "Export Keys Error", "No Keys Selected"); - return false; - } - - for (int i = 0; i < uidList->count(); i++) { - err = gpgme_data_new(&dataOut); - checkErr(err); - - err = gpgme_op_export(mCtx, uidList->at(i).toUtf8().constData(), 0, dataOut); - checkErr(err); - - read_bytes = gpgme_data_seek(dataOut, 0, SEEK_END); - - err = readToBuffer(dataOut, outBuffer); - checkErr(err); - gpgme_data_release(dataOut); - } - return true; - } - - /** - * List all availabe Keys (VERY much like kgpgme) - */ - void GpgContext::fetch_keys() { - - gpgme_error_t gpgmeError; - - gpgme_key_t key; - - qDebug() << "Clear List and Map"; - - mKeyList.clear(); - mKeyMap.clear(); - - auto &keys = mKeyList; - auto &keys_map = mKeyMap; - - qDebug() << "Set Keylist Mode"; - - gpgmeError = gpgme_set_keylist_mode(mCtx, - GPGME_KEYLIST_MODE_LOCAL - | GPGME_KEYLIST_MODE_WITH_SECRET - | GPGME_KEYLIST_MODE_SIGS - | GPGME_KEYLIST_MODE_SIG_NOTATIONS - | GPGME_KEYLIST_MODE_WITH_TOFU); - if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) { - checkErr(gpgmeError); - return; - } - - qDebug() << "Operate KeyList Start"; - - gpgmeError = gpgme_op_keylist_start(mCtx, nullptr, 0); - if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) { - checkErr(gpgmeError); - return; - } - - qDebug() << "Start Loop"; - - while ((gpgmeError = gpgme_op_keylist_next(mCtx, &key)) == GPG_ERR_NO_ERROR) { - if (!key->subkeys) - continue; - - qDebug() << "Append Key" << key->subkeys->keyid; - - keys.emplace_back(key); - keys_map.insert(keys.back().id, &keys.back()); - gpgme_key_unref(key); - } - - - if (gpg_err_code(gpgmeError) != GPG_ERR_EOF) { - checkErr(gpgmeError); - return; - } - - qDebug() << "Operate KeyList End"; - - gpgmeError = gpgme_op_keylist_end(mCtx); - if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) { - checkErr(gpgmeError); - return; - } - - gpgmeError = gpgme_op_keylist_end(mCtx); - if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) { - checkErr(gpgmeError); - return; - } - - mKeyList = keys; - } - -/** Delete keys - */ - - void GpgContext::deleteKeys(QStringList *uidList) { - - gpgme_error_t error; - gpgme_key_t key; - - for (const auto &tmp : *uidList) { - - error = gpgme_op_keylist_start(mCtx, tmp.toUtf8().constData(), 0); - if (error != GPG_ERR_NO_ERROR) { - checkErr(error); - continue; - } - - error = gpgme_op_keylist_next(mCtx, &key); - if (error != GPG_ERR_NO_ERROR) { - checkErr(error); - continue; - } - - error = gpgme_op_keylist_end(mCtx); - if (error != GPG_ERR_NO_ERROR) { - checkErr(error); - continue; - } - - error = gpgme_op_delete(mCtx, key, 1); - if (error != GPG_ERR_NO_ERROR) { - checkErr(error); - continue; - } - - } - emit signalKeyDBChanged(); - } - -/** Encrypt inBuffer for reciepients-uids, write - * result to outBuffer - */ - gpg_error_t GpgContext::encrypt(QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer, - gpgme_encrypt_result_t *result) { - - gpgme_data_t dataIn = nullptr, dataOut = nullptr; - outBuffer->resize(0); - - //gpgme_encrypt_result_t e_result; - gpgme_key_t recipients[keys.count() + 1]; - - int index = 0; - for (const auto &key : keys) { - recipients[index++] = key.key_refer; - } - - //Last entry dataIn array has to be nullptr - recipients[keys.count()] = nullptr; - - //If the last parameter isnt 0, a private copy of data is made - if (mCtx) { - err = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1); - checkErr(err); - if (!err) { - err = gpgme_data_new(&dataOut); - checkErr(err); - if (!err) { - err = gpgme_op_encrypt(mCtx, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, dataIn, dataOut); - checkErr(err); - if (!err) { - err = readToBuffer(dataOut, outBuffer); - checkErr(err); - } - } - } - } - if (dataIn) { - gpgme_data_release(dataIn); - } - if (dataOut) { - gpgme_data_release(dataOut); - } - - if (result != nullptr) { - *result = gpgme_op_encrypt_result(mCtx); - } - return err; - } - -/** Decrypt QByteAarray, return QByteArray - * mainly from http://basket.kde.org/ (kgpgme.cpp) - */ - gpgme_error_t - GpgContext::decrypt(const QByteArray &inBuffer, QByteArray *outBuffer, gpgme_decrypt_result_t *result) { - gpgme_data_t dataIn = nullptr, dataOut = nullptr; - gpgme_decrypt_result_t m_result = nullptr; - - outBuffer->resize(0); - if (mCtx != nullptr) { - err = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1); - if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { - err = gpgme_data_new(&dataOut); - if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { - err = gpgme_op_decrypt(mCtx, dataIn, dataOut); - m_result = gpgme_op_decrypt_result(mCtx); - if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { - err = readToBuffer(dataOut, outBuffer); - } - } - } - } - - if (!settings.value("general/rememberPassword").toBool()) { - clearPasswordCache(); - } - - if (dataIn) { - gpgme_data_release(dataIn); - } - if (dataOut) { - gpgme_data_release(dataOut); - } - - if (result != nullptr) { - *result = m_result; - } - return err; - } - -/** Read gpgme-Data to QByteArray - * mainly from http://basket.kde.org/ (kgpgme.cpp) - */ -#define BUF_SIZE (32 * 1024) - - gpgme_error_t GpgContext::readToBuffer(gpgme_data_t dataIn, QByteArray *outBuffer) { - off_t ret; - gpgme_error_t gpgErrNoError = GPG_ERR_NO_ERROR; - - ret = gpgme_data_seek(dataIn, 0, SEEK_SET); - if (ret) { - gpgErrNoError = gpgme_err_code_from_errno(errno); - checkErr(gpgErrNoError, "failed dataseek dataIn readToBuffer"); - } else { - char buf[BUF_SIZE + 2]; - - while ((ret = gpgme_data_read(dataIn, buf, BUF_SIZE)) > 0) { - const size_t size = outBuffer->size(); - outBuffer->resize(static_cast<int>(size + ret)); - memcpy(outBuffer->data() + size, buf, ret); - } - if (ret < 0) { - gpgErrNoError = gpgme_err_code_from_errno(errno); - checkErr(gpgErrNoError, "failed data_read dataIn readToBuffer"); - } - } - return gpgErrNoError; - } - -/** The Passphrase window, if not provided by env-Var GPG_AGENT_INFO - * originally copied from http://basket.kde.org/ (kgpgme.cpp), but modified - */ - gpgme_error_t GpgContext::passphraseCb(void *hook, const char *uid_hint, - const char *passphrase_info, - int last_was_bad, int fd) { - auto *gpg = static_cast<GpgContext *>(hook); - return gpg->passphrase(uid_hint, passphrase_info, last_was_bad, fd); - } - - gpgme_error_t GpgContext::passphrase(const char *uid_hint, - const char * /*passphrase_info*/, - int last_was_bad, int fd) { - gpgme_error_t returnValue = GPG_ERR_CANCELED; - QString passwordDialogMessage; - QString gpgHint = QString::fromUtf8(uid_hint); - bool result; - -#ifdef _WIN32 - DWORD written; - auto hd = INT2VOIDP(fd); -#endif - - if (last_was_bad) { - passwordDialogMessage += "<i>" + tr("Wrong password") + ".</i><br><br>\n\n"; - clearPasswordCache(); - } - - /** if uid provided */ - if (!gpgHint.isEmpty()) { - // remove UID, leave only username & email - gpgHint.remove(0, gpgHint.indexOf(" ")); - passwordDialogMessage += "<b>" + tr("Enter Password for") + "</b><br>" + gpgHint + "<br>"; - } - - if (mPasswordCache.isEmpty()) { - QString password = QInputDialog::getText(QApplication::activeWindow(), tr("Enter Password"), - passwordDialogMessage, QLineEdit::Password, - "", &result); - - if (result) mPasswordCache = password.toUtf8(); - } else { - result = true; - } - - if (result) { - -#ifndef _WIN32 - if (write(fd, mPasswordCache.data(), mPasswordCache.length()) == -1) { - qDebug() << "something is terribly broken"; - } -#else - WriteFile(hd, mPasswordCache.data(), mPasswordCache.length(), &written, 0); -#endif - - returnValue = GPG_ERR_NO_ERROR; - } - -#ifndef _WIN32 - if (write(fd, "\n", 1) == -1) { - qDebug() << "something is terribly broken"; - } -#else - WriteFile(hd, "\n", 1, &written, 0); - - /* program will hang on cancel if hd not closed */ - if (!result) { - CloseHandle(hd); - } -#endif - - return returnValue; - } - -/** also from kgpgme.cpp, seems to clear password from mem */ - void GpgContext::clearPasswordCache() { - if (mPasswordCache.size() > 0) { - mPasswordCache.fill('\0'); - mPasswordCache.truncate(0); - } - } - -// error-handling - void GpgContext::checkErr(gpgme_error_t gpgmeError, const QString &comment) { - //if (gpgmeError != GPG_ERR_NO_ERROR && gpgmeError != GPG_ERR_CANCELED) { - if (gpgmeError != GPG_ERR_NO_ERROR) { - qDebug() << "[Error " << gpg_err_code(gpgmeError) - << "] Source: " << gpgme_strsource(gpgmeError) << " Description: " << gpgErrString(gpgmeError); - } - } - - void GpgContext::checkErr(gpgme_error_t gpgmeError) { - //if (gpgmeError != GPG_ERR_NO_ERROR && gpgmeError != GPG_ERR_CANCELED) { - if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) { - qDebug() << "[Error " << gpg_err_code(gpgmeError) - << "] Source: " << gpgme_strsource(gpgmeError) << " Description: " << gpgErrString(gpgmeError); - } - } - - QString GpgContext::gpgErrString(gpgme_error_t err) { - return QString::fromUtf8(gpgme_strerror(err)); - } - - bool GpgContext::exportSecretKey(const GpgKey &key, QByteArray *outBuffer) { - qDebug() << "Export Secret Key" << key.id; - gpgme_key_t target_key[2] = { - key.key_refer, - nullptr - }; - - gpgme_data_t dataOut; - gpgme_data_new(&dataOut); - // export private key to outBuffer - gpgme_error_t error = gpgme_op_export_keys(mCtx, target_key, GPGME_EXPORT_MODE_SECRET, dataOut); - - if (gpgme_err_code(error) != GPG_ERR_NO_ERROR) { - checkErr(error); - gpgme_data_release(dataOut); - return false; - } - - readToBuffer(dataOut, outBuffer); - gpgme_data_release(dataOut); - return true; - } - -/** return type should be gpgme_error_t*/ - QProcess * GpgContext::executeGpgCommand(const QStringList &arguments, QByteArray *stdOut, QByteArray *stdErr, - const std::function<void(QProcess *)> &interactFunc) { - QStringList args; - args << arguments; - - auto *gpgProcess = new QProcess(this); - qDebug() << "gpgExec" << gpgExec << args; - - gpgProcess->setReadChannel(QProcess::StandardOutput); - connect(gpgProcess, SIGNAL(finished(int,QProcess::ExitStatus)), - gpgProcess, SLOT(deleteLater())); - connect(gpgProcess, &QProcess::readyReadStandardOutput, this, [gpgProcess, interactFunc]() { - qDebug() << "Function Called" << &gpgProcess; - // interactFunc(gpgProcess); - }); - - gpgProcess->start(gpgExec, args); - - if (gpgProcess->waitForStarted()){ - qDebug() << "Gpg Process Started Success"; - } else { - qDebug() << "Gpg Process Started Failed"; - } - - return gpgProcess; - } - -/*** - * if sigbuffer not set, the inbuffer should contain signed text - * - * TODO: return type should contain: - * -> list of sigs - * -> valid - * -> errors - */ - gpgme_error_t GpgContext::verify(QByteArray *inBuffer, QByteArray *sigBuffer, gpgme_verify_result_t *result) { - - gpgme_data_t dataIn; - gpgme_error_t gpgmeError; - gpgme_signature_t sign; - gpgme_verify_result_t m_result; - - gpgmeError = gpgme_data_new_from_mem(&dataIn, inBuffer->data(), inBuffer->size(), 1); - checkErr(gpgmeError); - - if (sigBuffer != nullptr) { - gpgme_data_t sigdata; - gpgmeError = gpgme_data_new_from_mem(&sigdata, sigBuffer->data(), sigBuffer->size(), 1); - checkErr(gpgmeError); - gpgmeError = gpgme_op_verify(mCtx, sigdata, dataIn, nullptr); - } else { - gpgmeError = gpgme_op_verify(mCtx, dataIn, nullptr, dataIn); - } - - checkErr(gpgmeError); - - m_result = gpgme_op_verify_result(mCtx); - - if (result != nullptr) { - *result = m_result; - } - - return gpgmeError; - } - - gpg_error_t - GpgContext::sign(const QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer, gpgme_sig_mode_t mode, - gpgme_sign_result_t *result) { - - gpgme_error_t gpgmeError; - gpgme_data_t dataIn, dataOut; - gpgme_sign_result_t m_result; - - if (keys.isEmpty()) { - QMessageBox::critical(nullptr, tr("Key Selection"), tr("No Private Key Selected")); - return false; - } - - // at start or end? - - setSigners(keys); - - gpgmeError = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1); - checkErr(gpgmeError); - gpgmeError = gpgme_data_new(&dataOut); - checkErr(gpgmeError); - - /* - `GPGME_SIG_MODE_NORMAL' - A normal signature is made, the output includes the plaintext - and the signature. - - `GPGME_SIG_MODE_DETACH' - A detached signature is made. - - `GPGME_SIG_MODE_CLEAR' - A clear text signature is made. The ASCII armor and text - mode settings of the context are ignored. - */ - - gpgmeError = gpgme_op_sign(mCtx, dataIn, dataOut, mode); - checkErr(gpgmeError); - - if (gpgmeError == GPG_ERR_CANCELED) { - return false; - } - - if (gpgmeError != GPG_ERR_NO_ERROR) { - QMessageBox::critical(nullptr, tr("Error in signing:"), QString::fromUtf8(gpgme_strerror(gpgmeError))); - return false; - } - - m_result = gpgme_op_sign_result(mCtx); - - if (result != nullptr) { - *result = m_result; - } - - gpgmeError = readToBuffer(dataOut, outBuffer); - checkErr(gpgmeError); - - gpgme_data_release(dataIn); - gpgme_data_release(dataOut); - - if (!settings.value("general/rememberPassword").toBool()) { - clearPasswordCache(); - } - - return gpgmeError; - } - - /* - * if there is no '\n' before the PGP-Begin-Block, but for example a whitespace, - * GPGME doesn't recognise the Message as encrypted. This function adds '\n' - * before the PGP-Begin-Block, if missing. - */ - void GpgContext::preventNoDataErr(QByteArray *in) { - int block_start = in->indexOf(GpgConstants::PGP_CRYPT_BEGIN); - if (block_start > 0 && in->at(block_start - 1) != '\n') { - in->insert(block_start, '\n'); - } - block_start = in->indexOf(GpgConstants::PGP_SIGNED_BEGIN); - if (block_start > 0 && in->at(block_start - 1) != '\n') { - in->insert(block_start, '\n'); - } - } - - /* - * isSigned returns: - * - 0, if text isn't signed at all - * - 1, if text is partially signed - * - 2, if text is completly signed - */ - int GpgContext::textIsSigned(const QByteArray &text) { - if (text.trimmed().startsWith(GpgConstants::PGP_SIGNED_BEGIN) && - text.trimmed().endsWith(GpgConstants::PGP_SIGNED_END)) { - return 2; - } - if (text.contains(GpgConstants::PGP_SIGNED_BEGIN) && text.contains(GpgConstants::PGP_SIGNED_END)) { - return 1; - } - return 0; - } - - QString GpgContext::beautifyFingerprint(QString fingerprint) { - uint len = fingerprint.length(); - if ((len > 0) && (len % 4 == 0)) - for (uint n = 0; 4 * (n + 1) < len; ++n) - fingerprint.insert(static_cast<int>(5u * n + 4u), ' '); - return fingerprint; - } - - void GpgContext::slotRefreshKeyList() { - qDebug() << "Refreshing Keys"; - this->fetch_keys(); - emit signalKeyInfoChanged(); - } - -/** - * note: is_private_key status is not returned - */ - GpgKey GpgContext::getKeyByFpr(const QString &fpr) { - for (const auto &key : mKeyList) { - if (key.fpr == fpr) { - return key; - } else { - for (auto &subkey : key.subKeys) { - if (subkey.fpr == fpr) { - return key; - } - } - } - } - return GpgKey(nullptr); - } - - /** - * note: is_private_key status is not returned - */ - const GpgKey &GpgContext::getKeyById(const QString &id) { - - for (const auto &key : mKeyList) { - if (key.id == id) { - return key; - } else { - auto subkeys = key.subKeys; - for (const auto &subkey : subkeys) { - if (subkey.id == id) { - return key; - } - } - } - } - - throw std::runtime_error("key not found"); - } - - QString GpgContext::getGpgmeVersion() { - return QString(gpgme_check_version(nullptr)); - } - - bool GpgContext::signKey(const GpgKey &target, const QString &uid, const QDateTime *expires) { - - unsigned int flags = 0; - - unsigned int expires_time_t = 0; - if (expires == nullptr) { - flags |= GPGME_KEYSIGN_NOEXPIRE; - } else { - expires_time_t = QDateTime::currentDateTime().secsTo(*expires); - } - - auto gpgmeError = - gpgme_op_keysign(mCtx, target.key_refer, uid.toUtf8().constData(), expires_time_t, flags); - - if (gpgmeError == GPG_ERR_NO_ERROR) { - emit signalKeyUpdated(target.id); - return true; - } else { - checkErr(gpgmeError); - return false; - } - } - - const GpgKeyList &GpgContext::getKeys() const { - return mKeyList; - } - - void GpgContext::getSigners(QVector<GpgKey> &signer) { - auto count = gpgme_signers_count(mCtx); - signer.clear(); - for (auto i = 0; i < count; i++) { - auto key = gpgme_signers_enum(mCtx, i); - auto it = mKeyMap.find(key->subkeys->keyid); - if (it == mKeyMap.end()) { - qDebug() << "Inconsistent state"; - signer.push_back(GpgKey(key)); - } else { - signer.push_back(*it.value()); - } - } - } - - void GpgContext::setSigners(const QVector<GpgKey> &keys) { - gpgme_signers_clear(mCtx); - for (const auto &key : keys) { - if (checkIfKeyCanSign(key)) { - auto gpgmeError = gpgme_signers_add(mCtx, key.key_refer); - checkErr(gpgmeError); - } - } - if (keys.length() != gpgme_signers_count(mCtx)) { - qDebug() << "No All Keys Added"; - } - } - - void GpgContext::slotUpdateKeyList(const QString &key_id) { - auto it = mKeyMap.find(key_id); - if (it != mKeyMap.end()) { - gpgme_key_t new_key_refer; - auto gpgmeErr = gpgme_get_key(mCtx, key_id.toUtf8().constData(), &new_key_refer, 0); - - if (gpgme_err_code(gpgmeErr) == GPG_ERR_EOF) { - gpgmeErr = gpgme_get_key(mCtx, key_id.toUtf8().constData(), &new_key_refer, 1); - - if (gpgme_err_code(gpgmeErr) == GPG_ERR_EOF) { - throw std::runtime_error("key_id not found in key database"); - } - - } - - if (new_key_refer != nullptr) { - it.value()->swapKeyRefer(new_key_refer); - emit signalKeyInfoChanged(); - } - - } - } - - bool GpgContext::addUID(const GpgKey &key, const GpgUID &uid) { - QString userid = QString("%1 (%3) <%2>").arg(uid.name, uid.email, uid.comment); - auto gpgmeError = gpgme_op_adduid(mCtx, key.key_refer, userid.toUtf8().constData(), 0); - if (gpgmeError == GPG_ERR_NO_ERROR) { - emit signalKeyUpdated(key.id); - return true; - } else { - checkErr(gpgmeError); - return false; - } - - } - - bool GpgContext::revUID(const GpgKey &key, const GpgUID &uid) { - auto gpgmeError = gpgme_op_revuid(mCtx, key.key_refer, uid.uid.toUtf8().constData(), 0); - if (gpgmeError == GPG_ERR_NO_ERROR) { - emit signalKeyUpdated(key.id); - return true; - } else { - checkErr(gpgmeError); - return false; - } - } - - bool GpgContext::setPrimaryUID(const GpgKey &key, const GpgUID &uid) { - auto gpgmeError = gpgme_op_set_uid_flag(mCtx, key.key_refer, - uid.uid.toUtf8().constData(), "primary", nullptr); - if (gpgmeError == GPG_ERR_NO_ERROR) { - emit signalKeyUpdated(key.id); - return true; - } else { - checkErr(gpgmeError); - return false; - } - } - - bool GpgContext::revSign(const GpgKey &key, const GpgKeySignature &signature) { - - auto signing_key = getKeyById(signature.keyid); - - auto gpgmeError = gpgme_op_revsig(mCtx, key.key_refer, - signing_key.key_refer, - signature.uid.toUtf8().constData(), 0); - if (gpg_err_code(gpgmeError) == GPG_ERR_NO_ERROR) { - emit signalKeyUpdated(key.id); - return true; - } else { - checkErr(gpgmeError); - return false; - } - } - - gpgme_error_t GpgContext::generateSubkey(const GpgKey &key, GenKeyInfo *params) { - - if (!params->isSubKey()) { - return GPG_ERR_CANCELED; - } - - auto algo_utf8 = (params->getAlgo() + params->getKeySizeStr()).toUtf8(); - const char *algo = algo_utf8.constData(); - unsigned long expires = QDateTime::currentDateTime().secsTo(params->getExpired()); - unsigned int flags = 0; - - if (!params->isSubKey()) { - flags |= GPGME_CREATE_CERT; - } - - if (params->isAllowEncryption()) { - flags |= GPGME_CREATE_ENCR; - } - - if (params->isAllowSigning()) { - flags |= GPGME_CREATE_SIGN; - } - - if (params->isAllowAuthentication()) { - flags |= GPGME_CREATE_AUTH; - } - - if (params->isNonExpired()) { - flags |= GPGME_CREATE_NOEXPIRE; - } - - flags |= GPGME_CREATE_NOPASSWD; - - - auto gpgmeError = gpgme_op_createsubkey(mCtx, key.key_refer, - algo, 0, expires, flags); - if (gpgme_err_code(gpgmeError) == GPG_ERR_NO_ERROR) { - emit signalKeyUpdated(key.id); - return gpgmeError; - } else { - checkErr(gpgmeError); - return gpgmeError; - } - } - - bool GpgContext::setExpire(const GpgKey &key, const GpgSubKey *subkey, QDateTime *expires) { - unsigned long expires_time = 0; - if (expires != nullptr) { - qDebug() << "Expire Datetime" << expires->toString(); - expires_time = QDateTime::currentDateTime().secsTo(*expires); - } - - const char *subfprs = nullptr; - - if (subkey != nullptr) { - subfprs = subkey->fpr.toUtf8().constData(); - } - - auto gpgmeError = gpgme_op_setexpire(mCtx, key.key_refer, - expires_time, subfprs, 0); - if (gpgmeError == GPG_ERR_NO_ERROR) { - emit signalKeyUpdated(key.id); - return true; - } else { - checkErr(gpgmeError); - return false; - } - } - - bool GpgContext::checkIfKeyCanSign(const GpgKey &key) { - if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool { - return subkey.secret && subkey.can_sign && !subkey.disabled && !subkey.revoked && !subkey.expired; - })) - return true; - return false; - } - - bool GpgContext::checkIfKeyCanCert(const GpgKey &key) { - return key.has_master_key && !key.expired && !key.revoked && !key.disabled; - } - - bool GpgContext::checkIfKeyCanAuth(const GpgKey &key) { - if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool { - return subkey.secret && subkey.can_authenticate && !subkey.disabled && !subkey.revoked && !subkey.expired; - })) - return true; - return false; - } - - bool GpgContext::checkIfKeyCanEncr(const GpgKey &key) { - if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool { - return subkey.can_encrypt && !subkey.disabled && !subkey.revoked && !subkey.expired; - })) - return true; - return false; - } - - gpgme_error_t GpgContext::encryptSign(QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer, - gpgme_encrypt_result_t *encr_result, gpgme_sign_result_t *sign_result) { - gpgme_data_t dataIn = nullptr, dataOut = nullptr; - outBuffer->resize(0); - - setSigners(keys); - - //gpgme_encrypt_result_t e_result; - gpgme_key_t recipients[keys.count() + 1]; - - /* set key for user */ - int index = 0; - for (const auto &key : keys) { - recipients[index++] = key.key_refer; - } - //Last entry dataIn array has to be nullptr - recipients[keys.count()] = nullptr; - - //If the last parameter isnt 0, a private copy of data is made - if (mCtx != nullptr) { - err = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1); - if (gpg_err_code(err) == GPG_ERR_NO_ERROR) { - err = gpgme_data_new(&dataOut); - if (gpg_err_code(err) == GPG_ERR_NO_ERROR) { - err = gpgme_op_encrypt_sign(mCtx, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, dataIn, dataOut); - if (encr_result != nullptr) - *encr_result = gpgme_op_encrypt_result(mCtx); - if (sign_result != nullptr) - *sign_result = gpgme_op_sign_result(mCtx); - if (gpg_err_code(err) == GPG_ERR_NO_ERROR) { - err = readToBuffer(dataOut, outBuffer); - } - } - } - } - - if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) - checkErr(err); - - if (dataIn) { - gpgme_data_release(dataIn); - } - if (dataOut) { - gpgme_data_release(dataOut); - } - - return err; - } - - gpgme_error_t - GpgContext::decryptVerify(const QByteArray &inBuffer, QByteArray *outBuffer, gpgme_decrypt_result_t *decrypt_result, - gpgme_verify_result_t *verify_result) { - gpgme_data_t dataIn = nullptr, dataOut = nullptr; - - outBuffer->resize(0); - if (mCtx != nullptr) { - err = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1); - if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { - err = gpgme_data_new(&dataOut); - if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { - err = gpgme_op_decrypt_verify(mCtx, dataIn, dataOut); - if (decrypt_result != nullptr) - *decrypt_result = gpgme_op_decrypt_result(mCtx); - if (verify_result != nullptr) - *verify_result = gpgme_op_verify_result(mCtx); - if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { - err = readToBuffer(dataOut, outBuffer); - } - } - } - } - - if (!settings.value("general/rememberPassword").toBool()) { - clearPasswordCache(); - } - - if (dataIn) { - gpgme_data_release(dataIn); - } - if (dataOut) { - gpgme_data_release(dataOut); - } - - return err; - } - - bool GpgContext::exportKeys(const QVector<GpgKey> &keys, QByteArray &outBuffer) { - size_t read_bytes; - gpgme_data_t dataOut = nullptr; - outBuffer.resize(0); - - if (keys.count() == 0) { - QMessageBox::critical(nullptr, "Export Keys Error", "No Keys Selected"); - return false; - } - - for (const auto &key : keys) { - err = gpgme_data_new(&dataOut); - checkErr(err); - - err = gpgme_op_export(mCtx, key.id.toUtf8().constData(), 0, dataOut); - checkErr(err); - - read_bytes = gpgme_data_seek(dataOut, 0, SEEK_END); - - err = readToBuffer(dataOut, &outBuffer); - checkErr(err); - gpgme_data_release(dataOut); - } - return true; - } - - QProcess * GpgContext::generateRevokeCert(const GpgKey &key, const QString &outputFileName) { - QByteArray out, stdErr; - auto process = executeGpgCommand({ - "--command-fd", - "0", - "--status-fd", "1", - "-o", - outputFileName, - "--gen-revoke", - key.fpr - }, &out, &stdErr, - [](QProcess *proc) { - qDebug() << "Function Called" << proc; - while (proc->canReadLine()) { - const QString line = QString::fromUtf8(proc->readLine()).trimmed(); - // Command-fd is a stable interface, while this is all kind of hacky we - // are on a deadline :-/ - 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"); - } else if (line == QLatin1String("[GNUPG:] GET_LINE ask_revocation_reason.text")) { - proc->write("\n"); - } else if (line == QLatin1String("[GNUPG:] GET_BOOL openfile.overwrite.okay")) { - // We asked before - proc->write("y\n"); - } else if (line == QLatin1String("[GNUPG:] GET_BOOL ask_revocation_reason.okay")) { - proc->write("y\n"); - } - } - }); - - qDebug() << "GenerateRevokeCert Process" << process; - - return process; - } -} diff --git a/src/gpg/gpg_context/GpgContext.cpp b/src/gpg/gpg_context/GpgContext.cpp new file mode 100644 index 00000000..c8c16350 --- /dev/null +++ b/src/gpg/gpg_context/GpgContext.cpp @@ -0,0 +1,404 @@ +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "gpg/GpgContext.h" + +#include <functional> +#include <unistd.h> /* contains read/write */ + +#ifdef _WIN32 + +#include <windows.h> + +#endif + +#define INT2VOIDP(i) (void*)(uintptr_t)(i) + +namespace GpgME { + + /** Constructor + * Set up gpgme-context, set paths to app-run path + */ + GpgContext::GpgContext() { + /** get application path */ + QString appPath = qApp->applicationDirPath(); + + /** The function `gpgme_check_version' must be called before any other + * function in the library, because it initializes the thread support + * subsystem in GPGME. (from the info page) */ + gpgme_check_version(nullptr); + + // the locale set here is used for the other setlocale calls which have nullptr + // -> nullptr means use default, which is configured here + setlocale(LC_ALL, settings.value("int/lang").toLocale().name().toUtf8().constData()); + + /** set locale, because tests do also */ + gpgme_set_locale(nullptr, LC_CTYPE, setlocale(LC_CTYPE, nullptr)); + //qDebug() << "Locale set to" << LC_CTYPE << " - " << setlocale(LC_CTYPE, nullptr); +#ifndef _WIN32 + gpgme_set_locale(nullptr, LC_MESSAGES, setlocale(LC_MESSAGES, nullptr)); +#endif + + err = gpgme_new(&mCtx); + checkErr(err); + + gpgme_engine_info_t engineInfo; + engineInfo = gpgme_ctx_get_engine_info(mCtx); + +// Check ENV before running + bool check_pass = false, find_openpgp = false, find_gpgconf = false, find_assuan = false, find_cms = false; + while (engineInfo != nullptr) { + qDebug() << gpgme_get_protocol_name(engineInfo->protocol) << engineInfo->file_name << engineInfo->protocol + << engineInfo->home_dir << engineInfo->version; + if (engineInfo->protocol == GPGME_PROTOCOL_GPGCONF && strcmp(engineInfo->version, "1.0.0") != 0) + find_gpgconf = true; + if (engineInfo->protocol == GPGME_PROTOCOL_OpenPGP && strcmp(engineInfo->version, "1.0.0") != 0) { + gpgExec = engineInfo->file_name; + find_openpgp = true; + } + if (engineInfo->protocol == GPGME_PROTOCOL_CMS && strcmp(engineInfo->version, "1.0.0") != 0) + find_cms = true; + if (engineInfo->protocol == GPGME_PROTOCOL_ASSUAN) + find_assuan = true; + + engineInfo = engineInfo->next; + } + + if (find_gpgconf && find_openpgp && find_cms && find_assuan) + check_pass = true; + + if (!check_pass) { + good = false; + return; + } else good = true; + + +/** Setting the output type must be done at the beginning */ +/** think this means ascii-armor --> ? */ + gpgme_set_armor(mCtx, 1); +/** passphrase-callback */ + gpgme_set_passphrase_cb(mCtx, passphraseCb, this); + +/** check if app is called with -d from command line */ + if (qApp->arguments().contains("-d")) { + qDebug() << "gpgme_data_t debug on"; + debug = true; + } else { + debug = false; + } + + connect(this, SIGNAL(signalKeyDBChanged()), + this, SLOT(slotRefreshKeyList()), Qt::DirectConnection); + connect(this, SIGNAL(signalKeyUpdated(QString)), + this, SLOT(slotUpdateKeyList(QString)), Qt::DirectConnection); + slotRefreshKeyList(); + } + + /** Destructor + * Release gpgme-context + */ + GpgContext::~GpgContext() { + if (mCtx) gpgme_release(mCtx); + mCtx = nullptr; + } + + bool GpgContext::isGood() const { + return good; + } + + /** Read gpgme-Data to QByteArray + * mainly from http://basket.kde.org/ (kgpgme.cpp) + */ +#define BUF_SIZE (32 * 1024) + + gpgme_error_t GpgContext::readToBuffer(gpgme_data_t dataIn, QByteArray *outBuffer) { + gpgme_off_t ret; + gpgme_error_t gpgErrNoError = GPG_ERR_NO_ERROR; + + ret = gpgme_data_seek(dataIn, 0, SEEK_SET); + if (ret) { + gpgErrNoError = gpgme_err_code_from_errno(errno); + checkErr(gpgErrNoError, "failed dataseek dataIn readToBuffer"); + } else { + char buf[BUF_SIZE + 2]; + + while ((ret = gpgme_data_read(dataIn, buf, BUF_SIZE)) > 0) { + const size_t size = outBuffer->size(); + outBuffer->resize(static_cast<int>(size + ret)); + memcpy(outBuffer->data() + size, buf, ret); + } + if (ret < 0) { + gpgErrNoError = gpgme_err_code_from_errno(errno); + checkErr(gpgErrNoError, "failed data_read dataIn readToBuffer"); + } + } + return gpgErrNoError; + } + + /** + * The Passphrase window, if not provided by env-Var GPG_AGENT_INFO + * originally copied from http://basket.kde.org/ (kgpgme.cpp), but modified + */ + gpgme_error_t GpgContext::passphraseCb(void *hook, const char *uid_hint, + const char *passphrase_info, + int last_was_bad, int fd) { + auto *gpg = static_cast<GpgContext *>(hook); + return gpg->passphrase(uid_hint, passphrase_info, last_was_bad, fd); + } + + gpgme_error_t GpgContext::passphrase(const char *uid_hint, + const char * /*passphrase_info*/, + int last_was_bad, int fd) { + + gpgme_error_t returnValue = GPG_ERR_CANCELED; + QString passwordDialogMessage; + QString gpgHint = QString::fromUtf8(uid_hint); + bool result; + +#ifdef _WIN32 + DWORD written; + auto hd = INT2VOIDP(fd); +#endif + + if (last_was_bad) { + passwordDialogMessage += "<i>" + tr("Wrong password") + ".</i><br><br>\n\n"; + clearPasswordCache(); + } + + /** if uid provided */ + if (!gpgHint.isEmpty()) { + // remove UID, leave only username & email + gpgHint.remove(0, gpgHint.indexOf(" ")); + passwordDialogMessage += "<b>" + tr("Enter Password for") + "</b><br>" + gpgHint + "<br>"; + } + + if (mPasswordCache.isEmpty()) { + QString password = QInputDialog::getText(QApplication::activeWindow(), tr("Enter Password"), + passwordDialogMessage, QLineEdit::Password, + "", &result); + + if (result) mPasswordCache = password.toUtf8(); + } else result = true; + + if (result) { + +#ifndef _WIN32 + if (write(fd, mPasswordCache.data(), mPasswordCache.length()) == -1) qDebug() << "something is terribly broken"; +#else + WriteFile(hd, mPasswordCache.data(), mPasswordCache.length(), &written, 0); +#endif + returnValue = GPG_ERR_NO_ERROR; + } + +#ifndef _WIN32 + if (write(fd, "\n", 1) == -1) qDebug() << "something is terribly broken"; +#else + WriteFile(hd, "\n", 1, &written, 0); + + /* program will hang on cancel if hd not closed */ + if (!result) CloseHandle(hd); +#endif + + return returnValue; + } + + /** also from kgpgme.cpp, seems to clear password from mem */ + void GpgContext::clearPasswordCache() { + if (mPasswordCache.size() > 0) { + mPasswordCache.fill('\0'); + mPasswordCache.truncate(0); + } + } + + // error-handling + void GpgContext::checkErr(gpgme_error_t gpgmeError, const QString &comment) { + //if (gpgmeError != GPG_ERR_NO_ERROR && gpgmeError != GPG_ERR_CANCELED) { + if (gpgmeError != GPG_ERR_NO_ERROR) { + qDebug() << "[Error " << gpg_err_code(gpgmeError) + << "] Source: " << gpgme_strsource(gpgmeError) << " Description: " << gpgErrString(gpgmeError); + } + } + + void GpgContext::checkErr(gpgme_error_t gpgmeError) { + //if (gpgmeError != GPG_ERR_NO_ERROR && gpgmeError != GPG_ERR_CANCELED) { + if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) { + qDebug() << "[Error " << gpg_err_code(gpgmeError) + << "] Source: " << gpgme_strsource(gpgmeError) << " Description: " << gpgErrString(gpgmeError); + } + } + + QString GpgContext::gpgErrString(gpgme_error_t err) { + return QString::fromUtf8(gpgme_strerror(err)); + } + + /** return type should be gpgme_error_t*/ + QProcess *GpgContext::executeGpgCommand(const QStringList &arguments, QByteArray *stdOut, QByteArray *stdErr, + const std::function<void(QProcess *)> &interactFunc) { + QStringList args; + args << arguments; + + auto *gpgProcess = new QProcess(this); + qDebug() << "gpgExec" << gpgExec << args; + + gpgProcess->setReadChannel(QProcess::StandardOutput); + connect(gpgProcess, SIGNAL(finished(int, QProcess::ExitStatus)), + gpgProcess, SLOT(deleteLater())); + connect(gpgProcess, &QProcess::readyReadStandardOutput, this, [gpgProcess, interactFunc]() { + qDebug() << "Function Called" << &gpgProcess; + // interactFunc(gpgProcess); + }); + + gpgProcess->start(gpgExec, args); + + if (gpgProcess->waitForStarted()) { + qDebug() << "Gpg Process Started Success"; + } else { + qDebug() << "Gpg Process Started Failed"; + } + + return gpgProcess; + } + + + /* + * if there is no '\n' before the PGP-Begin-Block, but for example a whitespace, + * GPGME doesn't recognise the Message as encrypted. This function adds '\n' + * before the PGP-Begin-Block, if missing. + */ + void GpgContext::preventNoDataErr(QByteArray *in) { + int block_start = in->indexOf(GpgConstants::PGP_CRYPT_BEGIN); + if (block_start > 0 && in->at(block_start - 1) != '\n') { + in->insert(block_start, '\n'); + } + block_start = in->indexOf(GpgConstants::PGP_SIGNED_BEGIN); + if (block_start > 0 && in->at(block_start - 1) != '\n') { + in->insert(block_start, '\n'); + } + } + + /* + * isSigned returns: + * - 0, if text isn't signed at all + * - 1, if text is partially signed + * - 2, if text is completly signed + */ + int GpgContext::textIsSigned(const QByteArray &text) { + if (text.trimmed().startsWith(GpgConstants::PGP_SIGNED_BEGIN) && + text.trimmed().endsWith(GpgConstants::PGP_SIGNED_END)) + return 2; + else if (text.contains(GpgConstants::PGP_SIGNED_BEGIN) && text.contains(GpgConstants::PGP_SIGNED_END)) + return 1; + + else return 0; + } + + QString GpgContext::beautifyFingerprint(QString fingerprint) { + uint len = fingerprint.length(); + if ((len > 0) && (len % 4 == 0)) + for (uint n = 0; 4 * (n + 1) < len; ++n) fingerprint.insert(static_cast<int>(5u * n + 4u), ' '); + return fingerprint; + } + + void GpgContext::slotRefreshKeyList() { + qDebug() << "Refreshing Keys"; + this->fetch_keys(); + emit signalKeyInfoChanged(); + } + + QString GpgContext::getGpgmeVersion() { + return {gpgme_check_version(nullptr)}; + } + + const GpgKeyList &GpgContext::getKeys() const { + return mKeyList; + } + + void GpgContext::getSigners(QVector<GpgKey> &signer) { + auto count = gpgme_signers_count(mCtx); + signer.clear(); + for (auto i = 0; i < count; i++) { + auto key = gpgme_signers_enum(mCtx, i); + auto it = mKeyMap.find(key->subkeys->keyid); + if (it == mKeyMap.end()) { + qDebug() << "Inconsistent state"; + signer.push_back(GpgKey(key)); + } else { + signer.push_back(*it.value()); + } + } + } + + void GpgContext::setSigners(const QVector<GpgKey> &keys) { + gpgme_signers_clear(mCtx); + for (const auto &key : keys) { + if (checkIfKeyCanSign(key)) { + auto gpgmeError = gpgme_signers_add(mCtx, key.key_refer); + checkErr(gpgmeError); + } + } + if (keys.length() != gpgme_signers_count(mCtx)) { + qDebug() << "No All Keys Added"; + } + } + + void GpgContext::slotUpdateKeyList(const QString &key_id) { + auto it = mKeyMap.find(key_id); + if (it != mKeyMap.end()) { + gpgme_key_t new_key_refer; + auto gpgmeErr = gpgme_get_key(mCtx, key_id.toUtf8().constData(), &new_key_refer, 0); + + if (gpgme_err_code(gpgmeErr) == GPG_ERR_EOF) { + gpgmeErr = gpgme_get_key(mCtx, key_id.toUtf8().constData(), &new_key_refer, 1); + + if (gpgme_err_code(gpgmeErr) == GPG_ERR_EOF) { + throw std::runtime_error("key_id not found in key database"); + } + + } + + if (new_key_refer != nullptr) { + it.value()->swapKeyRefer(new_key_refer); + emit signalKeyInfoChanged(); + } + + } + } + + bool GpgContext::revSign(const GpgKey &key, const GpgKeySignature &signature) { + + auto signing_key = getKeyById(signature.keyid); + + auto gpgmeError = gpgme_op_revsig(mCtx, key.key_refer, + signing_key.key_refer, + signature.uid.toUtf8().constData(), 0); + if (gpg_err_code(gpgmeError) == GPG_ERR_NO_ERROR) { + emit signalKeyUpdated(key.id); + return true; + } else { + checkErr(gpgmeError); + return false; + } + } + +} diff --git a/src/gpg/gpg_context/GpgContextBasicOpera.cpp b/src/gpg/gpg_context/GpgContextBasicOpera.cpp new file mode 100644 index 00000000..08c9ce05 --- /dev/null +++ b/src/gpg/gpg_context/GpgContextBasicOpera.cpp @@ -0,0 +1,304 @@ +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "gpg/GpgContext.h" + +/** + * Encrypt data + * @param keys keys used + * @param inBuffer input byte array + * @param outBuffer output byte array + * @param result opera result + * @return error information + */ +gpg_error_t GpgME::GpgContext::encrypt(QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer, + gpgme_encrypt_result_t *result) { + + gpgme_data_t dataIn = nullptr, dataOut = nullptr; + outBuffer->resize(0); + + // gpgme_encrypt_result_t e_result; + gpgme_key_t recipients[keys.count() + 1]; + + int index = 0; + for (const auto &key : keys) recipients[index++] = key.key_refer; + + // Last entry dataIn array has to be nullptr + recipients[keys.count()] = nullptr; + + // If the last parameter isnt 0, a private copy of data is made + if (mCtx) { + err = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1); + checkErr(err); + if (!err) { + err = gpgme_data_new(&dataOut); + checkErr(err); + if (!err) { + err = gpgme_op_encrypt(mCtx, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, dataIn, dataOut); + checkErr(err); + if (!err) { + err = readToBuffer(dataOut, outBuffer); + checkErr(err); + } + } + } + } + if (dataIn) gpgme_data_release(dataIn); + if (dataOut) gpgme_data_release(dataOut); + + if (result != nullptr) *result = gpgme_op_encrypt_result(mCtx); + return err; +} + +/** + * Decrypt data + * @param keys keys used + * @param inBuffer input byte array + * @param outBuffer output byte array + * @param result opera result + * @return error information + */ +gpgme_error_t GpgME::GpgContext::decrypt(const QByteArray &inBuffer, QByteArray *outBuffer, + gpgme_decrypt_result_t *result) { + gpgme_data_t dataIn = nullptr, dataOut = nullptr; + gpgme_decrypt_result_t m_result = nullptr; + + outBuffer->resize(0); + if (mCtx != nullptr) { + err = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1); + if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { + err = gpgme_data_new(&dataOut); + if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { + err = gpgme_op_decrypt(mCtx, dataIn, dataOut); + m_result = gpgme_op_decrypt_result(mCtx); + if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) err = readToBuffer(dataOut, outBuffer); + } + } + } + + if (!settings.value("general/rememberPassword").toBool()) clearPasswordCache(); + + if (dataIn) gpgme_data_release(dataIn); + if (dataOut) gpgme_data_release(dataOut); + + if (result != nullptr) *result = m_result; + + return err; +} + +/** + * Verify data + * @param keys keys used + * @param inBuffer input byte array + * @param sigBuffer signature byte array (detected by format) + * @param result opera result + * @return error information + */ +gpgme_error_t GpgME::GpgContext::verify(QByteArray *inBuffer, QByteArray *sigBuffer, gpgme_verify_result_t *result) { + + gpgme_data_t dataIn; + gpgme_error_t gpgmeError; + gpgme_verify_result_t m_result; + + gpgmeError = gpgme_data_new_from_mem(&dataIn, inBuffer->data(), inBuffer->size(), 1); + checkErr(gpgmeError); + + if (sigBuffer != nullptr) { + gpgme_data_t sigdata; + gpgmeError = gpgme_data_new_from_mem(&sigdata, sigBuffer->data(), sigBuffer->size(), 1); + checkErr(gpgmeError); + gpgmeError = gpgme_op_verify(mCtx, sigdata, dataIn, nullptr); + } else { + gpgmeError = gpgme_op_verify(mCtx, dataIn, nullptr, dataIn); + } + + checkErr(gpgmeError); + + m_result = gpgme_op_verify_result(mCtx); + + if (result != nullptr) { + *result = m_result; + } + + return gpgmeError; +} + +/** + * Sign data + * @param keys keys used + * @param inBuffer input byte array + * @param outBuffer output byte array + * @param mode sign mode + * @param result opera result + * @return + */ +gpg_error_t GpgME::GpgContext::sign(const QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer, + gpgme_sig_mode_t mode, gpgme_sign_result_t *result) { + + gpgme_error_t gpgmeError; + gpgme_data_t dataIn, dataOut; + gpgme_sign_result_t m_result; + + if (keys.isEmpty()) { + QMessageBox::critical(nullptr, tr("Key Selection"), tr("No Private Key Selected")); + return false; + } + + // Set Singers of this opera + setSigners(keys); + + gpgmeError = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1); + checkErr(gpgmeError); + gpgmeError = gpgme_data_new(&dataOut); + checkErr(gpgmeError); + + /** + `GPGME_SIG_MODE_NORMAL' + A normal signature is made, the output includes the plaintext + and the signature. + + `GPGME_SIG_MODE_DETACH' + A detached signature is made. + + `GPGME_SIG_MODE_CLEAR' + A clear text signature is made. The ASCII armor and text + mode settings of the context are ignored. + */ + + gpgmeError = gpgme_op_sign(mCtx, dataIn, dataOut, mode); + checkErr(gpgmeError); + + if (gpgmeError == GPG_ERR_CANCELED) return false; + + if (gpgmeError != GPG_ERR_NO_ERROR) { + QMessageBox::critical(nullptr, tr("Error in signing:"), QString::fromUtf8(gpgme_strerror(gpgmeError))); + return false; + } + + m_result = gpgme_op_sign_result(mCtx); + + if (result != nullptr) *result = m_result; + + gpgmeError = readToBuffer(dataOut, outBuffer); + checkErr(gpgmeError); + + gpgme_data_release(dataIn); + gpgme_data_release(dataOut); + + // Of no use yet + if (!settings.value("general/rememberPassword").toBool()) clearPasswordCache(); + + return gpgmeError; +} + +/** + * Encrypt and sign data + * @param keys keys used + * @param inBuffer input byte array + * @param outBuffer output byte array + * @param encr_result encrypt opera result + * @param sign_result sign opera result + * @return + */ +gpgme_error_t GpgME::GpgContext::encryptSign(QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer, + gpgme_encrypt_result_t *encr_result, gpgme_sign_result_t *sign_result) { + gpgme_data_t data_in = nullptr, data_out = nullptr; + outBuffer->resize(0); + + setSigners(keys); + + //gpgme_encrypt_result_t e_result; + gpgme_key_t recipients[keys.count() + 1]; + + // set key for user + int index = 0; + for (const auto &key : keys) recipients[index++] = key.key_refer; + + // Last entry dataIn array has to be nullptr + recipients[keys.count()] = nullptr; + + // If the last parameter isnt 0, a private copy of data is made + if (mCtx != nullptr) { + err = gpgme_data_new_from_mem(&data_in, inBuffer.data(), inBuffer.size(), 1); + if (gpg_err_code(err) == GPG_ERR_NO_ERROR) { + err = gpgme_data_new(&data_out); + if (gpg_err_code(err) == GPG_ERR_NO_ERROR) { + err = gpgme_op_encrypt_sign(mCtx, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, data_in, data_out); + if (encr_result != nullptr) + *encr_result = gpgme_op_encrypt_result(mCtx); + if (sign_result != nullptr) + *sign_result = gpgme_op_sign_result(mCtx); + if (gpg_err_code(err) == GPG_ERR_NO_ERROR) { + err = readToBuffer(data_out, outBuffer); + } + } + } + } + + if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) checkErr(err); + + if (data_in) gpgme_data_release(data_in); + if (data_out) gpgme_data_release(data_out); + + return err; +} + +/** + * Decrypt and verify data + * @param inBuffer input byte array + * @param outBuffer output byte array + * @param decrypt_result decrypt opera result + * @param verify_result verify opera result + * @return error info + */ +gpgme_error_t GpgME::GpgContext::decryptVerify(const QByteArray &inBuffer, QByteArray *outBuffer, + gpgme_decrypt_result_t *decrypt_result, + gpgme_verify_result_t *verify_result) { + gpgme_data_t data_in = nullptr, data_out = nullptr; + + outBuffer->resize(0); + if (mCtx != nullptr) { + err = gpgme_data_new_from_mem(&data_in, inBuffer.data(), inBuffer.size(), 1); + if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { + err = gpgme_data_new(&data_out); + if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { + err = gpgme_op_decrypt_verify(mCtx, data_in, data_out); + if (decrypt_result != nullptr) + *decrypt_result = gpgme_op_decrypt_result(mCtx); + if (verify_result != nullptr) + *verify_result = gpgme_op_verify_result(mCtx); + if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { + err = readToBuffer(data_out, outBuffer); + } + } + } + } + + if (!settings.value("general/rememberPassword").toBool()) clearPasswordCache(); + + if (data_in) gpgme_data_release(data_in); + if (data_out) gpgme_data_release(data_out); + + return err; +} diff --git a/src/gpg/gpg_context/GpgContextKeyInfo.cpp b/src/gpg/gpg_context/GpgContextKeyInfo.cpp new file mode 100644 index 00000000..af57a96c --- /dev/null +++ b/src/gpg/gpg_context/GpgContextKeyInfo.cpp @@ -0,0 +1,111 @@ +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "gpg/GpgContext.h" + +/** + * check if key can sign(actually) + * @param key target key + * @return if key sign + */ +bool GpgME::GpgContext::checkIfKeyCanSign(const GpgKey &key) { + if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool { + return subkey.secret && subkey.can_sign && !subkey.disabled && !subkey.revoked && !subkey.expired; + })) + return true; + else return false; +} + +/** + * check if key can certify(actually) + * @param key target key + * @return if key certify + */ +bool GpgME::GpgContext::checkIfKeyCanCert(const GpgKey &key) { + return key.has_master_key && !key.expired && !key.revoked && !key.disabled; +} + +/** + * check if key can authenticate(actually) + * @param key target key + * @return if key authenticate + */ +bool GpgME::GpgContext::checkIfKeyCanAuth(const GpgKey &key) { + if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool { + return subkey.secret && subkey.can_authenticate && !subkey.disabled && !subkey.revoked && !subkey.expired; + })) + return true; + else return false; +} + +/** + * check if key can encrypt(actually) + * @param key target key + * @return if key encrypt + */ +bool GpgME::GpgContext::checkIfKeyCanEncr(const GpgKey &key) { + if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool { + return subkey.can_encrypt && !subkey.disabled && !subkey.revoked && !subkey.expired; + })) + return true; + else return false; +} + +/** + * Get target key + * @param fpr master key's fingerprint + * @return the key + */ +GpgKey GpgME::GpgContext::getKeyByFpr(const QString &fpr) { + for (const auto &key : mKeyList) { + if (key.fpr == fpr) return key; + else + for (auto &subkey : key.subKeys) { + if (subkey.fpr == fpr) return key; + } + } + return GpgKey(nullptr); +} + + +/** + * Get target key + * @param id master key's id + * @return the key + */ +const GpgKey &GpgME::GpgContext::getKeyById(const QString &id) { + + for (const auto &key : mKeyList) { + if (key.id == id) + return key; + else { + auto sub_keys = key.subKeys; + for (const auto &subkey : sub_keys) { + if (subkey.id == id) return key; + } + } + } + + throw std::runtime_error("key not found"); +} diff --git a/src/gpg/gpg_context/GpgContextKeyOpera.cpp b/src/gpg/gpg_context/GpgContextKeyOpera.cpp new file mode 100644 index 00000000..54123405 --- /dev/null +++ b/src/gpg/gpg_context/GpgContextKeyOpera.cpp @@ -0,0 +1,411 @@ +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "gpg/GpgContext.h" + +/** + * Import key pair + * @param inBuffer input byte array + * @return Import information + */ +GpgImportInformation GpgME::GpgContext::importKey(QByteArray inBuffer) { + auto *importInformation = new GpgImportInformation(); + err = gpgme_data_new_from_mem(&in, inBuffer.data(), inBuffer.size(), 1); + checkErr(err); + err = gpgme_op_import(mCtx, in); + gpgme_import_result_t result; + + result = gpgme_op_import_result(mCtx); + + if (result->unchanged) importInformation->unchanged = result->unchanged; + if (result->considered) importInformation->considered = result->considered; + if (result->no_user_id) importInformation->no_user_id = result->no_user_id; + if (result->imported) importInformation->imported = result->imported; + if (result->imported_rsa) importInformation->imported_rsa = result->imported_rsa; + if (result->unchanged) importInformation->unchanged = result->unchanged; + if (result->new_user_ids) importInformation->new_user_ids = result->new_user_ids; + if (result->new_sub_keys) importInformation->new_sub_keys = result->new_sub_keys; + if (result->new_signatures) importInformation->new_signatures = result->new_signatures; + if (result->new_revocations) importInformation->new_revocations = result->new_revocations; + if (result->secret_read) importInformation->secret_read = result->secret_read; + if (result->secret_imported) importInformation->secret_imported = result->secret_imported; + if (result->secret_unchanged) importInformation->secret_unchanged = result->secret_unchanged; + if (result->not_imported) importInformation->not_imported = result->not_imported; + + gpgme_import_status_t status = result->imports; + while (status != nullptr) { + GpgImportedKey key; + key.importStatus = static_cast<int>(status->status); + key.fpr = status->fpr; + importInformation->importedKeys.emplace_back(key); + status = status->next; + } + checkErr(err); + emit signalKeyDBChanged(); + gpgme_data_release(in); + return *importInformation; +} + +/** + * Generate a new key pair + * @param params key generation args + * @return error information + */ +gpgme_error_t GpgME::GpgContext::generateKey(GenKeyInfo *params) { + + auto userid_utf8 = params->getUserid().toUtf8(); + const char *userid = userid_utf8.constData(); + auto algo_utf8 = (params->getAlgo() + params->getKeySizeStr()).toUtf8(); + const char *algo = algo_utf8.constData(); + unsigned long expires = QDateTime::currentDateTime().secsTo(params->getExpired()); + unsigned int flags = 0; + + if (!params->isSubKey()) flags |= GPGME_CREATE_CERT; + if (params->isAllowEncryption()) flags |= GPGME_CREATE_ENCR; + if (params->isAllowSigning()) flags |= GPGME_CREATE_SIGN; + if (params->isAllowAuthentication()) flags |= GPGME_CREATE_AUTH; + if (params->isNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; + if (params->isNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; + + err = gpgme_op_createkey(mCtx, userid, algo, 0, expires, nullptr, flags); + + if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) { + checkErr(err); + return err; + } else { + emit signalKeyDBChanged(); + return err; + } +} + +/** + * Export Key + * @param uidList key ids + * @param outBuffer output byte array + * @return if success + */ +bool GpgME::GpgContext::exportKeys(QStringList *uidList, QByteArray *outBuffer) { + size_t read_bytes; + gpgme_data_t dataOut = nullptr; + outBuffer->resize(0); + + if (uidList->count() == 0) { + QMessageBox::critical(nullptr, "Export Keys Error", "No Keys Selected"); + return false; + } + + for (int i = 0; i < uidList->count(); i++) { + err = gpgme_data_new(&dataOut); + checkErr(err); + + err = gpgme_op_export(mCtx, uidList->at(i).toUtf8().constData(), 0, dataOut); + checkErr(err); + + read_bytes = gpgme_data_seek(dataOut, 0, SEEK_END); + + err = readToBuffer(dataOut, outBuffer); + checkErr(err); + gpgme_data_release(dataOut); + } + return true; +} + +/** + * Get and store all key pairs info + */ +void GpgME::GpgContext::fetch_keys() { + + gpgme_error_t gpgmeError; + + gpgme_key_t key; + + qDebug() << "Clear List and Map"; + + mKeyList.clear(); + mKeyMap.clear(); + + auto &keys = mKeyList; + auto &keys_map = mKeyMap; + + qDebug() << "Set Key Listing Mode"; + + gpgmeError = gpgme_set_keylist_mode(mCtx, + GPGME_KEYLIST_MODE_LOCAL + | GPGME_KEYLIST_MODE_WITH_SECRET + | GPGME_KEYLIST_MODE_SIGS + | GPGME_KEYLIST_MODE_SIG_NOTATIONS + | GPGME_KEYLIST_MODE_WITH_TOFU); + if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) { + checkErr(gpgmeError); + return; + } + + qDebug() << "Operate KeyList Start"; + + gpgmeError = gpgme_op_keylist_start(mCtx, nullptr, 0); + if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) { + checkErr(gpgmeError); + return; + } + + qDebug() << "Start Loop"; + + while ((gpgmeError = gpgme_op_keylist_next(mCtx, &key)) == GPG_ERR_NO_ERROR) { + if (!key->subkeys) + continue; + + qDebug() << "Append Key" << key->subkeys->keyid; + + keys.emplace_back(key); + keys_map.insert(keys.back().id, &keys.back()); + gpgme_key_unref(key); + } + + + if (gpg_err_code(gpgmeError) != GPG_ERR_EOF) { + checkErr(gpgmeError); + return; + } + + qDebug() << "Operate KeyList End"; + + gpgmeError = gpgme_op_keylist_end(mCtx); + if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) { + checkErr(gpgmeError); + return; + } + + gpgmeError = gpgme_op_keylist_end(mCtx); + if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) { + checkErr(gpgmeError); + return; + } + + mKeyList = keys; +} + +/** + * Delete keys + * @param uidList key ids + */ +void GpgME::GpgContext::deleteKeys(QStringList *uidList) { + + gpgme_error_t error; + gpgme_key_t key; + + for (const auto &tmp : *uidList) { + + error = gpgme_op_keylist_start(mCtx, tmp.toUtf8().constData(), 0); + if (error != GPG_ERR_NO_ERROR) { + checkErr(error); + continue; + } + + error = gpgme_op_keylist_next(mCtx, &key); + if (error != GPG_ERR_NO_ERROR) { + checkErr(error); + continue; + } + + error = gpgme_op_keylist_end(mCtx); + if (error != GPG_ERR_NO_ERROR) { + checkErr(error); + continue; + } + + error = gpgme_op_delete(mCtx, key, 1); + if (error != GPG_ERR_NO_ERROR) { + checkErr(error); + continue; + } + + } + emit signalKeyDBChanged(); +} + +/** + * Export keys + * @param keys keys used + * @param outBuffer output byte array + * @return if success + */ +bool GpgME::GpgContext::exportKeys(const QVector<GpgKey> &keys, QByteArray &outBuffer) { + size_t read_bytes; + gpgme_data_t data_out = nullptr; + outBuffer.resize(0); + + if (keys.empty()) { + QMessageBox::critical(nullptr, "Export Keys Error", "No Keys Selected"); + return false; + } + + for (const auto &key : keys) { + err = gpgme_data_new(&data_out); + checkErr(err); + + err = gpgme_op_export(mCtx, key.id.toUtf8().constData(), 0, data_out); + checkErr(err); + + read_bytes = gpgme_data_seek(data_out, 0, SEEK_END); + + err = readToBuffer(data_out, &outBuffer); + checkErr(err); + gpgme_data_release(data_out); + } + + return true; +} + +/** + * Set the expire date and time of a key pair(actually the master key) or subkey + * @param key target key pair + * @param subkey null if master key + * @param expires date and time + * @return if successful + */ +bool GpgME::GpgContext::setExpire(const GpgKey &key, const GpgSubKey *subkey, QDateTime *expires) { + unsigned long expires_time = 0; + if (expires != nullptr) { + qDebug() << "Expire Datetime" << expires->toString(); + expires_time = QDateTime::currentDateTime().secsTo(*expires); + } + + const char *subfprs = nullptr; + + if (subkey != nullptr) subfprs = subkey->fpr.toUtf8().constData(); + + auto gpgmeError = gpgme_op_setexpire(mCtx, key.key_refer, + expires_time, subfprs, 0); + if (gpgmeError == GPG_ERR_NO_ERROR) { + emit signalKeyUpdated(key.id); + return true; + } else { + checkErr(gpgmeError); + return false; + } +} + +/** + * Export the secret key of a key pair(including subkeys) + * @param key target key pair + * @param outBuffer output byte array + * @return if successful + */ +bool GpgME::GpgContext::exportSecretKey(const GpgKey &key, QByteArray *outBuffer) { + qDebug() << "Export Secret Key" << key.id; + gpgme_key_t target_key[2] = { + key.key_refer, + nullptr + }; + + gpgme_data_t dataOut; + gpgme_data_new(&dataOut); + + // export private key to outBuffer + gpgme_error_t error = gpgme_op_export_keys(mCtx, target_key, GPGME_EXPORT_MODE_SECRET, dataOut); + + if (gpgme_err_code(error) != GPG_ERR_NO_ERROR) { + checkErr(error); + gpgme_data_release(dataOut); + return false; + } + + readToBuffer(dataOut, outBuffer); + gpgme_data_release(dataOut); + return true; +} + +/** + * Sign a key pair(actually a certain uid) + * @param target target key pair + * @param uid target + * @param expires expire date and time of the signature + * @return if successful + */ +bool GpgME::GpgContext::signKey(const GpgKey &target, const QString &uid, const QDateTime *expires) { + + unsigned int flags = 0; + + unsigned int expires_time_t = 0; + if (expires == nullptr) flags |= GPGME_KEYSIGN_NOEXPIRE; + else expires_time_t = QDateTime::currentDateTime().secsTo(*expires); + + auto gpgmeError = + gpgme_op_keysign(mCtx, target.key_refer, uid.toUtf8().constData(), expires_time_t, flags); + + if (gpgmeError == GPG_ERR_NO_ERROR) { + emit signalKeyUpdated(target.id); + return true; + } else { + checkErr(gpgmeError); + return false; + } +} + +/** + * Generate revoke cert of a key pair (TODO) + * @param key target key pair + * @param outputFileName out file name(path) + * @return the process doing this job + */ +QProcess *GpgME::GpgContext::generateRevokeCert(const GpgKey &key, const QString &outputFileName) { + QByteArray out, stdErr; + auto process = executeGpgCommand({ + "--command-fd", + "0", + "--status-fd", "1", + "-o", + outputFileName, + "--gen-revoke", + key.fpr + }, &out, &stdErr, + [](QProcess *proc) { + qDebug() << "Function Called" << proc; + while (proc->canReadLine()) { + const QString line = QString::fromUtf8(proc->readLine()).trimmed(); + // Command-fd is a stable interface, while this is all kind of hacky we + // are on a deadline :-/ + 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"); + } else if (line == QLatin1String( + "[GNUPG:] GET_LINE ask_revocation_reason.text")) { + proc->write("\n"); + } else if (line == QLatin1String( + "[GNUPG:] GET_BOOL openfile.overwrite.okay")) { + // We asked before + proc->write("y\n"); + } else if (line == QLatin1String( + "[GNUPG:] GET_BOOL ask_revocation_reason.okay")) { + proc->write("y\n"); + } + } + }); + + qDebug() << "GenerateRevokeCert Process" << process; + + return process; +} diff --git a/src/gpg/gpg_context/GpgContextSubkeyOpera.cpp b/src/gpg/gpg_context/GpgContextSubkeyOpera.cpp new file mode 100644 index 00000000..10243f5e --- /dev/null +++ b/src/gpg/gpg_context/GpgContextSubkeyOpera.cpp @@ -0,0 +1,61 @@ +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "gpg/GpgContext.h" + +/** + * Generate a new subkey of a certain key pair + * @param key target key pair + * @param params opera args + * @return error info + */ +gpgme_error_t GpgME::GpgContext::generateSubkey(const GpgKey &key, GenKeyInfo *params) { + + if (!params->isSubKey()) return GPG_ERR_CANCELED; + + auto algo_utf8 = (params->getAlgo() + params->getKeySizeStr()).toUtf8(); + const char *algo = algo_utf8.constData(); + unsigned long expires = QDateTime::currentDateTime().secsTo(params->getExpired()); + unsigned int flags = 0; + + if (!params->isSubKey()) flags |= GPGME_CREATE_CERT; + if (params->isAllowEncryption()) flags |= GPGME_CREATE_ENCR; + if (params->isAllowSigning()) flags |= GPGME_CREATE_SIGN; + if (params->isAllowAuthentication()) flags |= GPGME_CREATE_AUTH; + if (params->isNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; + + flags |= GPGME_CREATE_NOPASSWD; + + + auto gpgmeError = gpgme_op_createsubkey(mCtx, key.key_refer, + algo, 0, expires, flags); + if (gpgme_err_code(gpgmeError) == GPG_ERR_NO_ERROR) { + emit signalKeyUpdated(key.id); + return gpgmeError; + } else { + checkErr(gpgmeError); + return gpgmeError; + } +} + diff --git a/src/gpg/gpg_context/GpgContextUIDOpera.cpp b/src/gpg/gpg_context/GpgContextUIDOpera.cpp new file mode 100644 index 00000000..b96f5f8f --- /dev/null +++ b/src/gpg/gpg_context/GpgContextUIDOpera.cpp @@ -0,0 +1,80 @@ +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "gpg/GpgContext.h" + +/** + * create a new uid in certain key pair + * @param key target key pair + * @param uid uid args + * @return if successful + */ +bool GpgME::GpgContext::addUID(const GpgKey &key, const GpgUID &uid) { + QString userid = QString("%1 (%3) <%2>").arg(uid.name, uid.email, uid.comment); + auto gpgmeError = gpgme_op_adduid(mCtx, key.key_refer, userid.toUtf8().constData(), 0); + if (gpgmeError == GPG_ERR_NO_ERROR) { + emit signalKeyUpdated(key.id); + return true; + } else { + checkErr(gpgmeError); + return false; + } + +} + +/** + * Revoke(Delete) UID from certain key pair + * @param key target key pair + * @param uid target uid + * @return if successful + */ +bool GpgME::GpgContext::revUID(const GpgKey &key, const GpgUID &uid) { + auto gpgmeError = gpgme_op_revuid(mCtx, key.key_refer, uid.uid.toUtf8().constData(), 0); + if (gpgmeError == GPG_ERR_NO_ERROR) { + emit signalKeyUpdated(key.id); + return true; + } else { + checkErr(gpgmeError); + return false; + } +} + +/** + * Set one of a uid of a key pair as primary + * @param key target key pair + * @param uid target uid + * @return if successful + */ +bool GpgME::GpgContext::setPrimaryUID(const GpgKey &key, const GpgUID &uid) { + auto gpgmeError = gpgme_op_set_uid_flag(mCtx, key.key_refer, + uid.uid.toUtf8().constData(), "primary", nullptr); + if (gpgmeError == GPG_ERR_NO_ERROR) { + emit signalKeyUpdated(key.id); + return true; + } else { + checkErr(gpgmeError); + return false; + } +} + diff --git a/src/gpg/result_analyse/DecryptResultAnalyse.cpp b/src/gpg/result_analyse/DecryptResultAnalyse.cpp index 7eda4027..6fab0067 100644 --- a/src/gpg/result_analyse/DecryptResultAnalyse.cpp +++ b/src/gpg/result_analyse/DecryptResultAnalyse.cpp @@ -1,6 +1,26 @@ -// -// Created by eric on 2021/6/9. -// +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ #include "gpg/result_analyse/DecryptResultAnalyse.h" diff --git a/src/gpg/result_analyse/EncryptResultAnalyse.cpp b/src/gpg/result_analyse/EncryptResultAnalyse.cpp index dfcad1ac..de12c4d8 100644 --- a/src/gpg/result_analyse/EncryptResultAnalyse.cpp +++ b/src/gpg/result_analyse/EncryptResultAnalyse.cpp @@ -1,6 +1,26 @@ -// -// Created by eric on 2021/6/9. -// +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ #include "gpg/result_analyse/EncryptResultAnalyse.h" diff --git a/src/gpg/result_analyse/ResultAnalyse.cpp b/src/gpg/result_analyse/ResultAnalyse.cpp index 960c24cd..7186d21a 100644 --- a/src/gpg/result_analyse/ResultAnalyse.cpp +++ b/src/gpg/result_analyse/ResultAnalyse.cpp @@ -1,6 +1,26 @@ -// -// Created by eric on 2021/6/8. -// +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ #include "gpg/result_analyse/ResultAnalyse.h" diff --git a/src/gpg/result_analyse/VerifyResultAnalyse.cpp b/src/gpg/result_analyse/VerifyResultAnalyse.cpp index 59c7e3ef..3b4c450b 100644 --- a/src/gpg/result_analyse/VerifyResultAnalyse.cpp +++ b/src/gpg/result_analyse/VerifyResultAnalyse.cpp @@ -1,6 +1,26 @@ -// -// Created by eric on 2021/6/7. -// +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ #include "GpgFrontend.h" #include "gpg/result_analyse/VerifyResultAnalyse.h" diff --git a/src/ui/ShowCopyDialog.cpp b/src/ui/ShowCopyDialog.cpp index 58a6cf0a..6785b0a3 100644 --- a/src/ui/ShowCopyDialog.cpp +++ b/src/ui/ShowCopyDialog.cpp @@ -1,6 +1,26 @@ -// -// Created by Administrator on 2021/7/21. -// +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ #include "ui/ShowCopyDialog.h" diff --git a/src/ui/help/VersionCheckThread.cpp b/src/ui/help/VersionCheckThread.cpp index c7c77d1c..bf1bbeda 100644 --- a/src/ui/help/VersionCheckThread.cpp +++ b/src/ui/help/VersionCheckThread.cpp @@ -1,6 +1,26 @@ -// -// Created by Administrator on 2021/7/12. -// +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ #include "ui/help/VersionCheckThread.h" #include "GpgFrontendBuildInfo.h" diff --git a/src/ui/keypair_details/EditSubKeyDialog.cpp b/src/ui/keypair_details/EditSubKeyDialog.cpp index 5e26a098..e44c987f 100644 --- a/src/ui/keypair_details/EditSubKeyDialog.cpp +++ b/src/ui/keypair_details/EditSubKeyDialog.cpp @@ -1,5 +1,25 @@ -// -// Created by eric on 2021/6/2. -// +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ #include "ui/keypair_details/EditSubKeyDialog.h" diff --git a/src/ui/main_window/MainWindowFileSlotFunction.cpp b/src/ui/main_window/MainWindowFileSlotFunction.cpp new file mode 100644 index 00000000..5e0a3e40 --- /dev/null +++ b/src/ui/main_window/MainWindowFileSlotFunction.cpp @@ -0,0 +1,610 @@ +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "MainWindow.h" + +void MainWindow::slotFileEncrypt() { + + auto fileTreeView = edit->slotCurPageFileTreeView(); + auto path = fileTreeView->getSelected(); + + QFileInfo fileInfo(path); + QFileInfo pathInfo(fileInfo.absolutePath()); + + if (!fileInfo.isFile()) { + QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it.")); + return; + } + if (!fileInfo.isReadable()) { + QMessageBox::critical(this, tr("Error"), tr("No permission to read this file.")); + return; + } + if (!pathInfo.isWritable()) { + QMessageBox::critical(this, tr("Error"), tr("No permission to create file.")); + return; + } + if (QFile::exists(path + ".asc")) { + auto ret = QMessageBox::warning(this, + tr("Warning"), + tr("The target file already exists, do you need to overwrite it?"), + QMessageBox::Ok | QMessageBox::Cancel); + + if (ret == QMessageBox::Cancel) + return; + } + + QVector<GpgKey> keys; + + mKeyList->getCheckedKeys(keys); + + if (keys.empty()) { + QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected")); + return; + } + + for (const auto &key : keys) { + if (!GpgME::GpgContext::checkIfKeyCanEncr(key)) { + QMessageBox::information(this, + tr("Invalid Operation"), + tr("The selected key contains a key that does not actually have a encrypt usage.<br/>") + + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid); + return; + + } + } + + gpgme_encrypt_result_t result; + + gpgme_error_t error; + bool if_error = false; + auto thread = QThread::create([&]() { + try { + error = GpgFileOpera::encryptFile(mCtx, keys, path, &result); + } catch (const std::runtime_error &e) { + if_error = true; + } + }); + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); + thread->start(); + + auto *dialog = new WaitingDialog(tr("Encrypting"), this); + while (thread->isRunning()) { + QApplication::processEvents(); + } + + dialog->close(); + if (!if_error) { + auto resultAnalyse = new EncryptResultAnalyse(error, result); + auto &reportText = resultAnalyse->getResultReport(); + infoBoard->associateTabWidget(edit->tabWidget); + infoBoard->associateFileTreeView(edit->curFilePage()); + + if (resultAnalyse->getStatus() < 0) + infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); + else if (resultAnalyse->getStatus() > 0) + infoBoard->slotRefresh(reportText, INFO_ERROR_OK); + else + infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); + + delete resultAnalyse; + + fileTreeView->update(); + } else { + QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); + return; + } +} + +void MainWindow::slotFileDecrypt() { + + auto fileTreeView = edit->slotCurPageFileTreeView(); + auto path = fileTreeView->getSelected(); + + QFileInfo fileInfo(path); + QFileInfo pathInfo(fileInfo.absolutePath()); + if (!fileInfo.isFile()) { + QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it.")); + return; + } + if (!fileInfo.isReadable()) { + QMessageBox::critical(this, tr("Error"), tr("No permission to read this file.")); + return; + } + if (!pathInfo.isWritable()) { + QMessageBox::critical(this, tr("Error"), tr("No permission to create file.")); + return; + } + + QString outFileName, fileExtension = fileInfo.suffix(); + + if (fileExtension == "asc" || fileExtension == "gpg") { + int pos = path.lastIndexOf(QChar('.')); + outFileName = path.left(pos); + } else { + outFileName = path + ".out"; + } + + if (QFile::exists(outFileName)) { + auto ret = QMessageBox::warning(this, + tr("Warning"), + tr("The target file already exists, do you need to overwrite it?"), + QMessageBox::Ok | QMessageBox::Cancel); + + if (ret == QMessageBox::Cancel) + return; + } + + gpgme_decrypt_result_t result; + gpgme_error_t error; + bool if_error = false; + + auto thread = QThread::create([&]() { + try { + error = GpgFileOpera::decryptFile(mCtx, path, &result); + } catch (const std::runtime_error &e) { + if_error = true; + } + }); + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); + thread->start(); + + auto *dialog = new WaitingDialog("Decrypting", this); + while (thread->isRunning()) { + QApplication::processEvents(); + } + + dialog->close(); + + if (!if_error) { + auto resultAnalyse = new DecryptResultAnalyse(mCtx, error, result); + auto &reportText = resultAnalyse->getResultReport(); + infoBoard->associateTabWidget(edit->tabWidget); + infoBoard->associateFileTreeView(edit->curFilePage()); + + if (resultAnalyse->getStatus() < 0) + infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); + else if (resultAnalyse->getStatus() > 0) + infoBoard->slotRefresh(reportText, INFO_ERROR_OK); + else + infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); + + delete resultAnalyse; + + fileTreeView->update(); + } else { + QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); + return; + } + + +} + +void MainWindow::slotFileSign() { + + auto fileTreeView = edit->slotCurPageFileTreeView(); + auto path = fileTreeView->getSelected(); + + QFileInfo fileInfo(path); + QFileInfo pathInfo(fileInfo.absolutePath()); + + if (!fileInfo.isFile()) { + QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it.")); + return; + } + if (!fileInfo.isReadable()) { + QMessageBox::critical(this, tr("Error"), tr("No permission to read this file.")); + return; + } + if (!pathInfo.isWritable()) { + QMessageBox::critical(this, tr("Error"), tr("No permission to create file.")); + return; + } + + if (QFile::exists(path + ".sig")) { + auto ret = QMessageBox::warning(this, + tr("Warning"), + tr("The target file already exists, do you need to overwrite it?"), + QMessageBox::Ok | QMessageBox::Cancel); + + if (ret == QMessageBox::Cancel) + return; + } + + QVector<GpgKey> keys; + + mKeyList->getCheckedKeys(keys); + + if (keys.empty()) { + QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected")); + return; + } + + for (const auto &key : keys) { + if (!GpgME::GpgContext::checkIfKeyCanEncr(key)) { + QMessageBox::information(this, + tr("Invalid Operation"), + tr("The selected key contains a key that does not actually have a encrypt usage.<br/>") + + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid); + return; + + } + } + + gpgme_sign_result_t result; + gpgme_error_t error; + bool if_error = false; + + auto thread = QThread::create([&]() { + try { + error = GpgFileOpera::signFile(mCtx, keys, path, &result); + } catch (const std::runtime_error &e) { + if_error = true; + } + }); + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); + thread->start(); + + auto *dialog = new WaitingDialog(tr("Signing"), this); + while (thread->isRunning()) { + QApplication::processEvents(); + } + + dialog->close(); + + if (!if_error) { + + auto resultAnalyse = new SignResultAnalyse(error, result); + auto &reportText = resultAnalyse->getResultReport(); + infoBoard->associateTabWidget(edit->tabWidget); + infoBoard->associateFileTreeView(edit->curFilePage()); + + if (resultAnalyse->getStatus() < 0) + infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); + else if (resultAnalyse->getStatus() > 0) + infoBoard->slotRefresh(reportText, INFO_ERROR_OK); + else + infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); + + delete resultAnalyse; + + fileTreeView->update(); + + } else { + QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); + return; + } + + fileTreeView->update(); + +} + +void MainWindow::slotFileVerify() { + + auto fileTreeView = edit->slotCurPageFileTreeView(); + auto path = fileTreeView->getSelected(); + + QFileInfo fileInfo(path); + + QString signFilePath, dataFilePath; + + if (fileInfo.suffix() == "gpg") { + dataFilePath = path; + signFilePath = path; + } else if (fileInfo.suffix() == "sig") { + int pos = path.lastIndexOf(QChar('.')); + dataFilePath = path.left(pos); + signFilePath = path; + } else { + dataFilePath = path; + signFilePath = path + ".sig"; + } + + QFileInfo dataFileInfo(dataFilePath), signFileInfo(signFilePath); + + if (!dataFileInfo.isFile() || !signFileInfo.isFile()) { + QMessageBox::critical(this, tr("Error"), + tr("Please select the appropriate target file or signature file. Ensure that both are in this directory.")); + return; + } + if (!dataFileInfo.isReadable()) { + QMessageBox::critical(this, tr("Error"), tr("No permission to read target file.")); + return; + } + if (!fileInfo.isReadable()) { + QMessageBox::critical(this, tr("Error"), tr("No permission to read signature file.")); + return; + } + + gpgme_verify_result_t result; + + gpgme_error_t error; + bool if_error = false; + auto thread = QThread::create([&]() { + try { + error = GpgFileOpera::verifyFile(mCtx, dataFilePath, &result); + } catch (const std::runtime_error &e) { + if_error = true; + } + }); + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); + thread->start(); + + auto *dialog = new WaitingDialog(tr("Verifying"), this); + while (thread->isRunning()) { + QApplication::processEvents(); + } + dialog->close(); + + if (!if_error) { + auto resultAnalyse = new VerifyResultAnalyse(mCtx, error, result); + auto &reportText = resultAnalyse->getResultReport(); + infoBoard->associateTabWidget(edit->tabWidget); + infoBoard->associateFileTreeView(edit->curFilePage()); + + if (resultAnalyse->getStatus() < 0) + infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); + else if (resultAnalyse->getStatus() > 0) + infoBoard->slotRefresh(reportText, INFO_ERROR_OK); + else + infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); + + if (resultAnalyse->getStatus() >= 0) { + infoBoard->resetOptionActionsMenu(); + infoBoard->addOptionalAction("Show Verify Details", [this, error, result]() { + VerifyDetailsDialog(this, mCtx, mKeyList, error, result); + }); + } + + delete resultAnalyse; + + fileTreeView->update(); + } else { + QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); + return; + } +} + +void MainWindow::slotFileEncryptSign() { + auto fileTreeView = edit->slotCurPageFileTreeView(); + auto path = fileTreeView->getSelected(); + + QFileInfo fileInfo(path); + QFileInfo pathInfo(fileInfo.absolutePath()); + + if (!fileInfo.isFile()) { + QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it.")); + return; + } + if (!fileInfo.isReadable()) { + QMessageBox::critical(this, tr("Error"), tr("No permission to read this file.")); + return; + } + if (!pathInfo.isWritable()) { + QMessageBox::critical(this, tr("Error"), tr("No permission to create file.")); + return; + } + if (QFile::exists(path + ".gpg")) { + auto ret = QMessageBox::warning(this, + tr("Warning"), + tr("The target file already exists, do you need to overwrite it?"), + QMessageBox::Ok | QMessageBox::Cancel); + + if (ret == QMessageBox::Cancel) + return; + } + + QVector<GpgKey> keys; + + mKeyList->getCheckedKeys(keys); + + if (keys.empty()) { + QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected")); + return; + } + + bool can_sign = false, can_encr = false; + + for (const auto &key : keys) { + bool key_can_sign = GpgME::GpgContext::checkIfKeyCanSign(key); + bool key_can_encr = GpgME::GpgContext::checkIfKeyCanEncr(key); + + if (!key_can_sign && !key_can_encr) { + QMessageBox::critical(nullptr, + tr("Invalid KeyPair"), + tr("The selected keypair cannot be used for signing and encryption at the same time.<br/>") + + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid); + return; + } + + if (key_can_sign) can_sign = true; + if (key_can_encr) can_encr = true; + } + + if (!can_encr) { + QMessageBox::critical(nullptr, + tr("Incomplete Operation"), + tr("None of the selected key pairs can provide the encryption function.")); + return; + } + + if (!can_sign) { + QMessageBox::warning(nullptr, + tr("Incomplete Operation"), + tr("None of the selected key pairs can provide the signature function.")); + } + + gpgme_encrypt_result_t encr_result = nullptr; + gpgme_sign_result_t sign_result = nullptr; + + gpgme_error_t error; + bool if_error = false; + + auto thread = QThread::create([&]() { + try { + error = GpgFileOpera::encryptSignFile(mCtx, keys, path, &encr_result, &sign_result); + } catch (const std::runtime_error &e) { + if_error = true; + } + }); + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); + thread->start(); + + auto *dialog = new WaitingDialog(tr("Encrypting and Signing"), this); + while (thread->isRunning()) { + QApplication::processEvents(); + } + dialog->close(); + + if (!if_error) { + + auto resultAnalyseEncr = new EncryptResultAnalyse(error, encr_result); + auto resultAnalyseSign = new SignResultAnalyse(error, sign_result); + int status = std::min(resultAnalyseEncr->getStatus(), resultAnalyseSign->getStatus()); + auto reportText = resultAnalyseEncr->getResultReport() + resultAnalyseSign->getResultReport(); + + infoBoard->associateFileTreeView(edit->curFilePage()); + + if (status < 0) + infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); + else if (status > 0) + infoBoard->slotRefresh(reportText, INFO_ERROR_OK); + else + infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); + + delete resultAnalyseEncr; + delete resultAnalyseSign; + + fileTreeView->update(); + + } else { + QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); + return; + } +} + +void MainWindow::slotFileDecryptVerify() { + auto fileTreeView = edit->slotCurPageFileTreeView(); + auto path = fileTreeView->getSelected(); + + QFileInfo fileInfo(path); + QFileInfo pathInfo(fileInfo.absolutePath()); + if (!fileInfo.isFile()) { + QMessageBox::critical(this, tr("Error"), tr("Select a file(.gpg/.asc) before doing it.")); + return; + } + if (!fileInfo.isReadable()) { + QMessageBox::critical(this, tr("Error"), tr("No permission to read this file.")); + return; + } + if (!pathInfo.isWritable()) { + QMessageBox::critical(this, tr("Error"), tr("No permission to create file.")); + return; + } + + QString outFileName, fileExtension = fileInfo.suffix(); + + if (fileExtension == "asc" || fileExtension == "gpg") { + int pos = path.lastIndexOf(QChar('.')); + outFileName = path.left(pos); + } else { + outFileName = path + ".out"; + } + + gpgme_decrypt_result_t d_result = nullptr; + gpgme_verify_result_t v_result = nullptr; + + gpgme_error_t error; + bool if_error = false; + + auto thread = QThread::create([&]() { + try { + error = GpgFileOpera::decryptVerifyFile(mCtx, path, &d_result, &v_result); + } catch (const std::runtime_error &e) { + if_error = true; + } + }); + connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); + thread->start(); + + + auto *dialog = new WaitingDialog(tr("Decrypting and Verifying"), this); + while (thread->isRunning()) { + QApplication::processEvents(); + } + dialog->close(); + + if (!if_error) { + infoBoard->associateFileTreeView(edit->curFilePage()); + + auto resultAnalyseDecrypt = new DecryptResultAnalyse(mCtx, error, d_result); + auto resultAnalyseVerify = new VerifyResultAnalyse(mCtx, error, v_result); + + int status = std::min(resultAnalyseDecrypt->getStatus(), resultAnalyseVerify->getStatus()); + auto &reportText = resultAnalyseDecrypt->getResultReport() + resultAnalyseVerify->getResultReport(); + if (status < 0) + infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); + else if (status > 0) + infoBoard->slotRefresh(reportText, INFO_ERROR_OK); + else + infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); + + if (resultAnalyseVerify->getStatus() >= 0) { + infoBoard->resetOptionActionsMenu(); + infoBoard->addOptionalAction("Show Verify Details", [this, error, v_result]() { + VerifyDetailsDialog(this, mCtx, mKeyList, error, v_result); + }); + } + delete resultAnalyseDecrypt; + delete resultAnalyseVerify; + + fileTreeView->update(); + } else { + QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); + return; + } +} + +void MainWindow::slotFileEncryptCustom() { + QStringList *keyList; + keyList = mKeyList->getChecked(); + new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Encrypt, this); +} + +void MainWindow::slotFileDecryptCustom() { + QStringList *keyList; + keyList = mKeyList->getChecked(); + new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Decrypt, this); +} + +void MainWindow::slotFileSignCustom() { + QStringList *keyList; + keyList = mKeyList->getChecked(); + new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Sign, this); +} + +void MainWindow::slotFileVerifyCustom() { + QStringList *keyList; + keyList = mKeyList->getChecked(); + new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Verify, this); +} diff --git a/src/ui/main_window/MainWindowServerSlotFunction.cpp b/src/ui/main_window/MainWindowServerSlotFunction.cpp new file mode 100644 index 00000000..c9d89fac --- /dev/null +++ b/src/ui/main_window/MainWindowServerSlotFunction.cpp @@ -0,0 +1,185 @@ +/** + * 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. + * + * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "MainWindow.h" +#include "server/ComUtils.h" +#include "ui/ShowCopyDialog.h" + +#include "rapidjson/document.h" +#include "rapidjson/prettywriter.h" + +/** + * get full size crypt text from server using short crypto text + * @param shortenCryptoText short crypto text([GpgFrontend_ShortCrypto]://) + * @return + */ +QString MainWindow::getCryptText(const QString &shortenCryptoText) { + auto host = settings.value("general/currentGpgfrontendServer", + "service.gpgfrontend.pub").toString(); + + QString ownKeyId = settings.value("general/ownKeyId").toString(); + + GpgKey key = mCtx->getKeyById(ownKeyId); + if (!key.good) { + QMessageBox::critical(this, tr("Invalid Own Key"), tr("Own Key can not be use to do any operation.")); + return {}; + } + + QString serviceToken = settings.value("general/serviceToken").toString(); + if (serviceToken.isEmpty()) { + QMessageBox::critical(this, tr("Error"), + tr("Please obtain a Service Token from the server in the settings.")); + return {}; + } + + QUrl reqUrl("http://127.0.0.1:9048/text/get"); + QNetworkRequest request(reqUrl); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + + // Sign Shorten Text + QVector keys{key}; + QByteArray outSignText; + mCtx->sign(keys, shortenCryptoText.toUtf8(), &outSignText, GPGME_SIG_MODE_NORMAL); + auto outSignTextBase64 = outSignText.toBase64(); + + rapidjson::Document doc; + doc.SetObject(); + + rapidjson::Value s, t; + + // Signature + s.SetString(outSignTextBase64.constData(), outSignTextBase64.count()); + // Service Token + const auto t_byte_array = serviceToken.toUtf8(); + t.SetString(t_byte_array.constData(), t_byte_array.count()); + + doc.AddMember("signature", s, doc.GetAllocator()); + doc.AddMember("serviceToken", t, doc.GetAllocator()); + + rapidjson::StringBuffer sb; + rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb); + doc.Accept(writer); + + QByteArray postData(sb.GetString()); + qDebug() << "postData" << QString::fromUtf8(postData); + + QNetworkReply *reply = networkAccessManager->post(request, postData); + + auto dialog = new WaitingDialog("Getting Crypt Text From Server", this); + dialog->show(); + + while (reply->isRunning()) { + QApplication::processEvents(); + } + + dialog->close(); + + QByteArray replyData = reply->readAll().constData(); + auto comUtils = new ComUtils(this); + if (comUtils->checkServerReply(replyData)) { + //TODO Logic + } else QMessageBox::critical(this, tr("Error"), tr("Unknown Error")); + + return {}; +} + +void MainWindow::shortenCryptText() { + + QString serviceToken = settings.value("general/serviceToken").toString(); + QString ownKeyId = settings.value("general/ownKeyId").toString(); + + QByteArray cryptoText = edit->curTextPage()->toPlainText().toUtf8(); + + QUrl reqUrl("http://127.0.0.1:9048/text/new"); + QNetworkRequest request(reqUrl); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + + GpgKey key = mCtx->getKeyById(ownKeyId); + if (!key.good) { + QMessageBox::critical(this, tr("Invalid Own Key"), tr("Own Key can not be use to do any operation.")); + return; + } + + QCryptographicHash ch(QCryptographicHash::Md5); + ch.addData(cryptoText); + QString md5 = ch.result().toHex(); + + qDebug() << "md5" << md5; + + QByteArray signText = QString("[%1][%2]").arg(serviceToken, md5).toUtf8(); + + QCryptographicHash sha(QCryptographicHash::Sha256); + sha.addData(signText); + QString shaText = sha.result().toHex(); + + qDebug() << "shaText" << shaText; + + QVector keys{key}; + QByteArray outSignText; + mCtx->sign(keys, signText, &outSignText, GPGME_SIG_MODE_NORMAL); + QByteArray outSignTextBase64 = outSignText.toBase64(); + + rapidjson::Value c, s, m, t; + + rapidjson::Document doc; + doc.SetObject(); + + c.SetString(cryptoText.constData(), cryptoText.count()); + auto m_byte_array = shaText.toUtf8(); + m.SetString(m_byte_array.constData(), m_byte_array.count()); + s.SetString(outSignTextBase64.constData(), outSignTextBase64.count()); + auto t_byte_array = serviceToken.toUtf8(); + t.SetString(t_byte_array.constData(), t_byte_array.count()); + + doc.AddMember("cryptoText", c, doc.GetAllocator()); + doc.AddMember("sha", m, doc.GetAllocator()); + doc.AddMember("sign", s, doc.GetAllocator()); + doc.AddMember("serviceToken", t, doc.GetAllocator()); + + rapidjson::StringBuffer sb; + rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb); + doc.Accept(writer); + + QByteArray postData(sb.GetString()); + qDebug() << "postData" << QString::fromUtf8(postData); + + QNetworkReply *reply = networkAccessManager->post(request, postData); + + while (reply->isRunning()) { + QApplication::processEvents(); + } + + if (reply->error() == QNetworkReply::NoError) { + rapidjson::Document docReply; + docReply.Parse(reply->readAll().constData()); + QString shortenText = docReply["shortenText"].GetString(); + auto *dialog = new ShowCopyDialog(shortenText, this); + dialog->show(); + } else { + QMessageBox::critical(this, tr("Error"), reply->errorString()); + } + + +} + diff --git a/src/ui/main_window/MainWindowSlotFunction.cpp b/src/ui/main_window/MainWindowSlotFunction.cpp index 736fecb5..7c35725f 100644 --- a/src/ui/main_window/MainWindowSlotFunction.cpp +++ b/src/ui/main_window/MainWindowSlotFunction.cpp @@ -23,13 +23,12 @@ */ #include "MainWindow.h" -#include "server/ComUtils.h" #include "ui/SendMailDialog.h" -#include "ui/ShowCopyDialog.h" -#include "rapidjson/document.h" -#include "rapidjson/prettywriter.h" +/** + * Encrypt Entry(Text & File) + */ void MainWindow::slotEncrypt() { if (edit->tabCount() == 0) return; @@ -462,159 +461,6 @@ void MainWindow::slotDecryptVerify() { } } -/** - * get full size crypt text from server using short crypto text - * @param shortenCryptoText short crypto text([GpgFrontend_ShortCrypto]://) - * @return - */ -QString MainWindow::getCryptText(const QString &shortenCryptoText) { - QString host = settings.value("general/currentGpgfrontendServer", - "service.gpgfrontend.pub").toString(); - - QString ownKeyId = settings.value("general/ownKeyId").toString(); - - GpgKey key = mCtx->getKeyById(ownKeyId); - if (!key.good) { - QMessageBox::critical(this, tr("Invalid Own Key"), tr("Own Key can not be use to do any operation.")); - return {}; - } - - QString serviceToken = settings.value("general/serviceToken").toString(); - if (serviceToken.isEmpty()) { - QMessageBox::critical(this, tr("Error"), - tr("Please obtain a Service Token from the server in the settings.")); - return {}; - } - - QUrl reqUrl("http://127.0.0.1:9048/text/get"); - QNetworkRequest request(reqUrl); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - - // Sign Shorten Text - QVector keys{key}; - QByteArray outSignText; - mCtx->sign(keys, shortenCryptoText.toUtf8(), &outSignText, GPGME_SIG_MODE_NORMAL); - auto outSignTextBase64 = outSignText.toBase64(); - - rapidjson::Document doc; - doc.SetObject(); - - rapidjson::Value s, t; - - // Signature - s.SetString(outSignTextBase64.constData(), outSignTextBase64.count()); - // Service Token - const auto t_byte_array = serviceToken.toUtf8(); - t.SetString(t_byte_array.constData(), t_byte_array.count()); - - doc.AddMember("signature", s, doc.GetAllocator()); - doc.AddMember("serviceToken", t, doc.GetAllocator()); - - rapidjson::StringBuffer sb; - rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb); - doc.Accept(writer); - - QByteArray postData(sb.GetString()); - qDebug() << "postData" << QString::fromUtf8(postData); - - QNetworkReply *reply = networkAccessManager->post(request, postData); - - auto dialog = new WaitingDialog("Getting Crypt Text From Server", this); - dialog->show(); - - while (reply->isRunning()) { - QApplication::processEvents(); - } - - dialog->close(); - - QByteArray replyData = reply->readAll().constData(); - auto comUtils = new ComUtils(this); - if (comUtils->checkServerReply(replyData)) { - //TODO Logic - } else QMessageBox::critical(this, tr("Error"), tr("Unknown Error")); - - return {}; -} - -void MainWindow::shortenCryptText() { - - QString serviceToken = settings.value("general/serviceToken").toString(); - QString ownKeyId = settings.value("general/ownKeyId").toString(); - - QByteArray cryptoText = edit->curTextPage()->toPlainText().toUtf8(); - - QUrl reqUrl("http://127.0.0.1:9048/text/new"); - QNetworkRequest request(reqUrl); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - - GpgKey key = mCtx->getKeyById(ownKeyId); - if (!key.good) { - QMessageBox::critical(this, tr("Invalid Own Key"), tr("Own Key can not be use to do any operation.")); - return; - } - - QCryptographicHash ch(QCryptographicHash::Md5); - ch.addData(cryptoText); - QString md5 = ch.result().toHex(); - - qDebug() << "md5" << md5; - - QByteArray signText = QString("[%1][%2]").arg(serviceToken, md5).toUtf8(); - - QCryptographicHash sha(QCryptographicHash::Sha256); - sha.addData(signText); - QString shaText = sha.result().toHex(); - - qDebug() << "shaText" << shaText; - - QVector keys{key}; - QByteArray outSignText; - mCtx->sign(keys, signText, &outSignText, GPGME_SIG_MODE_NORMAL); - QByteArray outSignTextBase64 = outSignText.toBase64(); - - rapidjson::Value c, s, m, t; - - rapidjson::Document doc; - doc.SetObject(); - - c.SetString(cryptoText.constData(), cryptoText.count()); - auto m_byte_array = shaText.toUtf8(); - m.SetString(m_byte_array.constData(), m_byte_array.count()); - s.SetString(outSignTextBase64.constData(), outSignTextBase64.count()); - auto t_byte_array = serviceToken.toUtf8(); - t.SetString(t_byte_array.constData(), t_byte_array.count()); - - doc.AddMember("cryptoText", c, doc.GetAllocator()); - doc.AddMember("sha", m, doc.GetAllocator()); - doc.AddMember("sign", s, doc.GetAllocator()); - doc.AddMember("serviceToken", t, doc.GetAllocator()); - - rapidjson::StringBuffer sb; - rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb); - doc.Accept(writer); - - QByteArray postData(sb.GetString()); - qDebug() << "postData" << QString::fromUtf8(postData); - - QNetworkReply *reply = networkAccessManager->post(request, postData); - - while (reply->isRunning()) { - QApplication::processEvents(); - } - - if (reply->error() == QNetworkReply::NoError) { - rapidjson::Document docReply; - docReply.Parse(reply->readAll().constData()); - QString shortenText = docReply["shortenText"].GetString(); - auto *dialog = new ShowCopyDialog(shortenText, this); - dialog->show(); - } else { - QMessageBox::critical(this, tr("Error"), reply->errorString()); - } - - -} /* * Append the selected (not checked!) Key(s) To Textedit @@ -668,590 +514,7 @@ void MainWindow::uploadKeyToServer() { dialog->slotUpload(); } -void MainWindow::slotFileEncrypt() { - - auto fileTreeView = edit->slotCurPageFileTreeView(); - auto path = fileTreeView->getSelected(); - - QFileInfo fileInfo(path); - QFileInfo pathInfo(fileInfo.absolutePath()); - - if (!fileInfo.isFile()) { - QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it.")); - return; - } - if (!fileInfo.isReadable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to read this file.")); - return; - } - if (!pathInfo.isWritable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to create file.")); - return; - } - if (QFile::exists(path + ".asc")) { - auto ret = QMessageBox::warning(this, - tr("Warning"), - tr("The target file already exists, do you need to overwrite it?"), - QMessageBox::Ok | QMessageBox::Cancel); - - if (ret == QMessageBox::Cancel) - return; - } - - QVector<GpgKey> keys; - - mKeyList->getCheckedKeys(keys); - - if (keys.empty()) { - QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected")); - return; - } - - for (const auto &key : keys) { - if (!GpgME::GpgContext::checkIfKeyCanEncr(key)) { - QMessageBox::information(this, - tr("Invalid Operation"), - tr("The selected key contains a key that does not actually have a encrypt usage.<br/>") - + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid); - return; - - } - } - - gpgme_encrypt_result_t result; - - gpgme_error_t error; - bool if_error = false; - auto thread = QThread::create([&]() { - try { - error = GpgFileOpera::encryptFile(mCtx, keys, path, &result); - } catch (const std::runtime_error &e) { - if_error = true; - } - }); - connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); - thread->start(); - - auto *dialog = new WaitingDialog(tr("Encrypting"), this); - while (thread->isRunning()) { - QApplication::processEvents(); - } - - dialog->close(); - if (!if_error) { - auto resultAnalyse = new EncryptResultAnalyse(error, result); - auto &reportText = resultAnalyse->getResultReport(); - infoBoard->associateTabWidget(edit->tabWidget); - infoBoard->associateFileTreeView(edit->curFilePage()); - - if (resultAnalyse->getStatus() < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (resultAnalyse->getStatus() > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); - - delete resultAnalyse; - - fileTreeView->update(); - } else { - QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); - return; - } -} - -void MainWindow::slotFileDecrypt() { - - auto fileTreeView = edit->slotCurPageFileTreeView(); - auto path = fileTreeView->getSelected(); - - QFileInfo fileInfo(path); - QFileInfo pathInfo(fileInfo.absolutePath()); - if (!fileInfo.isFile()) { - QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it.")); - return; - } - if (!fileInfo.isReadable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to read this file.")); - return; - } - if (!pathInfo.isWritable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to create file.")); - return; - } - - QString outFileName, fileExtension = fileInfo.suffix(); - - if (fileExtension == "asc" || fileExtension == "gpg") { - int pos = path.lastIndexOf(QChar('.')); - outFileName = path.left(pos); - } else { - outFileName = path + ".out"; - } - - if (QFile::exists(outFileName)) { - auto ret = QMessageBox::warning(this, - tr("Warning"), - tr("The target file already exists, do you need to overwrite it?"), - QMessageBox::Ok | QMessageBox::Cancel); - - if (ret == QMessageBox::Cancel) - return; - } - - gpgme_decrypt_result_t result; - gpgme_error_t error; - bool if_error = false; - - auto thread = QThread::create([&]() { - try { - error = GpgFileOpera::decryptFile(mCtx, path, &result); - } catch (const std::runtime_error &e) { - if_error = true; - } - }); - connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); - thread->start(); - - auto *dialog = new WaitingDialog("Decrypting", this); - while (thread->isRunning()) { - QApplication::processEvents(); - } - - dialog->close(); - - if (!if_error) { - auto resultAnalyse = new DecryptResultAnalyse(mCtx, error, result); - auto &reportText = resultAnalyse->getResultReport(); - infoBoard->associateTabWidget(edit->tabWidget); - infoBoard->associateFileTreeView(edit->curFilePage()); - - if (resultAnalyse->getStatus() < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (resultAnalyse->getStatus() > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); - - delete resultAnalyse; - - fileTreeView->update(); - } else { - QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); - return; - } - - -} - -void MainWindow::slotFileSign() { - - auto fileTreeView = edit->slotCurPageFileTreeView(); - auto path = fileTreeView->getSelected(); - - QFileInfo fileInfo(path); - QFileInfo pathInfo(fileInfo.absolutePath()); - - if (!fileInfo.isFile()) { - QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it.")); - return; - } - if (!fileInfo.isReadable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to read this file.")); - return; - } - if (!pathInfo.isWritable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to create file.")); - return; - } - - if (QFile::exists(path + ".sig")) { - auto ret = QMessageBox::warning(this, - tr("Warning"), - tr("The target file already exists, do you need to overwrite it?"), - QMessageBox::Ok | QMessageBox::Cancel); - - if (ret == QMessageBox::Cancel) - return; - } - - QVector<GpgKey> keys; - - mKeyList->getCheckedKeys(keys); - - if (keys.empty()) { - QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected")); - return; - } - - for (const auto &key : keys) { - if (!GpgME::GpgContext::checkIfKeyCanEncr(key)) { - QMessageBox::information(this, - tr("Invalid Operation"), - tr("The selected key contains a key that does not actually have a encrypt usage.<br/>") - + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid); - return; - - } - } - - gpgme_sign_result_t result; - gpgme_error_t error; - bool if_error = false; - - auto thread = QThread::create([&]() { - try { - error = GpgFileOpera::signFile(mCtx, keys, path, &result); - } catch (const std::runtime_error &e) { - if_error = true; - } - }); - connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); - thread->start(); - - auto *dialog = new WaitingDialog(tr("Signing"), this); - while (thread->isRunning()) { - QApplication::processEvents(); - } - - dialog->close(); - - if (!if_error) { - - auto resultAnalyse = new SignResultAnalyse(error, result); - auto &reportText = resultAnalyse->getResultReport(); - infoBoard->associateTabWidget(edit->tabWidget); - infoBoard->associateFileTreeView(edit->curFilePage()); - - if (resultAnalyse->getStatus() < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (resultAnalyse->getStatus() > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); - - delete resultAnalyse; - - fileTreeView->update(); - - } else { - QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); - return; - } - - fileTreeView->update(); - -} - -void MainWindow::slotFileVerify() { - - auto fileTreeView = edit->slotCurPageFileTreeView(); - auto path = fileTreeView->getSelected(); - - QFileInfo fileInfo(path); - - QString signFilePath, dataFilePath; - - if (fileInfo.suffix() == "gpg") { - dataFilePath = path; - signFilePath = path; - } else if (fileInfo.suffix() == "sig") { - int pos = path.lastIndexOf(QChar('.')); - dataFilePath = path.left(pos); - signFilePath = path; - } else { - dataFilePath = path; - signFilePath = path + ".sig"; - } - - QFileInfo dataFileInfo(dataFilePath), signFileInfo(signFilePath); - - if (!dataFileInfo.isFile() || !signFileInfo.isFile()) { - QMessageBox::critical(this, tr("Error"), - tr("Please select the appropriate target file or signature file. Ensure that both are in this directory.")); - return; - } - if (!dataFileInfo.isReadable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to read target file.")); - return; - } - if (!fileInfo.isReadable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to read signature file.")); - return; - } - - gpgme_verify_result_t result; - - gpgme_error_t error; - bool if_error = false; - auto thread = QThread::create([&]() { - try { - error = GpgFileOpera::verifyFile(mCtx, dataFilePath, &result); - } catch (const std::runtime_error &e) { - if_error = true; - } - }); - connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); - thread->start(); - - auto *dialog = new WaitingDialog(tr("Verifying"), this); - while (thread->isRunning()) { - QApplication::processEvents(); - } - dialog->close(); - - if (!if_error) { - auto resultAnalyse = new VerifyResultAnalyse(mCtx, error, result); - auto &reportText = resultAnalyse->getResultReport(); - infoBoard->associateTabWidget(edit->tabWidget); - infoBoard->associateFileTreeView(edit->curFilePage()); - - if (resultAnalyse->getStatus() < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (resultAnalyse->getStatus() > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); - - if (resultAnalyse->getStatus() >= 0) { - infoBoard->resetOptionActionsMenu(); - infoBoard->addOptionalAction("Show Verify Details", [this, error, result]() { - VerifyDetailsDialog(this, mCtx, mKeyList, error, result); - }); - } - - delete resultAnalyse; - - fileTreeView->update(); - } else { - QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); - return; - } -} - -void MainWindow::slotFileEncryptSign() { - auto fileTreeView = edit->slotCurPageFileTreeView(); - auto path = fileTreeView->getSelected(); - - QFileInfo fileInfo(path); - QFileInfo pathInfo(fileInfo.absolutePath()); - - if (!fileInfo.isFile()) { - QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it.")); - return; - } - if (!fileInfo.isReadable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to read this file.")); - return; - } - if (!pathInfo.isWritable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to create file.")); - return; - } - if (QFile::exists(path + ".gpg")) { - auto ret = QMessageBox::warning(this, - tr("Warning"), - tr("The target file already exists, do you need to overwrite it?"), - QMessageBox::Ok | QMessageBox::Cancel); - - if (ret == QMessageBox::Cancel) - return; - } - - QVector<GpgKey> keys; - - mKeyList->getCheckedKeys(keys); - - if (keys.empty()) { - QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected")); - return; - } - - bool can_sign = false, can_encr = false; - - for (const auto &key : keys) { - bool key_can_sign = GpgME::GpgContext::checkIfKeyCanSign(key); - bool key_can_encr = GpgME::GpgContext::checkIfKeyCanEncr(key); - - if (!key_can_sign && !key_can_encr) { - QMessageBox::critical(nullptr, - tr("Invalid KeyPair"), - tr("The selected keypair cannot be used for signing and encryption at the same time.<br/>") - + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid); - return; - } - - if (key_can_sign) can_sign = true; - if (key_can_encr) can_encr = true; - } - - if (!can_encr) { - QMessageBox::critical(nullptr, - tr("Incomplete Operation"), - tr("None of the selected key pairs can provide the encryption function.")); - return; - } - - if (!can_sign) { - QMessageBox::warning(nullptr, - tr("Incomplete Operation"), - tr("None of the selected key pairs can provide the signature function.")); - } - - gpgme_encrypt_result_t encr_result = nullptr; - gpgme_sign_result_t sign_result = nullptr; - - gpgme_error_t error; - bool if_error = false; - - auto thread = QThread::create([&]() { - try { - error = GpgFileOpera::encryptSignFile(mCtx, keys, path, &encr_result, &sign_result); - } catch (const std::runtime_error &e) { - if_error = true; - } - }); - connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); - thread->start(); - - WaitingDialog *dialog = new WaitingDialog(tr("Encrypting and Signing"), this); - while (thread->isRunning()) { - QApplication::processEvents(); - } - dialog->close(); - - if (!if_error) { - - auto resultAnalyseEncr = new EncryptResultAnalyse(error, encr_result); - auto resultAnalyseSign = new SignResultAnalyse(error, sign_result); - int status = std::min(resultAnalyseEncr->getStatus(), resultAnalyseSign->getStatus()); - auto reportText = resultAnalyseEncr->getResultReport() + resultAnalyseSign->getResultReport(); - - infoBoard->associateFileTreeView(edit->curFilePage()); - - if (status < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (status > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); - - delete resultAnalyseEncr; - delete resultAnalyseSign; - - fileTreeView->update(); - - } else { - QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); - return; - } -} - -void MainWindow::slotFileDecryptVerify() { - auto fileTreeView = edit->slotCurPageFileTreeView(); - auto path = fileTreeView->getSelected(); - - QFileInfo fileInfo(path); - QFileInfo pathInfo(fileInfo.absolutePath()); - if (!fileInfo.isFile()) { - QMessageBox::critical(this, tr("Error"), tr("Select a file(.gpg/.asc) before doing it.")); - return; - } - if (!fileInfo.isReadable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to read this file.")); - return; - } - if (!pathInfo.isWritable()) { - QMessageBox::critical(this, tr("Error"), tr("No permission to create file.")); - return; - } - - QString outFileName, fileExtension = fileInfo.suffix(); - if (fileExtension == "asc" || fileExtension == "gpg") { - int pos = path.lastIndexOf(QChar('.')); - outFileName = path.left(pos); - } else { - outFileName = path + ".out"; - } - - gpgme_decrypt_result_t d_result = nullptr; - gpgme_verify_result_t v_result = nullptr; - - gpgme_error_t error; - bool if_error = false; - - auto thread = QThread::create([&]() { - try { - error = GpgFileOpera::decryptVerifyFile(mCtx, path, &d_result, &v_result); - } catch (const std::runtime_error &e) { - if_error = true; - } - }); - connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater())); - thread->start(); - - - auto *dialog = new WaitingDialog(tr("Decrypting and Verifying"), this); - while (thread->isRunning()) { - QApplication::processEvents(); - } - dialog->close(); - - if (!if_error) { - infoBoard->associateFileTreeView(edit->curFilePage()); - - auto resultAnalyseDecrypt = new DecryptResultAnalyse(mCtx, error, d_result); - auto resultAnalyseVerify = new VerifyResultAnalyse(mCtx, error, v_result); - - int status = std::min(resultAnalyseDecrypt->getStatus(), resultAnalyseVerify->getStatus()); - auto &reportText = resultAnalyseDecrypt->getResultReport() + resultAnalyseVerify->getResultReport(); - if (status < 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL); - else if (status > 0) - infoBoard->slotRefresh(reportText, INFO_ERROR_OK); - else - infoBoard->slotRefresh(reportText, INFO_ERROR_WARN); - - if (resultAnalyseVerify->getStatus() >= 0) { - infoBoard->resetOptionActionsMenu(); - infoBoard->addOptionalAction("Show Verify Details", [this, error, v_result]() { - VerifyDetailsDialog(this, mCtx, mKeyList, error, v_result); - }); - } - delete resultAnalyseDecrypt; - delete resultAnalyseVerify; - - fileTreeView->update(); - } else { - QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation.")); - return; - } -} - -void MainWindow::slotFileEncryptCustom() { - QStringList *keyList; - keyList = mKeyList->getChecked(); - new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Encrypt, this); -} - -void MainWindow::slotFileDecryptCustom() { - QStringList *keyList; - keyList = mKeyList->getChecked(); - new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Decrypt, this); -} - -void MainWindow::slotFileSignCustom() { - QStringList *keyList; - keyList = mKeyList->getChecked(); - new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Sign, this); -} - -void MainWindow::slotFileVerifyCustom() { - QStringList *keyList; - keyList = mKeyList->getChecked(); - new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Verify, this); -} void MainWindow::slotOpenFile(QString &path) { edit->slotOpenFile(path); |