/**
* 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 "ui/KeyMgmt.h"
#include
KeyMgmt::KeyMgmt(GpgME::GpgContext *ctx, QWidget *parent ) :
QMainWindow(parent), appPath(qApp->applicationDirPath()), settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat)
{
mCtx = ctx;
/* the list of Keys available*/
mKeyList = new KeyList(mCtx);
mKeyList->setColumnWidth(2, 250);
mKeyList->setColumnWidth(3, 250);
setCentralWidget(mKeyList);
mKeyList->setDoubleClickedAction([this] (const GpgKey &key, QWidget *parent) {
new KeyDetailsDialog(mCtx, key, parent);
});
createActions();
createMenus();
createToolBars();
connect(this,SIGNAL(signalStatusBarChanged(QString)),this->parent(),SLOT(slotSetStatusBarText(QString)));
/* Restore the iconstyle */
this->settings.sync();
QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize();
settings.setValue("toolbar/iconsize", iconSize);
Qt::ToolButtonStyle buttonStyle = static_cast(settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon).toUInt());
this->setIconSize(iconSize);
this->setToolButtonStyle(buttonStyle);
// state sets pos & size of dock-widgets
this->restoreState(this->settings.value("keymgmt/windowState").toByteArray());
qDebug() << "windows/windowSave" << this->settings.value("window/windowSave").toBool();
// Restore window size & location
if (this->settings.value("keymgmt/setWindowSize").toBool()) {
QPoint pos = settings.value("keymgmt/pos", QPoint(100, 100)).toPoint();
QSize size = settings.value("keymgmt/size", QSize(900, 600)).toSize();
qDebug() << "Settings size" << size << "pos" << pos;
this->setMinimumSize(size);
this->move(pos);
} else {
qDebug() << "Use default min windows size and pos";
QPoint defaultPoint(100, 100);
QSize defaultMinSize(900, 600);
this->setMinimumSize(defaultMinSize);
this->move(defaultPoint);
this->settings.setValue("keymgmt/pos", defaultPoint);
this->settings.setValue("keymgmt/size", defaultMinSize);
this->settings.setValue("keymgmt/setWindowSize", true);
}
setWindowTitle(tr("Key Pair Management"));
mKeyList->addMenuAction(deleteSelectedKeysAct);
mKeyList->addMenuAction(showKeyDetailsAct);
}
void KeyMgmt::createActions()
{
openKeyFileAct = new QAction(tr("&Open"), this);
openKeyFileAct->setShortcut(tr("Ctrl+O"));
openKeyFileAct->setToolTip(tr("Open Key File"));
connect(openKeyFileAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromFile()));
closeAct = new QAction(tr("&Close"), this);
closeAct->setShortcut(tr("Ctrl+Q"));
closeAct->setIcon(QIcon(":exit.png"));
closeAct->setToolTip(tr("Close"));
connect(closeAct, SIGNAL(triggered()), this, SLOT(close()));
generateKeyPairAct = new QAction(tr("New Keypair"), this);
generateKeyPairAct->setShortcut(tr("Ctrl+N"));
generateKeyPairAct->setIcon(QIcon(":key_generate.png"));
generateKeyPairAct->setToolTip(tr("Generate KeyPair"));
connect(generateKeyPairAct, SIGNAL(triggered()), this, SLOT(slotGenerateKeyDialog()));
generateSubKeyAct = new QAction(tr("New Subkey"), this);
generateSubKeyAct->setShortcut(tr("Ctrl+Shift+N"));
generateSubKeyAct->setIcon(QIcon(":key_generate.png"));
generateSubKeyAct->setToolTip(tr("Generate Subkey For Selected KeyPair"));
connect(generateSubKeyAct, SIGNAL(triggered()), this, SLOT(slotGenerateSubKey()));
importKeyFromFileAct = new QAction(tr("&File"), this);
importKeyFromFileAct->setIcon(QIcon(":import_key_from_file.png"));
importKeyFromFileAct->setToolTip(tr("Import New Key From File"));
connect(importKeyFromFileAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromFile()));
importKeyFromClipboardAct = new QAction(tr("&Clipboard"), this);
importKeyFromClipboardAct->setIcon(QIcon(":import_key_from_clipboard.png"));
importKeyFromClipboardAct->setToolTip(tr("Import New Key From Clipboard"));
connect(importKeyFromClipboardAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromClipboard()));
importKeyFromKeyServerAct = new QAction(tr("&Keyserver"), this);
importKeyFromKeyServerAct->setIcon(QIcon(":import_key_from_server.png"));
importKeyFromKeyServerAct->setToolTip(tr("Import New Key From Keyserver"));
connect(importKeyFromKeyServerAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromKeyServer()));
exportKeyToClipboardAct = new QAction(tr("Export To &Clipboard"), this);
exportKeyToClipboardAct->setIcon(QIcon(":export_key_to_clipboard.png"));
exportKeyToClipboardAct->setToolTip(tr("Export Selected Key(s) To Clipboard"));
connect(exportKeyToClipboardAct, SIGNAL(triggered()), this, SLOT(slotExportKeyToClipboard()));
exportKeyToFileAct = new QAction(tr("Export To &File"), this);
exportKeyToFileAct->setIcon(QIcon(":export_key_to_file.png"));
exportKeyToFileAct->setToolTip(tr("Export Selected Key(s) To File"));
connect(exportKeyToFileAct, SIGNAL(triggered()), this, SLOT(slotExportKeyToFile()));
deleteSelectedKeysAct = new QAction(tr("Delete Selected Key(s)"), this);
deleteSelectedKeysAct->setToolTip(tr("Delete the Selected keys"));
connect(deleteSelectedKeysAct, SIGNAL(triggered()), this, SLOT(slotDeleteSelectedKeys()));
deleteCheckedKeysAct = new QAction(tr("Delete Checked Key(s)"), this);
deleteCheckedKeysAct->setToolTip(tr("Delete the Checked keys"));
deleteCheckedKeysAct->setIcon(QIcon(":button_delete.png"));
connect(deleteCheckedKeysAct, SIGNAL(triggered()), this, SLOT(slotDeleteCheckedKeys()));
showKeyDetailsAct = new QAction(tr("Show Key Details"), this);
showKeyDetailsAct->setToolTip(tr("Show Details for this Key"));
connect(showKeyDetailsAct, SIGNAL(triggered()), this, SLOT(slotShowKeyDetails()));
}
void KeyMgmt::createMenus()
{
fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(openKeyFileAct);
fileMenu->addAction(closeAct);
keyMenu = menuBar()->addMenu(tr("&Key"));
generateKeyMenu = keyMenu->addMenu(tr("&Generate Key"));
generateKeyMenu->addAction(generateKeyPairAct);
generateKeyMenu->addAction(generateSubKeyAct);
importKeyMenu = keyMenu->addMenu(tr("&Import Key"));
importKeyMenu->addAction(importKeyFromFileAct);
importKeyMenu->addAction(importKeyFromClipboardAct);
importKeyMenu->addAction(importKeyFromKeyServerAct);
keyMenu->addAction(exportKeyToFileAct);
keyMenu->addAction(exportKeyToClipboardAct);
keyMenu->addSeparator();
keyMenu->addAction(deleteCheckedKeysAct);
}
void KeyMgmt::createToolBars()
{
QToolBar *keyToolBar = addToolBar(tr("Key"));
keyToolBar->setObjectName("keytoolbar");
// add button with popup menu for import
auto* generateToolButton = new QToolButton(this);
generateToolButton->setMenu(generateKeyMenu);
generateToolButton->setPopupMode(QToolButton::InstantPopup);
generateToolButton->setIcon(QIcon(":key_generate.png"));
generateToolButton->setText(tr("Generate"));
generateToolButton->setToolTip(tr("Generate A New Keypair or Subkey"));
generateToolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
keyToolBar->addWidget(generateToolButton);
// add button with popup menu for import
auto* toolButton = new QToolButton(this);
toolButton->setMenu(importKeyMenu);
toolButton->setPopupMode(QToolButton::InstantPopup);
toolButton->setIcon(QIcon(":key_import.png"));
toolButton->setToolTip(tr("Import key"));
toolButton->setText(tr("Import Key"));
toolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
keyToolBar->addWidget(toolButton);
keyToolBar->addSeparator();
keyToolBar->addAction(deleteCheckedKeysAct);
keyToolBar->addSeparator();
keyToolBar->addAction(exportKeyToFileAct);
keyToolBar->addAction(exportKeyToClipboardAct);
}
void KeyMgmt::slotImportKeys(QByteArray inBuffer)
{
GpgImportInformation result = mCtx->importKey(std::move(inBuffer));
new KeyImportDetailDialog(mCtx, result, false, this);
}
void KeyMgmt::slotImportKeyFromFile()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Open Key"), "", tr("Key Files") + " (*.asc *.txt);;"+tr("Keyring files")+" (*.gpg);;All Files (*)");
if (! fileName.isNull()) {
QFile file;
file.setFileName(fileName);
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << tr("Couldn't Open File: ") + fileName;
return;
}
QByteArray inBuffer = file.readAll();
slotImportKeys(inBuffer);
file.close();
}
}
void KeyMgmt::slotImportKeyFromKeyServer()
{
importDialog = new KeyServerImportDialog(mCtx, mKeyList, false, this);
importDialog->show();
}
void KeyMgmt::slotImportKeyFromClipboard()
{
QClipboard *cb = QApplication::clipboard();
slotImportKeys(cb->text(QClipboard::Clipboard).toUtf8());
}
void KeyMgmt::slotDeleteSelectedKeys()
{
deleteKeysWithWarning(mKeyList->getSelected());
}
void KeyMgmt::slotDeleteCheckedKeys()
{
deleteKeysWithWarning(mKeyList->getChecked());
}
void KeyMgmt::deleteKeysWithWarning(QStringList *uidList)
{
/**
* TODO: Different Messages for private/public key, check if
* more than one selected... compare to seahorse "delete-dialog"
*/
if (uidList->isEmpty()) {
return;
}
QString keynames;
for (const auto &uid : *uidList) {
auto &key = mCtx->getKeyById(uid);
keynames.append(key.name);
keynames.append(" <");
keynames.append(key.email);
keynames.append(">
");
}
int ret = QMessageBox::warning(this, tr("Deleting Keys"),
""+tr("Are you sure that you want to delete the following keys?")+"
"+keynames+
+"
"+tr("The action can not be undone."),
QMessageBox::No | QMessageBox::Yes);
if (ret == QMessageBox::Yes) {
mCtx->deleteKeys(uidList);
}
}
void KeyMgmt::slotShowKeyDetails()
{
if (mKeyList->getSelected()->isEmpty()) {
return;
}
auto &key = mCtx->getKeyById(mKeyList->getSelected()->first());
new KeyDetailsDialog(mCtx, key);
}
void KeyMgmt::slotExportKeyToFile()
{
auto *keyArray = new QByteArray();
if (!mCtx->exportKeys(mKeyList->getChecked(), keyArray)) {
delete keyArray;
return;
}
auto &key = mCtx->getKeyById(mKeyList->getSelected()->first());
QString fileString = key.name + " " + key.email+ "(" + key.id+ ")_pub.asc";
QString fileName = QFileDialog::getSaveFileName(this, tr("Export Key To File"), fileString, tr("Key Files") + " (*.asc *.txt);;All Files (*)");
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
delete keyArray;
return;
}
QTextStream stream(&file);
stream << *keyArray;
file.close();
delete keyArray;
emit signalStatusBarChanged(QString(tr("key(s) exported")));
}
void KeyMgmt::slotExportKeyToClipboard()
{
auto *keyArray = new QByteArray();
QClipboard *cb = QApplication::clipboard();
if (!mCtx->exportKeys(mKeyList->getChecked(), keyArray)) {
return;
}
cb->setText(*keyArray);
delete keyArray;
}
void KeyMgmt::slotGenerateKeyDialog()
{
auto *keyGenDialog = new KeyGenDialog(mCtx,this);
keyGenDialog->show();
}
void KeyMgmt::closeEvent(QCloseEvent *event)
{
QMainWindow::closeEvent(event);
}
void KeyMgmt::slotGenerateSubKey() {
auto selectedList = mKeyList->getSelected();
if(selectedList->empty()) {
QMessageBox::information(nullptr,
tr("Invalid Operation"),
tr("Please select one KeyPair before doing this operation."));
return;
}
const auto &key = mCtx->getKeyById(selectedList->first());
if(!key.is_private_key) {
QMessageBox::critical(nullptr,
tr("Invalid Operation"),
tr("If a key pair does not have a private key then it will not be able to generate sub-keys."));
return;
}
auto dialog = new SubkeyGenerateDialog(mCtx, key, this);
dialog->show();
}