mirror of
https://github.com/chris2511/xca.git
synced 2026-09-12 19:51:05 +05:00
Close #88: Export to multiple files
Extend the ExportFile dialog by a checkbox to switch between "all-in-one-file" or every item in a separate file. It is only visible if more than one file is selected. Activating the checkbox will: - Change the file-input into a directory-input and cut off the file name - Disabling all formats that are intended for multiple items. De-activating the checkbox will: - Change the directory-input back into a file-input and append the previously erased file name again. - Disabling all export-formats that are only useful for single items.
This commit is contained in:
parent
71f28ef0e3
commit
46c1b78577
@ -718,10 +718,6 @@ int db_base::exportFlags(const QModelIndexList &indexes) const
|
||||
int disabled_flags = 0;
|
||||
foreach(const QModelIndex &idx, indexes)
|
||||
disabled_flags |= exportFlags(idx);
|
||||
if (indexes.size() > 1)
|
||||
disabled_flags |= F_SINGLE;
|
||||
else
|
||||
disabled_flags |= F_MULTI;
|
||||
return disabled_flags;
|
||||
}
|
||||
|
||||
|
||||
@ -384,5 +384,9 @@ QString fingerprint(const QByteArray &data, const EVP_MD *type)
|
||||
|
||||
void update_workingdir(const QString &file)
|
||||
{
|
||||
Settings["workingdir"] = QFileInfo(file).absolutePath();
|
||||
QFileInfo fi(file);
|
||||
if (fi.isDir())
|
||||
Settings["workingdir"] = fi.absoluteFilePath();
|
||||
else
|
||||
Settings["workingdir"] = fi.absolutePath();
|
||||
}
|
||||
|
||||
@ -62,16 +62,16 @@ void pki_export::init_elements()
|
||||
elements = QList<pki_export*> {
|
||||
|
||||
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", tr("PEM selected"), F_PEM | F_MULTI, tr("Concatenated list of all selected items in one PEM text file")),
|
||||
new pki_export( 3, x509, "pem", tr("PEM selected"), F_PEM | F_MULTI, tr("Concatenated list of all selected certificates in one PEM text 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( 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 | 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(40, x509, "pem", "All unusable", F_PEM | F_UNUSABLE, tr("Concatenation of all expired or revoked certificates in one PEM file")),
|
||||
new pki_export( 7, x509, "pem", "PEM + PKCS#8", F_PEM | F_PKCS8 | F_PRIVATE | F_CRYPT | F_SINGLE | F_CLIPBOARD, tr("Concatenation of the certificate and the encrypted private key in PKCS#8 format in one file")),
|
||||
new pki_export(40, x509, "pem", tr("All unusable"), F_PEM | F_UNUSABLE, tr("Concatenation of all expired or revoked certificates in one PEM 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")),
|
||||
new pki_export(41, x509, "p7b", "PKCS #7 Unusable", F_PKCS7 | F_UNUSABLE, tr("PKCS#7 encoded collection of all expired or revoked certificates")),
|
||||
new pki_export(41, x509, "p7b", tr("PKCS #7 unusable"), F_PKCS7 | F_UNUSABLE, tr("PKCS#7 encoded collection of all expired or revoked certificates")),
|
||||
new pki_export(13, x509, "cer", "DER", F_DER | F_SINGLE, tr("Binary DER encoded certificate")),
|
||||
new pki_export(14, x509, "pfx", tr("PKCS #12 chain"),F_PKCS12 | F_USUAL | F_CHAIN | F_CRYPT | F_PRIVATE | F_SINGLE, tr("The complete certificate chain and the private key as encrypted PKCS#12 file")),
|
||||
new pki_export(15, x509, "pfx", tr("PKCS #12"), F_PKCS12 | F_USUAL | F_CRYPT | F_PRIVATE | F_SINGLE, tr("The certificate and the private key as encrypted PKCS#12 file")),
|
||||
|
||||
@ -187,14 +187,14 @@ void test_main::exportFormat()
|
||||
idx = certs->index(certs->getByName("Root CA"));
|
||||
list << idx;
|
||||
QCOMPARE(certs->exportFlags(idx) , F_CHAIN | F_PRIVATE);
|
||||
QCOMPARE(certs->exportFlags(list) , F_CHAIN | F_PRIVATE | F_MULTI);
|
||||
QCOMPARE(certs->exportFlags(list) , F_CHAIN | F_PRIVATE);
|
||||
|
||||
// Inter CA 1: All export options permitted
|
||||
// Together with "Root CA" in "list": No chain, private or single
|
||||
idx = certs->index(certs->getByName("Inter CA 1"));
|
||||
list << idx;
|
||||
QCOMPARE(certs->exportFlags(idx) , 0);
|
||||
QCOMPARE(certs->exportFlags(list) , F_CHAIN | F_PRIVATE | F_SINGLE);
|
||||
QCOMPARE(certs->exportFlags(list) , F_CHAIN | F_PRIVATE);
|
||||
|
||||
// Endentity has no private key and id no CA
|
||||
idx = certs->index(certs->getByName("Endentity"));
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>589</width>
|
||||
<height>343</height>
|
||||
<height>366</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -22,6 +22,7 @@
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
<pointsize>14</pointsize>
|
||||
<weight>50</weight>
|
||||
<italic>false</italic>
|
||||
<bold>false</bold>
|
||||
<underline>false</underline>
|
||||
@ -70,7 +71,7 @@
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="TextLabel2">
|
||||
<widget class="QLabel" name="descriptionLabel">
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
@ -84,7 +85,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="TextLabel14">
|
||||
<widget class="QLabel" name="filenameLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@ -114,6 +115,13 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="separateFiles">
|
||||
<property name="text">
|
||||
<string>Each Item in a separate file</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
|
||||
@ -23,9 +23,8 @@ ExportDialog::ExportDialog(QWidget *w, const QString &title,
|
||||
const QString &filt, const QModelIndexList &indexes,
|
||||
const QPixmap &img, QList<const pki_export*> types,
|
||||
const QString &help_ctx)
|
||||
: QDialog(w ? w : mainwin)
|
||||
: QDialog(w ? w : mainwin), filter(filt), savedFile(), alltypes(types)
|
||||
{
|
||||
QList<const pki_export*> usual, normal;
|
||||
QString fname = "selected_items";
|
||||
setupUi(this);
|
||||
setWindowTitle(XCA_TITLE);
|
||||
@ -35,24 +34,37 @@ ExportDialog::ExportDialog(QWidget *w, const QString &title,
|
||||
description->setText(pki->getIntName());
|
||||
fname = pki->getUnderlinedName();
|
||||
}
|
||||
separateFiles->hide();
|
||||
setupExportFormat(F_MULTI);
|
||||
} else {
|
||||
// Plural form not required for < 2 items
|
||||
// Will only be called for 2 or more items
|
||||
description->setText(tr("%n selected item(s)", "", indexes.size()));
|
||||
setupExportFormat(F_SINGLE);
|
||||
}
|
||||
description->setReadOnly(true);
|
||||
image->setPixmap(img);
|
||||
label->setText(title);
|
||||
mainwin->helpdlg->register_ctxhelp_button(this, help_ctx);
|
||||
|
||||
QString fn = Settings["workingdir"] +
|
||||
fname + "." + types[0]->extension;
|
||||
filename->setText(nativeSeparator(fn));
|
||||
fname = Settings["workingdir"] + fname + "." + types[0]->extension;
|
||||
filename->setText(nativeSeparator(fname));
|
||||
filter = tr("All files ( * )") + ";;" + filter;
|
||||
filenameLabelOrig = filenameLabel->text();
|
||||
}
|
||||
|
||||
filter = tr("All files ( * )") + ";;" + filt;
|
||||
|
||||
foreach(const pki_export *t, types) {
|
||||
void ExportDialog::setupExportFormat(int disable_flag)
|
||||
{
|
||||
QList<const pki_export*> usual, normal;
|
||||
for (const pki_export *t : alltypes) {
|
||||
if (t->flags & disable_flag)
|
||||
continue;
|
||||
if (t->flags & F_USUAL)
|
||||
usual << t;
|
||||
else
|
||||
normal << t;
|
||||
}
|
||||
exportFormat->clear();
|
||||
foreach(const pki_export *t, usual + normal) {
|
||||
exportFormat->addItem(QString("%1 (*.%2)").
|
||||
arg(t->desc).arg(t->extension), QVariant(t->id));
|
||||
@ -71,10 +83,15 @@ ExportDialog::~ExportDialog()
|
||||
|
||||
void ExportDialog::on_fileBut_clicked()
|
||||
{
|
||||
QString s = QFileDialog::getSaveFileName(this, QString(),
|
||||
QString s;
|
||||
if (separateFiles->isChecked()) {
|
||||
s = QFileDialog::getExistingDirectory(this, QString(), filename->text(),
|
||||
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
||||
} else {
|
||||
s = QFileDialog::getSaveFileName(this, QString(),
|
||||
filename->text(), filter, NULL,
|
||||
QFileDialog::DontConfirmOverwrite);
|
||||
|
||||
}
|
||||
if (!s.isEmpty())
|
||||
filename->setText(nativeSeparator(s));
|
||||
}
|
||||
@ -99,7 +116,8 @@ void ExportDialog::on_exportFormat_activated(int selected)
|
||||
|
||||
bool ExportDialog::mayWriteFile(const QString &fname)
|
||||
{
|
||||
if (QFile::exists(fname)) {
|
||||
QFileInfo fi(fname);
|
||||
if (fi.exists() && !fi.isDir()) {
|
||||
xcaWarningBox msg(NULL,
|
||||
tr("The file: '%1' already exists!").arg(fname));
|
||||
msg.addButton(QMessageBox::Ok, tr("Overwrite"));
|
||||
@ -145,3 +163,21 @@ void ExportDialog::on_exportFormat_highlighted(int index)
|
||||
infoBox->setText(x->help);
|
||||
pemComment->setEnabled(x->flags & F_PEM);
|
||||
}
|
||||
|
||||
void ExportDialog::on_separateFiles_clicked(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
filenameLabel->setText(tr("Directory"));
|
||||
QFileInfo fi(filename->text());
|
||||
savedFile = fi.fileName();
|
||||
filename->setText(nativeSeparator(fi.path()));
|
||||
setupExportFormat(F_MULTI);
|
||||
} else {
|
||||
filenameLabel->setText(filenameLabelOrig);
|
||||
if (!savedFile.isEmpty()) {
|
||||
QString completefile = filename->text() + "/" + savedFile;
|
||||
filename->setText(nativeSeparator(completefile));
|
||||
}
|
||||
setupExportFormat(F_SINGLE);
|
||||
}
|
||||
}
|
||||
@ -20,7 +20,8 @@ class ExportDialog: public QDialog, public Ui::ExportDialog
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
QString filter{};
|
||||
QString filter{}, savedFile{}, filenameLabelOrig{};
|
||||
QList<const pki_export*> alltypes;
|
||||
|
||||
public:
|
||||
ExportDialog(QWidget *w, const QString &title, const QString &filt,
|
||||
@ -30,9 +31,11 @@ class ExportDialog: public QDialog, public Ui::ExportDialog
|
||||
~ExportDialog();
|
||||
static bool mayWriteFile(const QString &fname);
|
||||
const pki_export *export_type(int idx = -1) const;
|
||||
void setupExportFormat(int disable_flag);
|
||||
|
||||
public slots:
|
||||
void on_fileBut_clicked();
|
||||
void on_separateFiles_clicked(bool checked);
|
||||
void on_exportFormat_activated(int);
|
||||
void on_exportFormat_highlighted(int index);
|
||||
void accept();
|
||||
|
||||
@ -26,6 +26,8 @@
|
||||
#include "ExportDialog.h"
|
||||
#include "ImportMulti.h"
|
||||
#include "lib/load_obj.h"
|
||||
#include "lib/pass_info.h"
|
||||
#include "lib/PwDialogCore.h"
|
||||
|
||||
#include "ui_ItemProperties.h"
|
||||
|
||||
@ -480,17 +482,10 @@ void XcaTreeView::changeView()
|
||||
show();
|
||||
}
|
||||
|
||||
void XcaTreeView::exportItems(const QModelIndexList &indexes)
|
||||
void XcaTreeView::exportItems(const QModelIndexList &indexes,
|
||||
const QString &filename, const pki_export *xport)
|
||||
{
|
||||
if (!basemodel || indexes.empty())
|
||||
return;
|
||||
|
||||
ExportDialog *dlg = exportDialog(indexes);
|
||||
|
||||
if (dlg && dlg->exec()) {
|
||||
try {
|
||||
const pki_export *xport = dlg->export_type();
|
||||
XFile file(dlg->filename->text());
|
||||
XFile file(filename);
|
||||
|
||||
if (xport->match_all(F_PRIVATE))
|
||||
file.open_key();
|
||||
@ -498,6 +493,46 @@ void XcaTreeView::exportItems(const QModelIndexList &indexes)
|
||||
file.open_write();
|
||||
|
||||
basemodel->exportItems(indexes, xport, file);
|
||||
}
|
||||
|
||||
void XcaTreeView::exportItems(const QModelIndexList &indexes)
|
||||
{
|
||||
if (!basemodel || indexes.empty())
|
||||
return;
|
||||
|
||||
ExportDialog *dlg = exportDialog(indexes);
|
||||
if (dlg && dlg->exec()) {
|
||||
try {
|
||||
QString fname = dlg->filename->text();
|
||||
const pki_export *xport = dlg->export_type();
|
||||
|
||||
if (dlg->separateFiles->isChecked()) {
|
||||
Passwd pass;
|
||||
if (xport->match_all(F_CRYPT)) {
|
||||
// Plural form not required for < 2 items
|
||||
// Will only be called for 2 or more items
|
||||
pass_info p(tr("Export Password"),
|
||||
tr("Please enter the password to encrypt all %n "
|
||||
"exported private key(s) in:\n%1", "",
|
||||
indexes.size()).arg(fname),
|
||||
this);
|
||||
|
||||
// Ask for an encryption password once
|
||||
if (PwDialogCore::execute(&p, &pass, true) != 1)
|
||||
return;
|
||||
}
|
||||
for (QModelIndex idx : indexes) {
|
||||
pki_base *pki = db_base::fromIndex(idx);
|
||||
// Will be cleared by PwDialogCore
|
||||
PwDialogCore::cmdline_passwd = pass;
|
||||
QString fn = pki->get_dump_filename(fname,
|
||||
QString(".%1").arg(xport->extension));
|
||||
exportItems(QModelIndexList() << idx, fn, xport);
|
||||
}
|
||||
PwDialogCore::cmdline_passwd.cleanse();
|
||||
} else {
|
||||
exportItems(indexes, fname, xport);
|
||||
}
|
||||
} catch (errorEx &err) {
|
||||
XCA_ERROR(err);
|
||||
}
|
||||
|
||||
@ -68,6 +68,8 @@ class XcaTreeView: public QTreeView
|
||||
virtual void exportItems(const QModelIndexList &indexes);
|
||||
virtual void load_default(load_base *load);
|
||||
virtual ExportDialog *exportDialog(const QModelIndexList &indexes);
|
||||
virtual void exportItems(const QModelIndexList &indexes,
|
||||
const QString &filename, const pki_export *xport);
|
||||
|
||||
public slots:
|
||||
void changeView();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user