/** * 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" #include "gpg/function/GpgFileOpera.h" #include "gpg/function/GpgKeyGetter.h" #include "ui/UserInterfaceUtils.h" #include "ui/settings/GlobalSettingStation.h" #include "ui/widgets/SignersPicker.h" namespace GpgFrontend::UI { bool file_pre_check(QWidget* parent, const QString& path) { QFileInfo file_info(path); QFileInfo path_info(file_info.absolutePath()); if (!file_info.isFile()) { QMessageBox::critical(parent, _("Error"), _("Select a file before doing it.")); return false; } if (!file_info.isReadable()) { QMessageBox::critical(parent, _("Error"), _("No permission to read this file.")); return false; } if (!path_info.isWritable()) { QMessageBox::critical(parent, _("Error"), _("No permission to create file.")); return false; } return true; } void MainWindow::slotFileEncrypt() { auto fileTreeView = edit->slotCurPageFileTreeView(); auto path = fileTreeView->getSelected(); if (!file_pre_check(this, path)) return; // check selected keys auto key_ids = mKeyList->getChecked(); GpgEncrResult result = nullptr; GpgError error; bool if_error = false; // Detect ascii mode auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); bool non_ascii_when_export = true; try { non_ascii_when_export = settings.lookup("general.non_ascii_when_export"); } catch (...) { LOG(ERROR) << _("Setting Operation Error") << _("non_ascii_when_export"); } auto _channel = GPGFRONTEND_DEFAULT_CHANNEL; auto _extension = ".asc"; if (non_ascii_when_export) { _channel = GPGFRONTEND_NON_ASCII_CHANNEL; _extension = ".gpg"; } auto out_path = path + _extension; if (QFile::exists(out_path)) { boost::filesystem::path _out_path = out_path.toStdString(); auto out_file_name = boost::format(_("The target file %1% already exists, " "do you need to overwrite it?")) % _out_path.filename(); auto ret = QMessageBox::warning(this, _("Warning"), out_file_name.str().c_str(), QMessageBox::Ok | QMessageBox::Cancel); if (ret == QMessageBox::Cancel) return; } if (key_ids->empty()) { // Symmetric Encrypt auto ret = QMessageBox::information( this, _("Symmetric Encryption"), _("No Key Selected. Do you want to encrypt with a " "symmetric cipher using a passphrase?"), QMessageBox::Ok | QMessageBox::Cancel); if (ret == QMessageBox::Cancel) return; process_operation(this, _("Symmetrically Encrypting"), [&]() { try { error = GpgFrontend::GpgFileOpera::EncryptFileSymmetric( path.toStdString(), out_path.toStdString(), result, _channel); } catch (const std::runtime_error& e) { if_error = true; } }); } else { auto p_keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); // check key abilities for (const auto& key : *p_keys) { bool key_can_encrypt = key.CanEncrActual(); if (!key_can_encrypt) { QMessageBox::critical( nullptr, _("Invalid KeyPair"), QString(_("The selected keypair cannot be used for encryption.")) + "

" + _("For example the Following Key:") + "
" + QString::fromStdString(key.uids()->front().uid())); return; } } process_operation(this, _("Encrypting"), [&]() { try { error = GpgFileOpera::EncryptFile(std::move(p_keys), path.toStdString(), out_path.toStdString(), result, _channel); } catch (const std::runtime_error& e) { if_error = true; } }); } if (!if_error) { auto resultAnalyse = EncryptResultAnalyse(error, std::move(result)); resultAnalyse.analyse(); process_result_analyse(edit, infoBoard, resultAnalyse); fileTreeView->update(); } else { QMessageBox::critical(this, _("Error"), _("An error occurred during operation.")); return; } } void MainWindow::slotFileDecrypt() { auto fileTreeView = edit->slotCurPageFileTreeView(); auto path = fileTreeView->getSelected(); if (!file_pre_check(this, path)) return; boost::filesystem::path out_path = path.toStdString(); if (out_path.extension() == ".asc" || out_path.extension() == ".gpg") { out_path = out_path.parent_path() / out_path.stem(); } else { out_path += ".out"; } if (exists(out_path)) { auto ret = QMessageBox::warning( this, _("Warning"), _("The target file already exists, do you need to overwrite it?"), QMessageBox::Ok | QMessageBox::Cancel); if (ret == QMessageBox::Cancel) return; } GpgDecrResult result = nullptr; gpgme_error_t error; bool if_error = false; process_operation(this, _("Decrypting"), [&]() { try { error = GpgFileOpera::DecryptFile(path.toStdString(), out_path.string(), result); } catch (const std::runtime_error& e) { if_error = true; } }); if (!if_error) { auto resultAnalyse = DecryptResultAnalyse(error, std::move(result)); resultAnalyse.analyse(); process_result_analyse(edit, infoBoard, resultAnalyse); fileTreeView->update(); } else { QMessageBox::critical(this, _("Error"), _("An error occurred during operation.")); return; } } void MainWindow::slotFileSign() { auto fileTreeView = edit->slotCurPageFileTreeView(); auto path = fileTreeView->getSelected(); if (!file_pre_check(this, path)) return; auto key_ids = mKeyList->getChecked(); auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); if (keys->empty()) { QMessageBox::critical( this, _("No Key Selected"), _("Please select the key in the key toolbox on the right.")); return; } for (const auto& key : *keys) { if (!key.CanSignActual()) { QMessageBox::information( this, _("Invalid Operation"), QString(_("The selected key contains a key that does not actually " "have a sign usage.")) + "

" + _("for example the Following Key:") + "
" + QString::fromStdString(key.uids()->front().uid())); return; } } // Detect ascii mode auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); bool non_ascii_when_export = true; try { non_ascii_when_export = settings.lookup("general.non_ascii_when_export"); } catch (...) { LOG(ERROR) << _("Setting Operation Error") << _("non_ascii_when_export"); } auto _channel = GPGFRONTEND_DEFAULT_CHANNEL; auto _extension = ".asc"; if (non_ascii_when_export) { _channel = GPGFRONTEND_NON_ASCII_CHANNEL; _extension = ".sig"; } boost::filesystem::path in_path = path.toStdString(); auto sig_file_path = in_path; sig_file_path += _extension; if (exists(sig_file_path)) { auto ret = QMessageBox::warning( this, _("Warning"), QString(_("The signature file \"%1\" exists, " "do you need to overwrite it?")) .arg(sig_file_path.filename().string().c_str()), QMessageBox::Ok | QMessageBox::Cancel); if (ret == QMessageBox::Cancel) return; } GpgSignResult result = nullptr; gpgme_error_t error; bool if_error = false; process_operation(this, _("Signing"), [&]() { try { error = GpgFileOpera::SignFile(std::move(keys), in_path.string(), sig_file_path.string(), result, _channel); } catch (const std::runtime_error& e) { if_error = true; } }); if (!if_error) { auto resultAnalyse = SignResultAnalyse(error, std::move(result)); resultAnalyse.analyse(); process_result_analyse(edit, infoBoard, resultAnalyse); fileTreeView->update(); } else { QMessageBox::critical(this, _("Error"), _("An error occurred during operation.")); return; } fileTreeView->update(); } void MainWindow::slotFileVerify() { auto fileTreeView = edit->slotCurPageFileTreeView(); auto path = fileTreeView->getSelected(); boost::filesystem::path in_path = path.toStdString(); boost::filesystem::path sign_file_path = in_path, data_file_path; // Detect ascii mode auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); bool non_ascii_when_export = true; try { non_ascii_when_export = settings.lookup("general.non_ascii_when_export"); } catch (...) { LOG(ERROR) << _("Setting Operation Error") << _("non_ascii_when_export"); } auto _channel = GPGFRONTEND_DEFAULT_CHANNEL; if (non_ascii_when_export) { _channel = GPGFRONTEND_NON_ASCII_CHANNEL; } if (in_path.extension() == ".gpg") { swap(data_file_path, sign_file_path); } else if (in_path.extension() == ".sig" || in_path.extension() == ".asc") { data_file_path = sign_file_path.parent_path() / sign_file_path.stem(); } LOG(INFO) << "sign_file_path" << sign_file_path << sign_file_path.extension(); if (in_path.extension() != ".gpg") { bool ok; QString text = QInputDialog::getText(this, _("Origin file to verify"), _("Filepath"), QLineEdit::Normal, data_file_path.string().c_str(), &ok); if (ok && !text.isEmpty()) { data_file_path = text.toStdString(); } else { return; } } if (!is_regular_file(data_file_path) || (!sign_file_path.empty() && !is_regular_file(sign_file_path))) { QMessageBox::critical( this, _("Error"), _("Please select the appropriate origin file or signature file. " "Ensure that both are in this directory.")); return; } DLOG(INFO) << "data path" << data_file_path; DLOG(INFO) << "sign path" << sign_file_path; GpgVerifyResult result = nullptr; gpgme_error_t error; bool if_error = false; process_operation(this, _("Verifying"), [&]() { try { error = GpgFileOpera::VerifyFile( data_file_path.string(), sign_file_path.string(), result, _channel); } catch (const std::runtime_error& e) { if_error = true; } }); if (!if_error) { auto result_analyse = VerifyResultAnalyse(error, result); result_analyse.analyse(); process_result_analyse(edit, infoBoard, result_analyse); if (result_analyse.getStatus() == -2) import_unknown_key_from_keyserver(this, result_analyse); if (result_analyse.getStatus() >= 0) show_verify_details(this, infoBoard, error, result); fileTreeView->update(); } else { QMessageBox::critical(this, _("Error"), _("An error occurred during operation.")); return; } } void MainWindow::slotFileEncryptSign() { auto fileTreeView = edit->slotCurPageFileTreeView(); auto path = fileTreeView->getSelected(); if (!file_pre_check(this, path)) return; // check selected keys auto key_ids = mKeyList->getChecked(); auto p_keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); if (p_keys->empty()) { QMessageBox::critical( this, _("No Key Selected"), _("Please select the key in the key toolbox on the right.")); return; } // check key abilities for (const auto& key : *p_keys) { bool key_can_encrypt = key.CanEncrActual(); if (!key_can_encrypt) { QMessageBox::critical( nullptr, _("Invalid KeyPair"), QString(_("The selected keypair cannot be used for encryption.")) + "

" + _("For example the Following Key:") + "
" + QString::fromStdString(key.uids()->front().uid())); return; } } // Detect ascii mode auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); bool non_ascii_when_export = true; try { non_ascii_when_export = settings.lookup("general.non_ascii_when_export"); } catch (...) { LOG(ERROR) << _("Setting Operation Error") << _("non_ascii_when_export"); } auto _channel = GPGFRONTEND_DEFAULT_CHANNEL; auto _extension = ".asc"; if (non_ascii_when_export) { _channel = GPGFRONTEND_NON_ASCII_CHANNEL; _extension = ".gpg"; } boost::filesystem::path out_path = path.toStdString() + _extension; if (exists(out_path)) { auto ret = QMessageBox::warning( this, _("Warning"), _("The target file already exists, do you need to overwrite it?"), QMessageBox::Ok | QMessageBox::Cancel); if (ret == QMessageBox::Cancel) return; } auto signersPicker = new SignersPicker(this); QEventLoop loop; connect(signersPicker, SIGNAL(finished(int)), &loop, SLOT(quit())); loop.exec(); auto signer_key_ids = signersPicker->getCheckedSigners(); auto p_signer_keys = GpgKeyGetter::GetInstance().GetKeys(signer_key_ids); GpgEncrResult encr_result = nullptr; GpgSignResult sign_result = nullptr; gpgme_error_t error; bool if_error = false; process_operation(this, _("Encrypting and Signing"), [&]() { try { error = GpgFileOpera::EncryptSignFile( std::move(p_keys), std::move(p_signer_keys), path.toStdString(), out_path.string(), encr_result, sign_result, _channel); } catch (const std::runtime_error& e) { if_error = true; } }); if (!if_error) { auto encrypt_result = EncryptResultAnalyse(error, std::move(encr_result)); auto sign_res = SignResultAnalyse(error, std::move(sign_result)); encrypt_result.analyse(); sign_res.analyse(); process_result_analyse(edit, infoBoard, encrypt_result, sign_res); fileTreeView->update(); } else { QMessageBox::critical(this, _("Error"), _("An error occurred during operation.")); return; } } void MainWindow::slotFileDecryptVerify() { auto fileTreeView = edit->slotCurPageFileTreeView(); auto path = fileTreeView->getSelected(); if (!file_pre_check(this, path)) return; boost::filesystem::path in_path(path.toStdString()); boost::filesystem::path out_path = in_path; if (in_path.extension() == ".asc" || in_path.extension() == ".gpg") { out_path = in_path.parent_path() / out_path.stem(); } else { out_path += ".out"; } LOG(INFO) << "out path" << out_path; if (QFile::exists(out_path.string().c_str())) { auto ret = QMessageBox::warning(this, _("Warning"), QString(_("The output file %1 already exists, do " "you need to overwrite it?")) .arg(out_path.filename().string().c_str()), QMessageBox::Ok | QMessageBox::Cancel); if (ret == QMessageBox::Cancel) return; } GpgDecrResult d_result = nullptr; GpgVerifyResult v_result = nullptr; gpgme_error_t error; bool if_error = false; process_operation(this, _("Decrypting and Verifying"), [&]() { try { error = GpgFileOpera::DecryptVerifyFile( path.toStdString(), out_path.string(), d_result, v_result); } catch (const std::runtime_error& e) { if_error = true; } }); if (!if_error) { auto decrypt_res = DecryptResultAnalyse(error, std::move(d_result)); auto verify_res = VerifyResultAnalyse(error, v_result); decrypt_res.analyse(); verify_res.analyse(); process_result_analyse(edit, infoBoard, decrypt_res, verify_res); if (verify_res.getStatus() == -2) import_unknown_key_from_keyserver(this, verify_res); if (verify_res.getStatus() >= 0) show_verify_details(this, infoBoard, error, v_result); fileTreeView->update(); } else { QMessageBox::critical(this, _("Error"), _("An error occurred during operation.")); return; } } } // namespace GpgFrontend::UI