From 2060d75f51a63fc0022319e8423df7d55f9bdefc Mon Sep 17 00:00:00 2001 From: Christian Hohnstaedt Date: Fri, 19 Apr 2024 08:41:33 +0200 Subject: [PATCH] Close #395: Flexible Clipboard Export Generalize the Clipboard format selection and extend it to certificates. Certificates may now be exported as chain or together with private key. The clipboard format selection also affects the Drag&Drop content. The Export->Clipboard men now also shows the currently selected format export. --- lib/pki_export.cpp | 8 ++++---- lib/pki_export.h | 1 + lib/pki_x509.cpp | 22 ++++++++++++++++++++-- lib/settings.cpp | 1 + widgets/CertTreeView.h | 6 +++++- widgets/KeyTreeView.cpp | 26 -------------------------- widgets/KeyTreeView.h | 7 +++++-- widgets/XcaTreeView.cpp | 35 ++++++++++++++++++++++++++++++++++- widgets/XcaTreeView.h | 6 ++++++ 9 files changed, 76 insertions(+), 36 deletions(-) diff --git a/lib/pki_export.cpp b/lib/pki_export.cpp index 9d1843d6..c3d09524 100644 --- a/lib/pki_export.cpp +++ b/lib/pki_export.cpp @@ -61,12 +61,12 @@ void pki_export::init_elements() free_elements(); elements = QList { -new pki_export( 1, x509, "crt", "PEM", F_PEM | F_USUAL | F_SINGLE, tr("PEM Text format with headers")), +new pki_export( 1, x509, "crt", "PEM", F_PEM | F_USUAL | F_SINGLE | F_CLIPBOARD, tr("PEM Text format with headers")), new pki_export( 3, x509, "pem", "PEM", F_PEM | F_MULTI, tr("Concatenated list of all selected items in one PEM text file")), -new pki_export( 2, x509, "pem", tr("PEM chain"), F_PEM | F_USUAL | F_CHAIN | F_SINGLE, tr("Concatenated text format of the complete certificate chain in one PEM file")), +new pki_export( 2, x509, "pem", tr("PEM chain"), F_PEM | F_USUAL | F_CHAIN | F_SINGLE | F_CLIPBOARD, tr("Concatenated text format of the complete certificate chain in one PEM file")), new pki_export( 4, x509, "ovpn","OpenVPN", F_PEM | F_OVPN | F_CHAIN | F_PRIVATE | F_SINGLE, tr("The complete certificate chain and the private key of the selected certificate with tags usable in OpenVPN configuration files")), -new pki_export( 6, x509, "pem", tr("PEM + key"), F_PEM | F_PRIVATE| F_SINGLE, tr("Concatenation of the certificate and the unencrypted private key in one PEM file")), -new pki_export( 7, x509, "pem", "PEM + PKCS#8", F_PEM | F_PKCS8 | F_PRIVATE | F_CRYPT, tr("Concatenation of the certificate and the encrypted private key in PKCS#8 format in one file")), +new pki_export( 6, x509, "pem", tr("PEM + key"), F_PEM | F_PRIVATE| F_SINGLE | F_CLIPBOARD, tr("Concatenation of the certificate and the unencrypted private key in one PEM file")), +new pki_export( 7, x509, "pem", "PEM + PKCS#8", F_PEM | F_PKCS8 | F_PRIVATE | F_CRYPT | F_CLIPBOARD, tr("Concatenation of the certificate and the encrypted private key in PKCS#8 format in one file")), new pki_export( 8, x509, "p7b", "PKCS #7", F_PKCS7 | F_USUAL | F_SINGLE, tr("PKCS#7 encoded single certificate")), new pki_export(10, x509, "p7b", "PKCS #7", F_PKCS7 | F_USUAL | F_MULTI, tr("All selected certificates encoded in one PKCS#7 file")), new pki_export(12, x509, "p7b", tr("PKCS #7 chain"), F_PKCS7 | F_USUAL | F_CHAIN | F_SINGLE, tr("PKCS#7 encoded complete certificate chain")), diff --git a/lib/pki_export.h b/lib/pki_export.h index cdc2e5b6..e6d41f93 100644 --- a/lib/pki_export.h +++ b/lib/pki_export.h @@ -15,6 +15,7 @@ #define BIT(n) (1<match_all(F_PEM | F_CHAIN)) { + pki_x509 *iss, *prev; + for (iss = this, prev = nullptr; iss && iss != prev; + prev = iss, iss = iss->getSigner()) + { + qDebug() << "Exporting to ClipBoard" << iss->getIntName(); + if (!PEM_write_bio_X509(b, iss->cert)) + return false; + } + } else if (xport->match_all(F_PEM | F_PRIVATE)) { + pki_key *key = getRefKey(); + if (!key || !PEM_write_bio_X509(b, cert)) + return false; + return key->pem(b, xport); + } else { + return PEM_write_bio_X509(b, cert); + } + return true; } bool pki_x509::cmpIssuerAndSerial(pki_x509 *refcert) @@ -725,7 +744,6 @@ bool pki_x509::cmpIssuerAndSerial(pki_x509 *refcert) bool ret = X509_issuer_and_serial_cmp(cert, refcert->cert); pki_openssl_error(); return ret; - } bool pki_x509::verify_only(const pki_x509 *signer) const diff --git a/lib/settings.cpp b/lib/settings.cpp index 16b2e6c4..be4bc733 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -48,6 +48,7 @@ settings::settings() defaul["fp_separator"] = ":"; defaul["fp_digits"] = "2"; defaul["KeyFormat"] = QString::number(DEFAULT_KEY_CLIPBOARD_TYPE); + defaul["CertFormat"] = QString::number(DEFAULT_CERT_CLIPBOARD_TYPE); hostspecific << "pkcs11path" << "workingdir" << "mw_geometry"; } diff --git a/widgets/CertTreeView.h b/widgets/CertTreeView.h index 10f381b9..fa765416 100644 --- a/widgets/CertTreeView.h +++ b/widgets/CertTreeView.h @@ -21,7 +21,11 @@ class CertTreeView: public X509SuperTreeView } public: - CertTreeView(QWidget *parent) : X509SuperTreeView(parent) { } + CertTreeView(QWidget *parent) : X509SuperTreeView(parent) + { + ClipboardSettings = "CertFormat"; + ClipboardPki_type = x509; + } void fillContextMenu(QMenu *menu, QMenu *subExport, const QModelIndex &index, QModelIndexList indexes); ExportDialog *exportDialog(const QModelIndexList &index); diff --git a/widgets/KeyTreeView.cpp b/widgets/KeyTreeView.cpp index 6e7a6315..e5703d35 100644 --- a/widgets/KeyTreeView.cpp +++ b/widgets/KeyTreeView.cpp @@ -14,35 +14,14 @@ #include "ExportDialog.h" #include "XcaWarning.h" #include -#include #include void KeyTreeView::fillContextMenu(QMenu *menu, QMenu *subExport, const QModelIndex &index, QModelIndexList indexes) { - QMenu *clipboard; - QAction *a; bool multi = indexes.size() > 1; - QActionGroup *group = new QActionGroup(menu); pki_key *key = db_base::fromIndex(index); - int exp_type = Settings["KeyFormat"]; - const pki_export *x; - - clipboard = menu->addMenu(tr("Clipboard format")); - foreach(x, pki_export::select(asym_key, 0)) { - if (!(x->flags & F_CLIPBOARD)) - continue; - a = clipboard->addAction(x->desc); - a->setData(x->id); - a->setCheckable(true); - a->setChecked(exp_type == x->id); - group->addAction(a); - } - - connect(group, SIGNAL(triggered(QAction*)), - this, SLOT(clipboardFormat(QAction*))); - if (indexes.size() == 0 || !key) return; @@ -209,11 +188,6 @@ void KeyTreeView::newItem(const QString &name) delete dlg; } -void KeyTreeView::clipboardFormat(QAction *a) -{ - Settings["KeyFormat"] = a->data().toInt(); -} - void KeyTreeView::load(void) { load_key l; diff --git a/widgets/KeyTreeView.h b/widgets/KeyTreeView.h index e38953dc..84857108 100644 --- a/widgets/KeyTreeView.h +++ b/widgets/KeyTreeView.h @@ -22,7 +22,11 @@ class KeyTreeView: public XcaTreeView } public: - KeyTreeView(QWidget *parent) : XcaTreeView(parent) { } + KeyTreeView(QWidget *parent) : XcaTreeView(parent) + { + ClipboardSettings = "KeyFormat"; + ClipboardPki_type = asym_key; + } void fillContextMenu(QMenu *menu, QMenu *subExport, const QModelIndex &index, QModelIndexList indexes); void showPki(pki_base *pki); @@ -38,6 +42,5 @@ class KeyTreeView: public XcaTreeView void newItem(); void load(); void newItem(const QString &name); - void clipboardFormat(QAction*); }; #endif diff --git a/widgets/XcaTreeView.cpp b/widgets/XcaTreeView.cpp index 9beff802..9a4b053a 100644 --- a/widgets/XcaTreeView.cpp +++ b/widgets/XcaTreeView.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "OidResolver.h" #include "XcaHeaderView.h" @@ -531,12 +532,16 @@ void XcaTreeView::showContextMenu(QContextMenuEvent *e, menu->addAction(tr("Delete"), this, SLOT(deleteItems()))-> setShortcut(QKeySequence::Delete); subExport = menu->addMenu(tr("Export")); - subExport->addAction(tr("Clipboard"), this, + const pki_export *xport = pki_export::by_id(Settings[ClipboardSettings]); + subExport->addAction(QString("%1 (%2)") + .arg(tr("Clipboard")).arg(xport->desc), this, SLOT(pem2clipboard()))->setShortcut(QKeySequence::Copy); subExport->addAction(tr("File"), this, SLOT(exportItems()))-> setShortcut(QKeySequence::Save); } + clipboardFormatMenu(menu); + fillContextMenu(menu, subExport, index, indexes); contextMenu(e, menu, -1); @@ -585,3 +590,31 @@ void XcaTreeView::changeEvent(QEvent *event) } QTreeView::changeEvent(event); } + +void XcaTreeView::clipboardFormatMenu(QMenu *menu) +{ + if (!ClipboardSettings || !ClipboardPki_type) + return; + int exp_type = Settings[ClipboardSettings]; + + QActionGroup *group = new QActionGroup(menu); + QMenu *clipboard = menu->addMenu(tr("Clipboard format")); + foreach(const pki_export *x, pki_export::select(ClipboardPki_type, 0)) { + if (!(x->flags & F_CLIPBOARD)) + continue; + QAction *a = clipboard->addAction(x->desc); + a->setData(x->id); + a->setCheckable(true); + a->setChecked(exp_type == x->id); + group->addAction(a); + } + + connect(group, SIGNAL(triggered(QAction*)), + this, SLOT(clipboardFormat(QAction*))); +} + +void XcaTreeView::clipboardFormat(QAction *a) +{ + if (ClipboardSettings) + Settings[ClipboardSettings] = a->data().toInt(); +} diff --git a/widgets/XcaTreeView.h b/widgets/XcaTreeView.h index 2f4ef227..2ec4a367 100644 --- a/widgets/XcaTreeView.h +++ b/widgets/XcaTreeView.h @@ -14,6 +14,8 @@ #include #include +#include "lib/pki_export.h" + class database_model; class MainWindow; class db_base; @@ -36,6 +38,9 @@ class XcaTreeView: public QTreeView db_base *basemodel{}; QSortFilterProxyModel *proxy{}; MainWindow *mainwin{}; + const char *ClipboardSettings{}; + enum pki_type ClipboardPki_type{ none }; + void clipboardFormatMenu(QMenu *menu); public: XcaTreeView(QWidget *parent = nullptr); @@ -85,5 +90,6 @@ class XcaTreeView: public QTreeView void showItem(const QModelIndex &index); void showItem(const QString &name); void itemSelectionChanged(const QModelIndex &m, const QModelIndex &); + void clipboardFormat(QAction*); }; #endif