/** * 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 . * * 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 starting on May 12, 2021. * */ #include "MainWindow.h" #ifdef ADVANCE_SUPPORT #include "advance/UnknownSignersChecker.h" #endif #ifdef SERVER_SUPPORT #include "server/api/PubkeyUploader.h" #endif #include "ui/SendMailDialog.h" #include "ui/widgets/SignersPicker.h" namespace GpgFrontend::UI { /** * Encrypt Entry(Text & File) */ void MainWindow::slotEncrypt() { if (edit->tabCount() == 0) return; if (edit->slotCurPageTextEdit() != nullptr) { auto keys = mKeyList->getChecked(keys); if (keys.count() == 0) { QMessageBox::critical(nullptr, tr("No Key Selected"), tr("No Key Selected")); return; } for (const auto& key : keys) { if (!GpgFrontend::GpgContext::checkIfKeyCanEncr(key)) { QMessageBox::information( nullptr, tr("Invalid Operation"), tr("The selected key contains a key that does not actually have a " "encrypt usage.
") + tr("
For example the Following Key:
") + key.uids.first().uid); return; } } auto tmp = QByteArray(); gpgme_encrypt_result_t result = nullptr; gpgme_error_t error; auto thread = QThread::create([&]() { error = mCtx->encrypt(keys, edit->curTextPage()->toPlainText().toUtf8(), &tmp, &result); }); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start(); auto* dialog = new WaitingDialog(tr("Encrypting"), this); while (thread->isRunning()) QApplication::processEvents(); dialog->close(); auto resultAnalyse = new EncryptResultAnalyse(error, result); auto& reportText = resultAnalyse->getResultReport(); auto tmp2 = QString(tmp); edit->slotFillTextEditWithText(tmp2); infoBoard->associateTextEdit(edit->curTextPage()); // check result analyse status 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); // set optional actions if (resultAnalyse->getStatus() >= 0) { infoBoard->resetOptionActionsMenu(); infoBoard->addOptionalAction("Send Mail", [this]() { if (settings.value("sendMail/enable", false).toBool()) new SendMailDialog(edit->curTextPage()->toPlainText(), this); else { QMessageBox::warning(nullptr, tr("Function Disabled"), tr("Please go to the settings interface to " "enable and configure this function.")); } }); } delete resultAnalyse; } else if (edit->slotCurPageFileTreeView() != nullptr) { this->slotFileEncrypt(); } } void MainWindow::slotSign() { if (edit->tabCount() == 0) return; if (edit->slotCurPageTextEdit() != nullptr) { QVector keys; mKeyList->getPrivateCheckedKeys(keys); if (keys.isEmpty()) { QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected")); return; } for (const auto& key : keys) { if (!GpgFrontend::GpgContext::checkIfKeyCanSign(key)) { QMessageBox::information( this, tr("Invalid Operation"), tr("The selected key contains a key that does not actually have a " "signature usage.
") + tr("
For example the Following Key:
") + key.uids.first().uid); return; } } auto tmp = QByteArray(); gpgme_sign_result_t result = nullptr; gpgme_error_t error; auto thread = QThread::create([&]() { error = mCtx->sign(keys, edit->curTextPage()->toPlainText().toUtf8(), &tmp, GPGME_SIG_MODE_CLEAR, &result); }); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start(); auto* dialog = new WaitingDialog(tr("Signing"), this); while (thread->isRunning()) { QApplication::processEvents(); } dialog->close(); infoBoard->associateTextEdit(edit->curTextPage()); edit->slotFillTextEditWithText(QString::fromUtf8(tmp)); auto resultAnalyse = new SignResultAnalyse(mCtx, error, result); auto& reportText = resultAnalyse->getResultReport(); 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; } else if (edit->slotCurPageFileTreeView() != nullptr) { this->slotFileSign(); } } void MainWindow::slotDecrypt() { if (edit->tabCount() == 0) return; if (edit->slotCurPageTextEdit() != nullptr) { auto decrypted = QByteArray(); QByteArray text = edit->curTextPage()->toPlainText().toUtf8(); GpgFrontend::GpgContext::preventNoDataErr(&text); if (text.trimmed().startsWith( GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) { QMessageBox::critical( this, tr("Notice"), tr("Short Crypto Text only supports Decrypt & Verify.")); return; } gpgme_decrypt_result_t result = nullptr; gpgme_error_t error; auto thread = QThread::create([&]() { // try decrypt, if fail do nothing, especially don't replace text error = mCtx->decrypt(text, &decrypted, &result); }); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start(); auto* dialog = new WaitingDialog(tr("Decrypting"), this); while (thread->isRunning()) { QApplication::processEvents(); } dialog->close(); infoBoard->associateTextEdit(edit->curTextPage()); if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) edit->slotFillTextEditWithText(QString::fromUtf8(decrypted)); auto resultAnalyse = new DecryptResultAnalyse(mCtx, error, result); auto& reportText = resultAnalyse->getResultReport(); 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; } else if (edit->slotCurPageFileTreeView() != nullptr) { this->slotFileDecrypt(); } } void MainWindow::slotFind() { if (edit->tabCount() == 0 || edit->curTextPage() == nullptr) { return; } // At first close verifynotification, if existing edit->slotCurPageTextEdit()->closeNoteByClass("findwidget"); auto* fw = new FindWidget(this, edit->curTextPage()); edit->slotCurPageTextEdit()->showNotificationWidget(fw, "findWidget"); } void MainWindow::slotVerify() { if (edit->tabCount() == 0) return; if (edit->slotCurPageTextEdit() != nullptr) { QByteArray text = edit->curTextPage()->toPlainText().toUtf8(); GpgFrontend::GpgContext::preventNoDataErr(&text); gpgme_verify_result_t result; gpgme_error_t error; auto thread = QThread::create( [&]() { error = mCtx->verify(&text, nullptr, &result); }); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start(); auto* dialog = new WaitingDialog(tr("Verifying"), this); while (thread->isRunning()) QApplication::processEvents(); dialog->close(); auto resultAnalyse = new VerifyResultAnalyse(mCtx, error, result); infoBoard->associateTextEdit(edit->curTextPage()); auto& reportText = resultAnalyse->getResultReport(); 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; } else if (edit->slotCurPageFileTreeView() != nullptr) { this->slotFileVerify(); } } void MainWindow::slotEncryptSign() { if (edit->tabCount() == 0) return; if (edit->slotCurPageTextEdit() != nullptr) { QVector keys; mKeyList->getCheckedKeys(keys); if (keys.empty()) { QMessageBox::critical(nullptr, tr("No Key Selected"), tr("No Key Selected")); return; } for (const auto& key : keys) { bool key_can_encr = GpgFrontend::GpgContext::checkIfKeyCanEncr(key); if (!key_can_encr) { QMessageBox::critical( nullptr, tr("Invalid KeyPair"), tr("The selected keypair cannot be used for encryption.
") + tr("
For example the Following Key:
") + key.uids.first().uid); return; } } QVector signerKeys; auto signersPicker = new SignersPicker(mCtx, this); QEventLoop loop; connect(signersPicker, SIGNAL(finished(int)), &loop, SLOT(quit())); loop.exec(); signersPicker->getCheckedSigners(signerKeys); for (const auto& key : keys) { qDebug() << "Keys " << key.email; } for (const auto& signer : signerKeys) { qDebug() << "Signers " << signer.email; } auto tmp = QByteArray(); gpgme_encrypt_result_t encr_result = nullptr; gpgme_sign_result_t sign_result = nullptr; gpgme_error_t error; auto thread = QThread::create([&]() { error = mCtx->encryptSign(keys, signerKeys, edit->curTextPage()->toPlainText().toUtf8(), &tmp, &encr_result, &sign_result); }); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start(); auto* dialog = new WaitingDialog(tr("Encrypting and Signing"), this); while (thread->isRunning()) { QApplication::processEvents(); } if (settings.value("advanced/autoPubkeyExchange").toBool()) { PubkeyUploader pubkeyUploader(mCtx, signerKeys); pubkeyUploader.start(); if (!pubkeyUploader.result()) { QMessageBox::warning(nullptr, tr("Automatic Key Exchange Warning"), tr("Part of the automatic key exchange failed, " "which may be related to your key.") + tr("If possible, try to use the RSA algorithm " "compatible with the server for signing.")); } } dialog->close(); if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) { auto tmp2 = QString(tmp); edit->slotFillTextEditWithText(tmp2); } qDebug() << "Start Analyse Result"; auto resultAnalyseEncr = new EncryptResultAnalyse(error, encr_result); auto resultAnalyseSign = new SignResultAnalyse(mCtx, error, sign_result); int status = std::min(resultAnalyseEncr->getStatus(), resultAnalyseSign->getStatus()); auto reportText = resultAnalyseEncr->getResultReport() + resultAnalyseSign->getResultReport(); infoBoard->associateTextEdit(edit->curTextPage()); 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); qDebug() << "End Analyse Result"; if (status >= 0) { infoBoard->resetOptionActionsMenu(); infoBoard->addOptionalAction("Send Mail", [this]() { if (settings.value("sendMail/enable", false).toBool()) new SendMailDialog(edit->curTextPage()->toPlainText(), this); else { QMessageBox::warning(nullptr, tr("Function Disabled"), tr("Please go to the settings interface to " "enable and configure this function.")); } }); infoBoard->addOptionalAction("Shorten Ciphertext", [this]() { if (settings.value("general/serviceToken").toString().isEmpty()) QMessageBox::warning(nullptr, tr("Service Token Empty"), tr("Please go to the settings interface to set " "Own Key and get Service Token.")); else { shortenCryptText(); } }); } delete resultAnalyseEncr; delete resultAnalyseSign; } else if (edit->slotCurPageFileTreeView() != nullptr) { this->slotFileEncryptSign(); } } void MainWindow::slotDecryptVerify() { if (edit->tabCount() == 0) return; if (edit->slotCurPageTextEdit() != nullptr) { auto decrypted = QByteArray(); QString plainText = edit->curTextPage()->toPlainText(); if (plainText.trimmed().startsWith( GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) { auto cryptoText = getCryptText(plainText); if (!cryptoText.isEmpty()) { plainText = cryptoText; } } QByteArray text = plainText.toUtf8(); GpgFrontend::GpgContext::preventNoDataErr(&text); gpgme_decrypt_result_t d_result = nullptr; gpgme_verify_result_t v_result = nullptr; auto* dialog = new WaitingDialog(tr("Decrypting and Verifying"), this); // Automatically import public keys that are not stored locally if (settings.value("advanced/autoPubkeyExchange").toBool()) { gpgme_verify_result_t tmp_v_result = nullptr; auto thread = QThread::create( [&]() { mCtx->verify(&text, nullptr, &tmp_v_result); }); thread->start(); while (thread->isRunning()) QApplication::processEvents(); auto* checker = new UnknownSignersChecker(mCtx, tmp_v_result); checker->start(); checker->deleteLater(); } gpgme_error_t error; auto thread = QThread::create([&]() { error = mCtx->decryptVerify(text, &decrypted, &d_result, &v_result); }); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start(); while (thread->isRunning()) QApplication::processEvents(); dialog->close(); qDebug() << "Start Analyse Result"; infoBoard->associateTextEdit(edit->curTextPage()); if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) edit->slotFillTextEditWithText(QString::fromUtf8(decrypted)); 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; qDebug() << "End Analyse Result"; } else if (edit->slotCurPageFileTreeView() != nullptr) { this->slotFileDecryptVerify(); } } /* * Append the selected (not checked!) Key(s) To Textedit */ void MainWindow::slotAppendSelectedKeys() { if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) { return; } auto* keyArray = new QByteArray(); mCtx->exportKeys(mKeyList->getSelected(), keyArray); edit->curTextPage()->append(*keyArray); } void MainWindow::slotCopyMailAddressToClipboard() { if (mKeyList->getSelected()->isEmpty()) { return; } auto key = mCtx->getKeyRefById(mKeyList->getSelected()->first()); if (!key.good) { QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found.")); return; } QClipboard* cb = QApplication::clipboard(); QString mail = key.email; cb->setText(mail); } void MainWindow::slotShowKeyDetails() { if (mKeyList->getSelected()->isEmpty()) { return; } auto key = mCtx->getKeyRefById(mKeyList->getSelected()->first()); if (key.good) { new KeyDetailsDialog(mCtx, key, this); } else { QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found.")); } } void MainWindow::refreshKeysFromKeyserver() { if (mKeyList->getSelected()->isEmpty()) { return; } auto* dialog = new KeyServerImportDialog(mCtx, mKeyList, true, this); dialog->show(); dialog->slotImport(*mKeyList->getSelected()); } void MainWindow::uploadKeyToServer() { QVector keys; keys.append(mKeyList->getSelectedKey()); auto* dialog = new KeyUploadDialog(mCtx, keys, this); dialog->show(); dialog->slotUpload(); } void MainWindow::slotOpenFile(QString& path) { edit->slotOpenFile(path); } void MainWindow::slotVersionUpgrade(const QString& currentVersion, const QString& latestVersion) { if (currentVersion < latestVersion) { QMessageBox::warning(this, tr("Outdated Version"), tr("This version(%1) is out of date, please update " "the latest version in time. ") .arg(currentVersion) + tr("You can download the latest version(%1) on " "Github Releases Page.
") .arg(latestVersion)); } else if (currentVersion > latestVersion) { QMessageBox::warning( this, tr("Unreleased Version"), tr("This version(%1) has not been officially released and is not " "recommended for use in a production environment.
") .arg(currentVersion) + tr("You can download the latest version(%1) on Github Releases " "Page.
") .arg(latestVersion)); } } } // namespace GpgFrontend::UI