KeeShare code formatting and spelling correction

This commit is contained in:
Jonathan White 2019-01-18 21:53:02 -05:00
parent 9b4a680f7e
commit 8c5da624e5
No known key found for this signature in database
GPG key ID: 440FC65F2E0C6E01
10 changed files with 538 additions and 487 deletions

View file

@ -202,7 +202,7 @@ add_feature_info(Auto-Type WITH_XC_AUTOTYPE "Automatic password typing")
add_feature_info(Networking WITH_XC_NETWORKING "Compile KeePassXC with network access code (e.g. for downloading website icons)") add_feature_info(Networking WITH_XC_NETWORKING "Compile KeePassXC with network access code (e.g. for downloading website icons)")
add_feature_info(KeePassXC-Browser WITH_XC_BROWSER "Browser integration with KeePassXC-Browser") add_feature_info(KeePassXC-Browser WITH_XC_BROWSER "Browser integration with KeePassXC-Browser")
add_feature_info(SSHAgent WITH_XC_SSHAGENT "SSH agent integration compatible with KeeAgent") add_feature_info(SSHAgent WITH_XC_SSHAGENT "SSH agent integration compatible with KeeAgent")
add_feature_info(KeeSharee WITH_XC_KEESHARE "Sharing integration with KeeShare") add_feature_info(KeeShare WITH_XC_KEESHARE "Sharing integration with KeeShare")
add_feature_info(KeeShare-Secure WITH_XC_KEESHARE_SECURE "Sharing integration with KeeShare with secure sources") add_feature_info(KeeShare-Secure WITH_XC_KEESHARE_SECURE "Sharing integration with KeeShare with secure sources")
add_feature_info(YubiKey WITH_XC_YUBIKEY "YubiKey HMAC-SHA1 challenge-response") add_feature_info(YubiKey WITH_XC_YUBIKEY "YubiKey HMAC-SHA1 challenge-response")
if(APPLE) if(APPLE)

View file

@ -45,8 +45,8 @@ void DatabaseSettingsWidgetKeeShare::loadSettings(QSharedPointer<Database> db)
m_referencesModel.reset(new QStandardItemModel()); m_referencesModel.reset(new QStandardItemModel());
m_referencesModel->setHorizontalHeaderLabels( m_referencesModel->setHorizontalHeaderLabels(QStringList() << tr("Breadcrumb") << tr("Type") << tr("Path")
QStringList() << tr("Breadcrumb") << tr("Type") << tr("Path") << tr("Last Signer") << tr("Certificates")); << tr("Last Signer") << tr("Certificates"));
const QList<Group*> groups = db->rootGroup()->groupsRecursive(true); const QList<Group*> groups = db->rootGroup()->groupsRecursive(true);
for (const Group* group : groups) { for (const Group* group : groups) {
if (!KeeShare::isShared(group)) { if (!KeeShare::isShared(group)) {

View file

@ -32,11 +32,11 @@
namespace namespace
{ {
static const QString KeeShare_Reference("KeeShare/Reference"); static const QString KeeShare_Reference("KeeShare/Reference");
static const QString KeeShare_Own("KeeShare/Settings.own"); static const QString KeeShare_Own("KeeShare/Settings.own");
static const QString KeeShare_Foreign("KeeShare/Settings.foreign"); static const QString KeeShare_Foreign("KeeShare/Settings.foreign");
static const QString KeeShare_Active("KeeShare/Settings.active"); static const QString KeeShare_Active("KeeShare/Settings.active");
} } // namespace
KeeShare* KeeShare::m_instance = nullptr; KeeShare* KeeShare::m_instance = nullptr;
@ -129,13 +129,13 @@ bool KeeShare::isEnabled(const Group* group)
{ {
const auto reference = KeeShare::referenceOf(group); const auto reference = KeeShare::referenceOf(group);
#if !defined(WITH_XC_KEESHARE_SECURE) #if !defined(WITH_XC_KEESHARE_SECURE)
if (reference.path.endsWith(signedContainerFileType(), Qt::CaseInsensitive)){ if (reference.path.endsWith(signedContainerFileType(), Qt::CaseInsensitive)) {
return false; return false;
} }
#endif #endif
#if !defined(WITH_XC_KEESHARE_INSECURE) #if !defined(WITH_XC_KEESHARE_INSECURE)
if (reference.path.endsWith(unsignedContainerFileType(), Qt::CaseInsensitive)){ if (reference.path.endsWith(unsignedContainerFileType(), Qt::CaseInsensitive)) {
return false; return false;
} }
#endif #endif
const auto active = KeeShare::active(); const auto active = KeeShare::active();
@ -198,13 +198,13 @@ void KeeShare::connectDatabase(QSharedPointer<Database> newDb, QSharedPointer<Da
} }
} }
const QString &KeeShare::signedContainerFileType() const QString& KeeShare::signedContainerFileType()
{ {
static const QString filetype("kdbx.share"); static const QString filetype("kdbx.share");
return filetype; return filetype;
} }
const QString &KeeShare::unsignedContainerFileType() const QString& KeeShare::unsignedContainerFileType()
{ {
static const QString filetype("kdbx"); static const QString filetype("kdbx");
return filetype; return filetype;

View file

@ -32,7 +32,7 @@ class QXmlStreamReader;
class KeeShare : public QObject class KeeShare : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
static KeeShare* instance(); static KeeShare* instance();
static void init(QObject* parent); static void init(QObject* parent);
@ -41,7 +41,7 @@ public:
static QPixmap indicatorBadge(const Group* group, QPixmap pixmap); static QPixmap indicatorBadge(const Group* group, QPixmap pixmap);
static bool isShared(const Group* group); static bool isShared(const Group* group);
static bool isEnabled(const Group *group); static bool isEnabled(const Group* group);
static KeeShareSettings::Own own(); static KeeShareSettings::Own own();
static KeeShareSettings::Active active(); static KeeShareSettings::Active active();

View file

@ -97,7 +97,7 @@ namespace KeeShareSettings
} }
specific(reader); specific(reader);
} }
} } // namespace
void Certificate::serialize(QXmlStreamWriter& writer, const Certificate& certificate) void Certificate::serialize(QXmlStreamWriter& writer, const Certificate& certificate)
{ {
@ -295,12 +295,12 @@ namespace KeeShareSettings
return own; return own;
} }
bool ScopedCertificate::operator==(const ScopedCertificate &other) const bool ScopedCertificate::operator==(const ScopedCertificate& other) const
{ {
return trust == other.trust && path == other.path && certificate == other.certificate; return trust == other.trust && path == other.path && certificate == other.certificate;
} }
bool ScopedCertificate::operator!=(const ScopedCertificate &other) const bool ScopedCertificate::operator!=(const ScopedCertificate& other) const
{ {
return !operator==(other); return !operator==(other);
} }
@ -309,26 +309,26 @@ namespace KeeShareSettings
{ {
writer.writeAttribute("Path", scopedCertificate.path); writer.writeAttribute("Path", scopedCertificate.path);
QString trust = "Ask"; QString trust = "Ask";
if(scopedCertificate.trust == KeeShareSettings::Trust::Trusted) { if (scopedCertificate.trust == KeeShareSettings::Trust::Trusted) {
trust = "Trusted"; trust = "Trusted";
} }
if(scopedCertificate.trust == KeeShareSettings::Trust::Untrusted){ if (scopedCertificate.trust == KeeShareSettings::Trust::Untrusted) {
trust = "Untrusted"; trust = "Untrusted";
} }
writer.writeAttribute("Trust", trust); writer.writeAttribute("Trust", trust);
Certificate::serialize(writer, scopedCertificate.certificate); Certificate::serialize(writer, scopedCertificate.certificate);
} }
ScopedCertificate ScopedCertificate::deserialize(QXmlStreamReader &reader) ScopedCertificate ScopedCertificate::deserialize(QXmlStreamReader& reader)
{ {
ScopedCertificate scopedCertificate; ScopedCertificate scopedCertificate;
scopedCertificate.path = reader.attributes().value("Path").toString(); scopedCertificate.path = reader.attributes().value("Path").toString();
scopedCertificate.trust = KeeShareSettings::Trust::Ask; scopedCertificate.trust = KeeShareSettings::Trust::Ask;
auto trust = reader.attributes().value("Trust").toString(); auto trust = reader.attributes().value("Trust").toString();
if(trust.compare("Trusted", Qt::CaseInsensitive) == 0) { if (trust.compare("Trusted", Qt::CaseInsensitive) == 0) {
scopedCertificate.trust = KeeShareSettings::Trust::Trusted; scopedCertificate.trust = KeeShareSettings::Trust::Trusted;
} }
if(trust.compare("Untrusted", Qt::CaseInsensitive) == 0) { if (trust.compare("Untrusted", Qt::CaseInsensitive) == 0) {
scopedCertificate.trust = KeeShareSettings::Trust::Untrusted; scopedCertificate.trust = KeeShareSettings::Trust::Untrusted;
} }
scopedCertificate.certificate = Certificate::deserialize(reader); scopedCertificate.certificate = Certificate::deserialize(reader);
@ -494,4 +494,4 @@ namespace KeeShareSettings
}); });
return sign; return sign;
} }
} } // namespace KeeShareSettings

View file

@ -99,7 +99,8 @@ namespace KeeShareSettings
static Own generate(); static Own generate();
}; };
enum class Trust { enum class Trust
{
Ask, Ask,
Untrusted, Untrusted,
Trusted Trusted
@ -113,8 +114,14 @@ namespace KeeShareSettings
bool operator==(const ScopedCertificate& other) const; bool operator==(const ScopedCertificate& other) const;
bool operator!=(const ScopedCertificate& other) const; bool operator!=(const ScopedCertificate& other) const;
bool isUnknown() const { return certificate.isNull(); } bool isUnknown() const
bool isKnown() const { return !certificate.isNull(); } {
return certificate.isNull();
}
bool isKnown() const
{
return !certificate.isNull();
}
static void serialize(QXmlStreamWriter& writer, const ScopedCertificate& certificate); static void serialize(QXmlStreamWriter& writer, const ScopedCertificate& certificate);
static ScopedCertificate deserialize(QXmlStreamReader& reader); static ScopedCertificate deserialize(QXmlStreamReader& reader);
@ -169,6 +176,6 @@ namespace KeeShareSettings
static QString serialize(const Reference& reference); static QString serialize(const Reference& reference);
static Reference deserialize(const QString& raw); static Reference deserialize(const QString& raw);
}; };
}; }; // namespace KeeShareSettings
#endif // KEEPASSXC_KEESHARESETTINGS_H #endif // KEEPASSXC_KEESHARESETTINGS_H

View file

@ -29,26 +29,26 @@
#include <QStandardItemModel> #include <QStandardItemModel>
SettingsWidgetKeeShare::SettingsWidgetKeeShare(QWidget* parent) SettingsWidgetKeeShare::SettingsWidgetKeeShare(QWidget* parent)
: QWidget(parent) : QWidget(parent)
, m_ui(new Ui::SettingsWidgetKeeShare()) , m_ui(new Ui::SettingsWidgetKeeShare())
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
#if !defined(WITH_XC_KEESHARE_SECURE) #if !defined(WITH_XC_KEESHARE_SECURE)
// Setting does not help the user of Version without signed export // Setting does not help the user of Version without signed export
m_ui->ownCertificateGroupBox->setVisible(false); m_ui->ownCertificateGroupBox->setVisible(false);
#endif #endif
connect(m_ui->ownCertificateSignerEdit, SIGNAL(textChanged(QString)), SLOT(setVerificationExporter(QString))); connect(m_ui->ownCertificateSignerEdit, SIGNAL(textChanged(QString)), SLOT(setVerificationExporter(QString)));
connect(m_ui->generateOwnCerticateButton, SIGNAL(clicked(bool)), SLOT(generateCertificate())); connect(m_ui->generateOwnCerticateButton, SIGNAL(clicked(bool)), SLOT(generateCertificate()));
connect(m_ui->importOwnCertificateButton, SIGNAL(clicked(bool)), SLOT(importCertificate())); connect(m_ui->importOwnCertificateButton, SIGNAL(clicked(bool)), SLOT(importCertificate()));
connect(m_ui->exportOwnCertificateButton, SIGNAL(clicked(bool)), SLOT(exportCertificate())); connect(m_ui->exportOwnCertificateButton, SIGNAL(clicked(bool)), SLOT(exportCertificate()));
connect(m_ui->trustImportedCertificateButton, SIGNAL(clicked(bool)), SLOT(trustSelectedCertificates())); connect(m_ui->trustImportedCertificateButton, SIGNAL(clicked(bool)), SLOT(trustSelectedCertificates()));
connect(m_ui->askImportedCertificateButton, SIGNAL(clicked(bool)), SLOT(askSelectedCertificates())); connect(m_ui->askImportedCertificateButton, SIGNAL(clicked(bool)), SLOT(askSelectedCertificates()));
connect(m_ui->untrustImportedCertificateButton, SIGNAL(clicked(bool)), SLOT(untrustSelectedCertificates())); connect(m_ui->untrustImportedCertificateButton, SIGNAL(clicked(bool)), SLOT(untrustSelectedCertificates()));
connect(m_ui->removeImportedCertificateButton, SIGNAL(clicked(bool)), SLOT(removeSelectedCertificates())); connect(m_ui->removeImportedCertificateButton, SIGNAL(clicked(bool)), SLOT(removeSelectedCertificates()));
} }
SettingsWidgetKeeShare::~SettingsWidgetKeeShare() SettingsWidgetKeeShare::~SettingsWidgetKeeShare()
@ -57,181 +57,189 @@ SettingsWidgetKeeShare::~SettingsWidgetKeeShare()
void SettingsWidgetKeeShare::loadSettings() void SettingsWidgetKeeShare::loadSettings()
{ {
const auto active = KeeShare::active(); const auto active = KeeShare::active();
m_ui->enableExportCheckBox->setChecked(active.out); m_ui->enableExportCheckBox->setChecked(active.out);
m_ui->enableImportCheckBox->setChecked(active.in); m_ui->enableImportCheckBox->setChecked(active.in);
m_own = KeeShare::own(); m_own = KeeShare::own();
updateOwnCertificate(); updateOwnCertificate();
m_foreign = KeeShare::foreign(); m_foreign = KeeShare::foreign();
updateForeignCertificates(); updateForeignCertificates();
} }
void SettingsWidgetKeeShare::updateForeignCertificates() void SettingsWidgetKeeShare::updateForeignCertificates()
{ {
m_importedCertificateModel.reset(new QStandardItemModel()); auto headers = QStringList() << tr("Path") << tr("Status");
m_importedCertificateModel->setHorizontalHeaderLabels(QStringList() << tr("Path") << tr("Status")
#if defined(WITH_XC_KEESHARE_SECURE) #if defined(WITH_XC_KEESHARE_SECURE)
<< tr("Signer") << tr("Fingerprint") << tr("Certificate") headers << tr("Signer") << tr("Fingerprint") << tr("Certificate");
#endif #endif
);
for (const auto& scopedCertificate : m_foreign.certificates) { m_importedCertificateModel.reset(new QStandardItemModel());
const auto items = QList<QStandardItem*>() m_importedCertificateModel->setHorizontalHeaderLabels(headers);
<< new QStandardItem(scopedCertificate.path)
<< new QStandardItem(scopedCertificate.trust == KeeShareSettings::Trust::Ask ? tr("Ask") for (const auto& scopedCertificate : m_foreign.certificates) {
: (scopedCertificate.trust == KeeShareSettings::Trust::Trusted ? tr("Trusted") const auto items = QList<QStandardItem*>()
: tr("Untrusted"))) << new QStandardItem(scopedCertificate.path)
<< new QStandardItem(scopedCertificate.trust == KeeShareSettings::Trust::Ask
? tr("Ask")
: (scopedCertificate.trust == KeeShareSettings::Trust::Trusted
? tr("Trusted")
: tr("Untrusted")))
#if defined(WITH_XC_KEESHARE_SECURE) #if defined(WITH_XC_KEESHARE_SECURE)
<< new QStandardItem(scopedCertificate.isKnown() ? scopedCertificate.certificate.signer : tr("Unknown")) << new QStandardItem(scopedCertificate.isKnown() ? scopedCertificate.certificate.signer
<< new QStandardItem(scopedCertificate.certificate.fingerprint()) : tr("Unknown"))
<< new QStandardItem(scopedCertificate.certificate.publicKey()) << new QStandardItem(scopedCertificate.certificate.fingerprint())
<< new QStandardItem(scopedCertificate.certificate.publicKey())
#endif #endif
; ;
m_importedCertificateModel->appendRow(items); m_importedCertificateModel->appendRow(items);
} }
m_ui->importedCertificateTableView->setModel(m_importedCertificateModel.data()); m_ui->importedCertificateTableView->setModel(m_importedCertificateModel.data());
m_ui->importedCertificateTableView->resizeColumnsToContents();
} }
void SettingsWidgetKeeShare::updateOwnCertificate() void SettingsWidgetKeeShare::updateOwnCertificate()
{ {
m_ui->ownCertificateSignerEdit->setText(m_own.certificate.signer); m_ui->ownCertificateSignerEdit->setText(m_own.certificate.signer);
m_ui->ownCertificatePublicKeyEdit->setText(m_own.certificate.publicKey()); m_ui->ownCertificatePublicKeyEdit->setText(m_own.certificate.publicKey());
m_ui->ownCertificatePrivateKeyEdit->setText(m_own.key.privateKey()); m_ui->ownCertificatePrivateKeyEdit->setText(m_own.key.privateKey());
m_ui->ownCertificateFingerprintEdit->setText(m_own.certificate.fingerprint()); m_ui->ownCertificateFingerprintEdit->setText(m_own.certificate.fingerprint());
} }
void SettingsWidgetKeeShare::saveSettings() void SettingsWidgetKeeShare::saveSettings()
{ {
KeeShareSettings::Active active; KeeShareSettings::Active active;
active.out = m_ui->enableExportCheckBox->isChecked(); active.out = m_ui->enableExportCheckBox->isChecked();
active.in = m_ui->enableImportCheckBox->isChecked(); active.in = m_ui->enableImportCheckBox->isChecked();
// TODO HNH: This depends on the order of saving new data - a better model would be to // TODO HNH: This depends on the order of saving new data - a better model would be to
// store changes to the settings in a temporary object and check on the final values // store changes to the settings in a temporary object and check on the final values
// of this object (similar scheme to Entry) - this way we could validate the settings before save // of this object (similar scheme to Entry) - this way we could validate the settings before save
KeeShare::setOwn(m_own); KeeShare::setOwn(m_own);
KeeShare::setForeign(m_foreign); KeeShare::setForeign(m_foreign);
KeeShare::setActive(active); KeeShare::setActive(active);
} }
void SettingsWidgetKeeShare::setVerificationExporter(const QString& signer) void SettingsWidgetKeeShare::setVerificationExporter(const QString& signer)
{ {
m_own.certificate.signer = signer; m_own.certificate.signer = signer;
m_ui->ownCertificateSignerEdit->setText(m_own.certificate.signer); m_ui->ownCertificateSignerEdit->setText(m_own.certificate.signer);
} }
void SettingsWidgetKeeShare::generateCertificate() void SettingsWidgetKeeShare::generateCertificate()
{ {
m_own = KeeShareSettings::Own::generate(); m_own = KeeShareSettings::Own::generate();
m_ui->ownCertificateSignerEdit->setText(m_own.certificate.signer); m_ui->ownCertificateSignerEdit->setText(m_own.certificate.signer);
m_ui->ownCertificatePublicKeyEdit->setText(m_own.certificate.publicKey()); m_ui->ownCertificatePublicKeyEdit->setText(m_own.certificate.publicKey());
m_ui->ownCertificatePrivateKeyEdit->setText(m_own.key.privateKey()); m_ui->ownCertificatePrivateKeyEdit->setText(m_own.key.privateKey());
m_ui->ownCertificateFingerprintEdit->setText(m_own.certificate.fingerprint()); m_ui->ownCertificateFingerprintEdit->setText(m_own.certificate.fingerprint());
} }
void SettingsWidgetKeeShare::importCertificate() void SettingsWidgetKeeShare::importCertificate()
{ {
QString defaultDirPath = config()->get("KeeShare/LastKeyDir").toString(); QString defaultDirPath = config()->get("KeeShare/LastKeyDir").toString();
const bool dirExists = !defaultDirPath.isEmpty() && QDir(defaultDirPath).exists(); const bool dirExists = !defaultDirPath.isEmpty() && QDir(defaultDirPath).exists();
if (!dirExists) { if (!dirExists) {
defaultDirPath = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first(); defaultDirPath = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first();
} }
const auto filetype = tr("key.share", "Filetype for KeeShare key"); const auto filetype = tr("key.share", "Filetype for KeeShare key");
const auto filters = QString("%1 (*." + filetype + ");;%2 (*)").arg(tr("KeeShare key file"), tr("All files")); const auto filters = QString("%1 (*." + filetype + ");;%2 (*)").arg(tr("KeeShare key file"), tr("All files"));
QString filename = fileDialog()->getOpenFileName(this, tr("Select path"), defaultDirPath, filters, nullptr, QFileDialog::Options(0)); QString filename = fileDialog()->getOpenFileName(
if (filename.isEmpty()) { this, tr("Select path"), defaultDirPath, filters, nullptr, QFileDialog::Options(0));
return; if (filename.isEmpty()) {
} return;
QFile file(filename); }
file.open(QIODevice::ReadOnly); QFile file(filename);
QTextStream stream(&file); file.open(QIODevice::ReadOnly);
m_own = KeeShareSettings::Own::deserialize(stream.readAll()); QTextStream stream(&file);
file.close(); m_own = KeeShareSettings::Own::deserialize(stream.readAll());
config()->set("KeeShare/LastKeyDir", QFileInfo(filename).absolutePath()); file.close();
config()->set("KeeShare/LastKeyDir", QFileInfo(filename).absolutePath());
updateOwnCertificate(); updateOwnCertificate();
} }
void SettingsWidgetKeeShare::exportCertificate() void SettingsWidgetKeeShare::exportCertificate()
{ {
if (KeeShare::own() != m_own) { if (KeeShare::own() != m_own) {
QMessageBox warning; QMessageBox warning;
warning.setIcon(QMessageBox::Warning); warning.setIcon(QMessageBox::Warning);
warning.setWindowTitle(tr("Exporting changed certificate")); warning.setWindowTitle(tr("Exporting changed certificate"));
warning.setText(tr("The exported certificate is not the same as the one in use. Do you want to export the current certificate?")); warning.setText(tr("The exported certificate is not the same as the one in use. Do you want to export the "
auto yes = warning.addButton(QMessageBox::StandardButton::Yes); "current certificate?"));
auto no = warning.addButton(QMessageBox::StandardButton::No); auto yes = warning.addButton(QMessageBox::StandardButton::Yes);
warning.setDefaultButton(no); auto no = warning.addButton(QMessageBox::StandardButton::No);
warning.exec(); warning.setDefaultButton(no);
if (warning.clickedButton() != yes) { warning.exec();
return; if (warning.clickedButton() != yes) {
} return;
} }
QString defaultDirPath = config()->get("KeeShare/LastKeyDir").toString(); }
const bool dirExists = !defaultDirPath.isEmpty() && QDir(defaultDirPath).exists(); QString defaultDirPath = config()->get("KeeShare/LastKeyDir").toString();
if (!dirExists) { const bool dirExists = !defaultDirPath.isEmpty() && QDir(defaultDirPath).exists();
defaultDirPath = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first(); if (!dirExists) {
} defaultDirPath = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first();
const auto filetype = tr("key.share", "Filetype for KeeShare key"); }
const auto filters = QString("%1 (*." + filetype + ");;%2 (*)").arg(tr("KeeShare key file"), tr("All files")); const auto filetype = tr("key.share", "Filetype for KeeShare key");
QString filename = tr("%1.%2", "Template for KeeShare key file").arg(m_own.certificate.signer).arg(filetype); const auto filters = QString("%1 (*." + filetype + ");;%2 (*)").arg(tr("KeeShare key file"), tr("All files"));
filename = fileDialog()->getSaveFileName(this, tr("Select path"), defaultDirPath, filters, nullptr, QFileDialog::Options(0), filetype, filename); QString filename = tr("%1.%2", "Template for KeeShare key file").arg(m_own.certificate.signer).arg(filetype);
if (filename.isEmpty()) { filename = fileDialog()->getSaveFileName(
return; this, tr("Select path"), defaultDirPath, filters, nullptr, QFileDialog::Options(0), filetype, filename);
} if (filename.isEmpty()) {
QFile file(filename); return;
file.open(QIODevice::Truncate | QIODevice::WriteOnly); }
QTextStream stream(&file); QFile file(filename);
stream << KeeShareSettings::Own::serialize(m_own); file.open(QIODevice::Truncate | QIODevice::WriteOnly);
stream.flush(); QTextStream stream(&file);
file.close(); stream << KeeShareSettings::Own::serialize(m_own);
config()->set("KeeShare/LastKeyDir", QFileInfo(filename).absolutePath()); stream.flush();
file.close();
config()->set("KeeShare/LastKeyDir", QFileInfo(filename).absolutePath());
} }
void SettingsWidgetKeeShare::trustSelectedCertificates() void SettingsWidgetKeeShare::trustSelectedCertificates()
{ {
const auto* selectionModel = m_ui->importedCertificateTableView->selectionModel(); const auto* selectionModel = m_ui->importedCertificateTableView->selectionModel();
Q_ASSERT(selectionModel); Q_ASSERT(selectionModel);
for (const auto& index : selectionModel->selectedRows()) { for (const auto& index : selectionModel->selectedRows()) {
m_foreign.certificates[index.row()].trust = KeeShareSettings::Trust::Trusted; m_foreign.certificates[index.row()].trust = KeeShareSettings::Trust::Trusted;
} }
updateForeignCertificates(); updateForeignCertificates();
} }
void SettingsWidgetKeeShare::askSelectedCertificates() void SettingsWidgetKeeShare::askSelectedCertificates()
{ {
const auto* selectionModel = m_ui->importedCertificateTableView->selectionModel(); const auto* selectionModel = m_ui->importedCertificateTableView->selectionModel();
Q_ASSERT(selectionModel); Q_ASSERT(selectionModel);
for (const auto& index : selectionModel->selectedRows()) { for (const auto& index : selectionModel->selectedRows()) {
m_foreign.certificates[index.row()].trust = KeeShareSettings::Trust::Ask; m_foreign.certificates[index.row()].trust = KeeShareSettings::Trust::Ask;
} }
updateForeignCertificates(); updateForeignCertificates();
} }
void SettingsWidgetKeeShare::untrustSelectedCertificates() void SettingsWidgetKeeShare::untrustSelectedCertificates()
{ {
const auto* selectionModel = m_ui->importedCertificateTableView->selectionModel(); const auto* selectionModel = m_ui->importedCertificateTableView->selectionModel();
Q_ASSERT(selectionModel); Q_ASSERT(selectionModel);
for (const auto& index : selectionModel->selectedRows()) { for (const auto& index : selectionModel->selectedRows()) {
m_foreign.certificates[index.row()].trust = KeeShareSettings::Trust::Untrusted; m_foreign.certificates[index.row()].trust = KeeShareSettings::Trust::Untrusted;
} }
updateForeignCertificates(); updateForeignCertificates();
} }
void SettingsWidgetKeeShare::removeSelectedCertificates() void SettingsWidgetKeeShare::removeSelectedCertificates()
{ {
auto certificates = m_foreign.certificates; auto certificates = m_foreign.certificates;
const auto* selectionModel = m_ui->importedCertificateTableView->selectionModel(); const auto* selectionModel = m_ui->importedCertificateTableView->selectionModel();
Q_ASSERT(selectionModel); Q_ASSERT(selectionModel);
for (const auto& index : selectionModel->selectedRows()) { for (const auto& index : selectionModel->selectedRows()) {
certificates.removeOne(m_foreign.certificates[index.row()]); certificates.removeOne(m_foreign.certificates[index.row()]);
} }
m_foreign.certificates = certificates; m_foreign.certificates = certificates;
updateForeignCertificates(); updateForeignCertificates();
} }

View file

@ -51,105 +51,111 @@
namespace namespace
{ {
static const QString KeeShare_Signature("container.share.signature"); static const QString KeeShare_Signature("container.share.signature");
static const QString KeeShare_Container("container.share.kdbx"); static const QString KeeShare_Container("container.share.kdbx");
enum Trust enum Trust
{ {
Invalid, Invalid,
Own, Own,
UntrustedForever, UntrustedForever,
UntrustedOnce, UntrustedOnce,
TrustedOnce, TrustedOnce,
TrustedForever, TrustedForever,
}; };
bool isOfExportType(const QFileInfo &fileInfo, const QString type) bool isOfExportType(const QFileInfo& fileInfo, const QString type)
{ {
return fileInfo.fileName().endsWith(type, Qt::CaseInsensitive); return fileInfo.fileName().endsWith(type, Qt::CaseInsensitive);
} }
QPair<Trust, KeeShareSettings::Certificate> check(QByteArray& data, QPair<Trust, KeeShareSettings::Certificate>
const KeeShareSettings::Reference& reference, check(QByteArray& data,
const KeeShareSettings::Certificate& ownCertificate, const KeeShareSettings::Reference& reference,
const QList<KeeShareSettings::ScopedCertificate>& knownCertificates, const KeeShareSettings::Certificate& ownCertificate,
const KeeShareSettings::Sign& sign) const QList<KeeShareSettings::ScopedCertificate>& knownCertificates,
{ const KeeShareSettings::Sign& sign)
KeeShareSettings::Certificate certificate; {
if (!sign.signature.isEmpty()) { KeeShareSettings::Certificate certificate;
certificate = sign.certificate; if (!sign.signature.isEmpty()) {
auto key = sign.certificate.sshKey(); certificate = sign.certificate;
key.openKey(QString()); auto key = sign.certificate.sshKey();
const auto signer = Signature(); key.openKey(QString());
if (!signer.verify(data, sign.signature, key)) { const auto signer = Signature();
if (!signer.verify(data, sign.signature, key)) {
qCritical("Invalid signature for sharing container %s.", qPrintable(reference.path)); qCritical("Invalid signature for sharing container %s.", qPrintable(reference.path));
return {Invalid, KeeShareSettings::Certificate()}; return {Invalid, KeeShareSettings::Certificate()};
} }
if (ownCertificate.key == sign.certificate.key) { if (ownCertificate.key == sign.certificate.key) {
return {Own, ownCertificate }; return {Own, ownCertificate};
} }
} }
enum Scope { Invalid, Global, Local }; enum Scope
Scope scope = Invalid; {
KeeShareSettings::Trust trusted = KeeShareSettings::Trust::Ask; Invalid,
for (const auto& scopedCertificate : knownCertificates) { Global,
if (scopedCertificate.certificate.key == certificate.key && scopedCertificate.path == reference.path) { Local
};
Scope scope = Invalid;
KeeShareSettings::Trust trusted = KeeShareSettings::Trust::Ask;
for (const auto& scopedCertificate : knownCertificates) {
if (scopedCertificate.certificate.key == certificate.key && scopedCertificate.path == reference.path) {
// Global scope is overwritten by local scope // Global scope is overwritten by local scope
scope = Global; scope = Global;
trusted = scopedCertificate.trust; trusted = scopedCertificate.trust;
} }
if (scopedCertificate.certificate.key == certificate.key && scopedCertificate.path == reference.path) { if (scopedCertificate.certificate.key == certificate.key && scopedCertificate.path == reference.path) {
scope = Local; scope = Local;
trusted = scopedCertificate.trust; trusted = scopedCertificate.trust;
break; break;
} }
} }
if (scope != Invalid && trusted != KeeShareSettings::Trust::Ask){ if (scope != Invalid && trusted != KeeShareSettings::Trust::Ask) {
// we introduce now scopes if there is a global // we introduce now scopes if there is a global
return {trusted == KeeShareSettings::Trust::Trusted ? TrustedForever : UntrustedForever, certificate}; return {trusted == KeeShareSettings::Trust::Trusted ? TrustedForever : UntrustedForever, certificate};
} }
QMessageBox warning; QMessageBox warning;
if (sign.signature.isEmpty()){ if (sign.signature.isEmpty()) {
warning.setIcon(QMessageBox::Warning); warning.setIcon(QMessageBox::Warning);
warning.setWindowTitle(ShareObserver::tr("Import from container without signature")); warning.setWindowTitle(ShareObserver::tr("Import from container without signature"));
warning.setText(ShareObserver::tr("We cannot verify the source of the shared container because it is not signed. Do you really want to import from %1?") warning.setText(ShareObserver::tr("We cannot verify the source of the shared container because it is not "
"signed. Do you really want to import from %1?")
.arg(reference.path)); .arg(reference.path));
} } else {
else { warning.setIcon(QMessageBox::Question);
warning.setIcon(QMessageBox::Question); warning.setWindowTitle(ShareObserver::tr("Import from container with certificate"));
warning.setWindowTitle(ShareObserver::tr("Import from container with certificate")); warning.setText(ShareObserver::tr("Do you want to trust %1 with the fingerprint of %2 from %3")
warning.setText(ShareObserver::tr("Do you want to trust %1 with the fingerprint of %2 from %3")
.arg(certificate.signer, certificate.fingerprint(), reference.path)); .arg(certificate.signer, certificate.fingerprint(), reference.path));
} }
auto untrustedOnce = warning.addButton(ShareObserver::tr("Not this time"), QMessageBox::ButtonRole::NoRole); auto untrustedOnce = warning.addButton(ShareObserver::tr("Not this time"), QMessageBox::ButtonRole::NoRole);
auto untrustedForever = warning.addButton(ShareObserver::tr("Never"), QMessageBox::ButtonRole::NoRole); auto untrustedForever = warning.addButton(ShareObserver::tr("Never"), QMessageBox::ButtonRole::NoRole);
auto trustedForever = warning.addButton(ShareObserver::tr("Always"), QMessageBox::ButtonRole::YesRole); auto trustedForever = warning.addButton(ShareObserver::tr("Always"), QMessageBox::ButtonRole::YesRole);
auto trustedOnce = warning.addButton(ShareObserver::tr("Just this time"), QMessageBox::ButtonRole::YesRole); auto trustedOnce = warning.addButton(ShareObserver::tr("Just this time"), QMessageBox::ButtonRole::YesRole);
warning.setDefaultButton(untrustedOnce); warning.setDefaultButton(untrustedOnce);
warning.exec(); warning.exec();
if (warning.clickedButton() == trustedForever){ if (warning.clickedButton() == trustedForever) {
return {TrustedForever, certificate }; return {TrustedForever, certificate};
} }
if (warning.clickedButton() == trustedOnce){ if (warning.clickedButton() == trustedOnce) {
return {TrustedOnce, certificate}; return {TrustedOnce, certificate};
} }
if (warning.clickedButton() == untrustedOnce){ if (warning.clickedButton() == untrustedOnce) {
return {UntrustedOnce, certificate }; return {UntrustedOnce, certificate};
} }
if (warning.clickedButton() == untrustedForever){ if (warning.clickedButton() == untrustedForever) {
return {UntrustedForever, certificate }; return {UntrustedForever, certificate};
} }
return {UntrustedOnce, certificate }; return {UntrustedOnce, certificate};
} }
} // End Namespace } // End Namespace
ShareObserver::ShareObserver(QSharedPointer<Database> db, QObject* parent) ShareObserver::ShareObserver(QSharedPointer<Database> db, QObject* parent)
: QObject(parent) : QObject(parent)
, m_db(std::move(db)) , m_db(std::move(db))
, m_fileWatcher(new BulkFileWatcher(this)) , m_fileWatcher(new BulkFileWatcher(this))
{ {
connect(KeeShare::instance(), SIGNAL(activeChanged()), SLOT(handleDatabaseChanged())); connect(KeeShare::instance(), SIGNAL(activeChanged()), SLOT(handleDatabaseChanged()));
@ -195,8 +201,9 @@ void ShareObserver::reinitialize()
m_groupToReference.remove(couple.group); m_groupToReference.remove(couple.group);
m_referenceToGroup.remove(couple.oldReference); m_referenceToGroup.remove(couple.oldReference);
m_shareToGroup.remove(couple.oldReference.path); m_shareToGroup.remove(couple.oldReference.path);
if (couple.newReference.isValid() && ((active.in && couple.newReference.isImporting()) if (couple.newReference.isValid()
|| (active.out && couple.newReference.isExporting()))) { && ((active.in && couple.newReference.isImporting())
|| (active.out && couple.newReference.isExporting()))) {
m_groupToReference[couple.group] = couple.newReference; m_groupToReference[couple.group] = couple.newReference;
m_referenceToGroup[couple.newReference] = couple.group; m_referenceToGroup[couple.newReference] = couple.group;
m_shareToGroup[couple.newReference.path] = couple.group; m_shareToGroup[couple.newReference.path] = couple.group;
@ -213,27 +220,27 @@ void ShareObserver::reinitialize()
} }
if (!update.newReference.path.isEmpty() && update.newReference.type != KeeShareSettings::Inactive) { if (!update.newReference.path.isEmpty() && update.newReference.type != KeeShareSettings::Inactive) {
m_fileWatcher->addPath(update.newReference.path); m_fileWatcher->addPath(update.newReference.path);
} }
if (update.newReference.isImporting()) { if (update.newReference.isImporting()) {
const auto result = this->importFromReferenceContainer(update.newReference.path); const auto result = this->importFromReferenceContainer(update.newReference.path);
if (!result.isValid()) { if (!result.isValid()) {
// tolerable result - blocked import or missing source // tolerable result - blocked import or missing source
continue; continue;
} }
if (result.isError()) { if (result.isError()) {
error << tr("Import from %1 failed (%2)").arg(result.path).arg(result.message); error << tr("Import from %1 failed (%2)").arg(result.path).arg(result.message);
} else if (result.isWarning()) { } else if (result.isWarning()) {
warning << tr("Import from %1 failed (%2)").arg(result.path).arg(result.message); warning << tr("Import from %1 failed (%2)").arg(result.path).arg(result.message);
} else if (result.isInfo()) { } else if (result.isInfo()) {
success << tr("Import from %1 successful (%2)").arg(result.path).arg(result.message); success << tr("Import from %1 successful (%2)").arg(result.path).arg(result.message);
} else { } else {
success << tr("Imported from %1").arg(result.path); success << tr("Imported from %1").arg(result.path);
} }
} }
} }
notifyAbout(success, warning, error); notifyAbout(success, warning, error);
} }
@ -301,11 +308,12 @@ void ShareObserver::handleFileUpdated(const QString& path)
notifyAbout(success, warning, error); notifyAbout(success, warning, error);
} }
ShareObserver::Result ShareObserver::importSingedContainerInto(const KeeShareSettings::Reference& reference, Group* targetGroup) ShareObserver::Result ShareObserver::importSingedContainerInto(const KeeShareSettings::Reference& reference,
Group* targetGroup)
{ {
#if !defined(WITH_XC_KEESHARE_SECURE) #if !defined(WITH_XC_KEESHARE_SECURE)
Q_UNUSED(targetGroup); Q_UNUSED(targetGroup);
return { reference.path, Result::Warning, tr("Signed share container are not supported - import prevented") }; return {reference.path, Result::Warning, tr("Signed share container are not supported - import prevented")};
#else #else
QuaZip zip(reference.path); QuaZip zip(reference.path);
if (!zip.open(QuaZip::mdUnzip)) { if (!zip.open(QuaZip::mdUnzip)) {
@ -359,25 +367,26 @@ ShareObserver::Result ShareObserver::importSingedContainerInto(const KeeShareSet
case UntrustedForever: case UntrustedForever:
case TrustedForever: { case TrustedForever: {
bool found = false; bool found = false;
const auto trusted = trust.first == TrustedForever ? KeeShareSettings::Trust::Trusted : KeeShareSettings::Trust::Untrusted; const auto trusted =
trust.first == TrustedForever ? KeeShareSettings::Trust::Trusted : KeeShareSettings::Trust::Untrusted;
for (KeeShareSettings::ScopedCertificate& scopedCertificate : foreign.certificates) { for (KeeShareSettings::ScopedCertificate& scopedCertificate : foreign.certificates) {
if (scopedCertificate.certificate.key == trust.second.key && scopedCertificate.path == reference.path) { if (scopedCertificate.certificate.key == trust.second.key && scopedCertificate.path == reference.path) {
scopedCertificate.certificate.signer = trust.second.signer; scopedCertificate.certificate.signer = trust.second.signer;
scopedCertificate.path = reference.path; scopedCertificate.path = reference.path;
scopedCertificate.trust = trusted; scopedCertificate.trust = trusted;
found = true; found = true;
} }
} }
if (!found) { if (!found) {
foreign.certificates << KeeShareSettings::ScopedCertificate{ reference.path, trust.second, trusted}; foreign.certificates << KeeShareSettings::ScopedCertificate{reference.path, trust.second, trusted};
// we need to update with the new signer // we need to update with the new signer
KeeShare::setForeign(foreign); KeeShare::setForeign(foreign);
} }
if (trust.first == TrustedForever) { if (trust.first == TrustedForever) {
qDebug("Synchronize %s %s with %s", qDebug("Synchronize %s %s with %s",
qPrintable(reference.path), qPrintable(reference.path),
qPrintable(targetGroup->name()), qPrintable(targetGroup->name()),
qPrintable(sourceDb->rootGroup()->name())); qPrintable(sourceDb->rootGroup()->name()));
Merger merger(sourceDb->rootGroup(), targetGroup); Merger merger(sourceDb->rootGroup(), targetGroup);
merger.setForcedMergeMode(Group::Synchronize); merger.setForcedMergeMode(Group::Synchronize);
const bool changed = merger.merge(); const bool changed = merger.merge();
@ -391,16 +400,16 @@ ShareObserver::Result ShareObserver::importSingedContainerInto(const KeeShareSet
case TrustedOnce: case TrustedOnce:
case Own: { case Own: {
qDebug("Synchronize %s %s with %s", qDebug("Synchronize %s %s with %s",
qPrintable(reference.path), qPrintable(reference.path),
qPrintable(targetGroup->name()), qPrintable(targetGroup->name()),
qPrintable(sourceDb->rootGroup()->name())); qPrintable(sourceDb->rootGroup()->name()));
Merger merger(sourceDb->rootGroup(), targetGroup); Merger merger(sourceDb->rootGroup(), targetGroup);
merger.setForcedMergeMode(Group::Synchronize); merger.setForcedMergeMode(Group::Synchronize);
const bool changed = merger.merge(); const bool changed = merger.merge();
if (changed) { if (changed) {
return {reference.path, Result::Success, tr("Successful signed import")}; return {reference.path, Result::Success, tr("Successful signed import")};
} }
return {}; return {};
} }
default: default:
Q_ASSERT(false); Q_ASSERT(false);
@ -409,14 +418,15 @@ ShareObserver::Result ShareObserver::importSingedContainerInto(const KeeShareSet
#endif #endif
} }
ShareObserver::Result ShareObserver::importUnsignedContainerInto(const KeeShareSettings::Reference& reference, Group* targetGroup) ShareObserver::Result ShareObserver::importUnsignedContainerInto(const KeeShareSettings::Reference& reference,
Group* targetGroup)
{ {
#if !defined(WITH_XC_KEESHARE_INSECURE) #if !defined(WITH_XC_KEESHARE_INSECURE)
Q_UNUSED(targetGroup); Q_UNUSED(targetGroup);
return {reference.path, Result::Warning, tr("Unsigned share container are not supported - import prevented")}; return {reference.path, Result::Warning, tr("Unsigned share container are not supported - import prevented")};
#else #else
QFile file(reference.path); QFile file(reference.path);
if (!file.open(QIODevice::ReadOnly)){ if (!file.open(QIODevice::ReadOnly)) {
qCritical("Unable to open file %s.", qPrintable(reference.path)); qCritical("Unable to open file %s.", qPrintable(reference.path));
return {reference.path, Result::Error, tr("File is not readable")}; return {reference.path, Result::Error, tr("File is not readable")};
} }
@ -438,34 +448,35 @@ ShareObserver::Result ShareObserver::importUnsignedContainerInto(const KeeShareS
const auto own = KeeShare::own(); const auto own = KeeShare::own();
const auto sign = KeeShareSettings::Sign(); // invalid sign const auto sign = KeeShareSettings::Sign(); // invalid sign
auto trust = check(payload, reference, own.certificate, foreign.certificates, sign); auto trust = check(payload, reference, own.certificate, foreign.certificates, sign);
switch(trust.first) { switch (trust.first) {
case UntrustedForever: case UntrustedForever:
case TrustedForever: { case TrustedForever: {
bool found = false; bool found = false;
const auto trusted = trust.first == TrustedForever ? KeeShareSettings::Trust::Trusted : KeeShareSettings::Trust::Untrusted; const auto trusted =
trust.first == TrustedForever ? KeeShareSettings::Trust::Trusted : KeeShareSettings::Trust::Untrusted;
for (KeeShareSettings::ScopedCertificate& scopedCertificate : foreign.certificates) { for (KeeShareSettings::ScopedCertificate& scopedCertificate : foreign.certificates) {
if (scopedCertificate.certificate.key == trust.second.key && scopedCertificate.path == reference.path) { if (scopedCertificate.certificate.key == trust.second.key && scopedCertificate.path == reference.path) {
scopedCertificate.certificate.signer = trust.second.signer; scopedCertificate.certificate.signer = trust.second.signer;
scopedCertificate.path = reference.path; scopedCertificate.path = reference.path;
scopedCertificate.trust = trusted; scopedCertificate.trust = trusted;
found = true; found = true;
} }
} }
if (!found) { if (!found) {
foreign.certificates << KeeShareSettings::ScopedCertificate{ reference.path, trust.second, trusted}; foreign.certificates << KeeShareSettings::ScopedCertificate{reference.path, trust.second, trusted};
// we need to update with the new signer // we need to update with the new signer
KeeShare::setForeign(foreign); KeeShare::setForeign(foreign);
} }
if (trust.first == TrustedForever) { if (trust.first == TrustedForever) {
qDebug("Synchronize %s %s with %s", qDebug("Synchronize %s %s with %s",
qPrintable(reference.path), qPrintable(reference.path),
qPrintable(targetGroup->name()), qPrintable(targetGroup->name()),
qPrintable(sourceDb->rootGroup()->name())); qPrintable(sourceDb->rootGroup()->name()));
Merger merger(sourceDb->rootGroup(), targetGroup); Merger merger(sourceDb->rootGroup(), targetGroup);
merger.setForcedMergeMode(Group::Synchronize); merger.setForcedMergeMode(Group::Synchronize);
const bool changed = merger.merge(); const bool changed = merger.merge();
if (changed) { if (changed) {
return {reference.path, Result::Success, tr("Successful signed import")}; return {reference.path, Result::Success, tr("Successful signed import")};
} }
} }
return {}; return {};
@ -491,7 +502,8 @@ ShareObserver::Result ShareObserver::importUnsignedContainerInto(const KeeShareS
#endif #endif
} }
ShareObserver::Result ShareObserver::importContainerInto(const KeeShareSettings::Reference& reference, Group* targetGroup) ShareObserver::Result ShareObserver::importContainerInto(const KeeShareSettings::Reference& reference,
Group* targetGroup)
{ {
const QFileInfo info(reference.path); const QFileInfo info(reference.path);
if (!info.exists()) { if (!info.exists()) {
@ -601,7 +613,7 @@ Database* ShareObserver::exportIntoContainer(const KeeShareSettings::Reference&
} }
for (auto* targetEntry : targetRoot->entriesRecursive(false)) { for (auto* targetEntry : targetRoot->entriesRecursive(false)) {
if (targetEntry->hasReferences()) { if (targetEntry->hasReferences()) {
resolveReferenceAttributes(targetEntry, sourceDb); resolveReferenceAttributes(targetEntry, sourceDb);
} }
} }
return targetDb; return targetDb;
@ -612,11 +624,13 @@ QSharedPointer<Database> ShareObserver::database()
return m_db; return m_db;
} }
ShareObserver::Result ShareObserver::exportIntoReferenceSignedContainer(const KeeShareSettings::Reference &reference, Database *targetDb) ShareObserver::Result ShareObserver::exportIntoReferenceSignedContainer(const KeeShareSettings::Reference& reference,
Database* targetDb)
{ {
#if !defined(WITH_XC_KEESHARE_SECURE) #if !defined(WITH_XC_KEESHARE_SECURE)
Q_UNUSED(targetDb); Q_UNUSED(targetDb);
return {reference.path, Result::Warning, tr("Overwriting signed share container is not supported - export prevented")}; return {
reference.path, Result::Warning, tr("Overwriting signed share container is not supported - export prevented")};
#else #else
QByteArray bytes; QByteArray bytes;
{ {
@ -657,7 +671,7 @@ ShareObserver::Result ShareObserver::exportIntoReferenceSignedContainer(const Ke
::qWarning("Embedding signature failed: %d", zip.getZipError()); ::qWarning("Embedding signature failed: %d", zip.getZipError());
return {reference.path, Result::Error, tr("Could not embed signature (%1)").arg(file.getZipError())}; return {reference.path, Result::Error, tr("Could not embed signature (%1)").arg(file.getZipError())};
} }
file.close(); file.close();
} }
{ {
QuaZipFile file(&zip); QuaZipFile file(&zip);
@ -678,11 +692,14 @@ ShareObserver::Result ShareObserver::exportIntoReferenceSignedContainer(const Ke
#endif #endif
} }
ShareObserver::Result ShareObserver::exportIntoReferenceUnsignedContainer(const KeeShareSettings::Reference &reference, Database *targetDb) ShareObserver::Result ShareObserver::exportIntoReferenceUnsignedContainer(const KeeShareSettings::Reference& reference,
Database* targetDb)
{ {
#if !defined(WITH_XC_KEESHARE_INSECURE) #if !defined(WITH_XC_KEESHARE_INSECURE)
Q_UNUSED(targetDb); Q_UNUSED(targetDb);
return {reference.path, Result::Warning, tr("Overwriting unsigned share container is not supported - export prevented")}; return {reference.path,
Result::Warning,
tr("Overwriting unsigned share container is not supported - export prevented")};
#else #else
QFile file(reference.path); QFile file(reference.path);
const bool fileOpened = file.open(QIODevice::WriteOnly); const bool fileOpened = file.open(QIODevice::WriteOnly);

View file

@ -35,7 +35,7 @@ class Database;
class ShareObserver : public QObject class ShareObserver : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit ShareObserver(QSharedPointer<Database> db, QObject* parent = nullptr); explicit ShareObserver(QSharedPointer<Database> db, QObject* parent = nullptr);
@ -79,8 +79,9 @@ private:
static void resolveReferenceAttributes(Entry* targetEntry, const Database* sourceDb); static void resolveReferenceAttributes(Entry* targetEntry, const Database* sourceDb);
static Database* exportIntoContainer(const KeeShareSettings::Reference& reference, const Group* sourceRoot); static Database* exportIntoContainer(const KeeShareSettings::Reference& reference, const Group* sourceRoot);
static Result exportIntoReferenceUnsignedContainer(const KeeShareSettings::Reference &reference, Database *targetDb); static Result exportIntoReferenceUnsignedContainer(const KeeShareSettings::Reference& reference,
static Result exportIntoReferenceSignedContainer(const KeeShareSettings::Reference &reference, Database *targetDb); Database* targetDb);
static Result exportIntoReferenceSignedContainer(const KeeShareSettings::Reference& reference, Database* targetDb);
static Result importSingedContainerInto(const KeeShareSettings::Reference& reference, Group* targetGroup); static Result importSingedContainerInto(const KeeShareSettings::Reference& reference, Group* targetGroup);
static Result importUnsignedContainerInto(const KeeShareSettings::Reference& reference, Group* targetGroup); static Result importUnsignedContainerInto(const KeeShareSettings::Reference& reference, Group* targetGroup);
static Result importContainerInto(const KeeShareSettings::Reference& reference, Group* targetGroup); static Result importContainerInto(const KeeShareSettings::Reference& reference, Group* targetGroup);

View file

@ -31,54 +31,53 @@
#include <QStandardPaths> #include <QStandardPaths>
EditGroupWidgetKeeShare::EditGroupWidgetKeeShare(QWidget* parent) EditGroupWidgetKeeShare::EditGroupWidgetKeeShare(QWidget* parent)
: QWidget(parent) : QWidget(parent)
, m_ui(new Ui::EditGroupWidgetKeeShare()) , m_ui(new Ui::EditGroupWidgetKeeShare())
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
m_ui->togglePasswordButton->setIcon(filePath()->onOffIcon("actions", "password-show")); m_ui->togglePasswordButton->setIcon(filePath()->onOffIcon("actions", "password-show"));
m_ui->togglePasswordGeneratorButton->setIcon(filePath()->icon("actions", "password-generator", false)); m_ui->togglePasswordGeneratorButton->setIcon(filePath()->icon("actions", "password-generator", false));
m_ui->passwordGenerator->layout()->setContentsMargins(0, 0, 0, 0); m_ui->passwordGenerator->layout()->setContentsMargins(0, 0, 0, 0);
m_ui->passwordGenerator->hide(); m_ui->passwordGenerator->hide();
m_ui->passwordGenerator->reset(); m_ui->passwordGenerator->reset();
m_ui->messageWidget->hide(); m_ui->messageWidget->hide();
m_ui->messageWidget->setCloseButtonVisible(false); m_ui->messageWidget->setCloseButtonVisible(false);
m_ui->messageWidget->setAutoHideTimeout(-1); m_ui->messageWidget->setAutoHideTimeout(-1);
connect(m_ui->togglePasswordButton, SIGNAL(toggled(bool)), m_ui->passwordEdit, SLOT(setShowPassword(bool))); connect(m_ui->togglePasswordButton, SIGNAL(toggled(bool)), m_ui->passwordEdit, SLOT(setShowPassword(bool)));
connect(m_ui->togglePasswordGeneratorButton, SIGNAL(toggled(bool)), SLOT(togglePasswordGeneratorButton(bool))); connect(m_ui->togglePasswordGeneratorButton, SIGNAL(toggled(bool)), SLOT(togglePasswordGeneratorButton(bool)));
connect(m_ui->passwordEdit, SIGNAL(textChanged(QString)), SLOT(selectPassword())); connect(m_ui->passwordEdit, SIGNAL(textChanged(QString)), SLOT(selectPassword()));
connect(m_ui->passwordGenerator, SIGNAL(appliedPassword(QString)), SLOT(setGeneratedPassword(QString))); connect(m_ui->passwordGenerator, SIGNAL(appliedPassword(QString)), SLOT(setGeneratedPassword(QString)));
connect(m_ui->pathEdit, SIGNAL(editingFinished()), SLOT(selectPath())); connect(m_ui->pathEdit, SIGNAL(editingFinished()), SLOT(selectPath()));
connect(m_ui->pathSelectionButton, SIGNAL(pressed()), SLOT(launchPathSelectionDialog())); connect(m_ui->pathSelectionButton, SIGNAL(pressed()), SLOT(launchPathSelectionDialog()));
connect(m_ui->typeComboBox, SIGNAL(currentIndexChanged(int)), SLOT(selectType())); connect(m_ui->typeComboBox, SIGNAL(currentIndexChanged(int)), SLOT(selectType()));
connect(KeeShare::instance(), SIGNAL(activeChanged()), SLOT(showSharingState())); connect(KeeShare::instance(), SIGNAL(activeChanged()), SLOT(showSharingState()));
const auto types = QList<KeeShareSettings::Type>() << KeeShareSettings::Inactive const auto types = QList<KeeShareSettings::Type>()
<< KeeShareSettings::ImportFrom << KeeShareSettings::Inactive << KeeShareSettings::ImportFrom << KeeShareSettings::ExportTo
<< KeeShareSettings::ExportTo << KeeShareSettings::SynchronizeWith;
<< KeeShareSettings::SynchronizeWith; for (const auto& type : types) {
for (const auto& type : types) { QString name;
QString name; switch (type) {
switch (type) { case KeeShareSettings::Inactive:
case KeeShareSettings::Inactive: name = tr("Inactive");
name = tr("Inactive"); break;
break; case KeeShareSettings::ImportFrom:
case KeeShareSettings::ImportFrom: name = tr("Import from path");
name = tr("Import from path"); break;
break; case KeeShareSettings::ExportTo:
case KeeShareSettings::ExportTo: name = tr("Export to path");
name = tr("Export to path"); break;
break; case KeeShareSettings::SynchronizeWith:
case KeeShareSettings::SynchronizeWith: name = tr("Synchronize with path");
name = tr("Synchronize with path"); break;
break; }
} m_ui->typeComboBox->insertItem(type, name, static_cast<int>(type));
m_ui->typeComboBox->insertItem(type, name, static_cast<int>(type)); }
}
} }
EditGroupWidgetKeeShare::~EditGroupWidgetKeeShare() EditGroupWidgetKeeShare::~EditGroupWidgetKeeShare()
@ -87,198 +86,217 @@ EditGroupWidgetKeeShare::~EditGroupWidgetKeeShare()
void EditGroupWidgetKeeShare::setGroup(Group* temporaryGroup) void EditGroupWidgetKeeShare::setGroup(Group* temporaryGroup)
{ {
if (m_temporaryGroup) { if (m_temporaryGroup) {
m_temporaryGroup->disconnect(this); m_temporaryGroup->disconnect(this);
} }
m_temporaryGroup = temporaryGroup; m_temporaryGroup = temporaryGroup;
if (m_temporaryGroup) { if (m_temporaryGroup) {
connect(m_temporaryGroup, SIGNAL(groupModified()), SLOT(update())); connect(m_temporaryGroup, SIGNAL(groupModified()), SLOT(update()));
} }
update(); update();
} }
void EditGroupWidgetKeeShare::showSharingState() void EditGroupWidgetKeeShare::showSharingState()
{ {
if (!m_temporaryGroup) { if (!m_temporaryGroup) {
return; return;
} }
auto supportedExtensions = QStringList(); auto supportedExtensions = QStringList();
#if defined(WITH_XC_KEESHARE_INSECURE) #if defined(WITH_XC_KEESHARE_INSECURE)
supportedExtensions << KeeShare::unsignedContainerFileType(); supportedExtensions << KeeShare::unsignedContainerFileType();
#endif #endif
#if defined(WITH_XC_KEESHARE_SECURE) #if defined(WITH_XC_KEESHARE_SECURE)
supportedExtensions << KeeShare::signedContainerFileType(); supportedExtensions << KeeShare::signedContainerFileType();
#endif #endif
const auto reference = KeeShare::referenceOf(m_temporaryGroup); const auto reference = KeeShare::referenceOf(m_temporaryGroup);
if (!reference.path.isEmpty()) { if (!reference.path.isEmpty()) {
bool supported = false; bool supported = false;
for(const auto &extension : supportedExtensions){ for (const auto& extension : supportedExtensions) {
if (reference.path.endsWith(extension, Qt::CaseInsensitive)){ if (reference.path.endsWith(extension, Qt::CaseInsensitive)) {
supported = true; supported = true;
break; break;
} }
} }
if (!supported) { if (!supported) {
m_ui->messageWidget->showMessage( m_ui->messageWidget->showMessage(
tr("Your KeePassXC version does not support sharing your container type. Please use %1.") tr("Your KeePassXC version does not support sharing your container type. Please use %1.")
.arg(supportedExtensions.join(", ")), .arg(supportedExtensions.join(", ")),
MessageWidget::Warning); MessageWidget::Warning);
return; return;
} }
} }
const auto active = KeeShare::active(); const auto active = KeeShare::active();
if (!active.in && !active.out) { if (!active.in && !active.out) {
m_ui->messageWidget->showMessage(tr("Database sharing is disabled"), MessageWidget::Information); m_ui->messageWidget->showMessage(tr("Database sharing is disabled"), MessageWidget::Information);
return; return;
} }
if (active.in && !active.out) { if (active.in && !active.out) {
m_ui->messageWidget->showMessage(tr("Database export is disabled"), MessageWidget::Information); m_ui->messageWidget->showMessage(tr("Database export is disabled"), MessageWidget::Information);
return; return;
} }
if (!active.in && active.out) { if (!active.in && active.out) {
m_ui->messageWidget->showMessage(tr("Database import is disabled"), MessageWidget::Information); m_ui->messageWidget->showMessage(tr("Database import is disabled"), MessageWidget::Information);
return; return;
} }
} }
void EditGroupWidgetKeeShare::update() void EditGroupWidgetKeeShare::update()
{ {
if (!m_temporaryGroup) { if (!m_temporaryGroup) {
m_ui->passwordEdit->clear(); m_ui->passwordEdit->clear();
m_ui->pathEdit->clear(); m_ui->pathEdit->clear();
} else { } else {
const auto reference = KeeShare::referenceOf(m_temporaryGroup); const auto reference = KeeShare::referenceOf(m_temporaryGroup);
m_ui->typeComboBox->setCurrentIndex(reference.type); m_ui->typeComboBox->setCurrentIndex(reference.type);
m_ui->passwordEdit->setText(reference.password); m_ui->passwordEdit->setText(reference.password);
m_ui->pathEdit->setText(reference.path); m_ui->pathEdit->setText(reference.path);
showSharingState(); showSharingState();
} }
m_ui->passwordGenerator->hide(); m_ui->passwordGenerator->hide();
m_ui->togglePasswordGeneratorButton->setChecked(false); m_ui->togglePasswordGeneratorButton->setChecked(false);
m_ui->togglePasswordButton->setChecked(false); m_ui->togglePasswordButton->setChecked(false);
} }
void EditGroupWidgetKeeShare::togglePasswordGeneratorButton(bool checked) void EditGroupWidgetKeeShare::togglePasswordGeneratorButton(bool checked)
{ {
m_ui->passwordGenerator->regeneratePassword(); m_ui->passwordGenerator->regeneratePassword();
m_ui->passwordGenerator->setVisible(checked); m_ui->passwordGenerator->setVisible(checked);
} }
void EditGroupWidgetKeeShare::setGeneratedPassword(const QString& password) void EditGroupWidgetKeeShare::setGeneratedPassword(const QString& password)
{ {
if (!m_temporaryGroup) { if (!m_temporaryGroup) {
return; return;
} }
auto reference = KeeShare::referenceOf(m_temporaryGroup); auto reference = KeeShare::referenceOf(m_temporaryGroup);
reference.password = password; reference.password = password;
KeeShare::setReferenceTo(m_temporaryGroup, reference); KeeShare::setReferenceTo(m_temporaryGroup, reference);
m_ui->togglePasswordGeneratorButton->setChecked(false); m_ui->togglePasswordGeneratorButton->setChecked(false);
} }
void EditGroupWidgetKeeShare::selectPath() void EditGroupWidgetKeeShare::selectPath()
{ {
if (!m_temporaryGroup) { if (!m_temporaryGroup) {
return; return;
} }
auto reference = KeeShare::referenceOf(m_temporaryGroup); auto reference = KeeShare::referenceOf(m_temporaryGroup);
reference.path = m_ui->pathEdit->text(); reference.path = m_ui->pathEdit->text();
KeeShare::setReferenceTo(m_temporaryGroup, reference); KeeShare::setReferenceTo(m_temporaryGroup, reference);
} }
void EditGroupWidgetKeeShare::launchPathSelectionDialog() void EditGroupWidgetKeeShare::launchPathSelectionDialog()
{ {
if (!m_temporaryGroup) { if (!m_temporaryGroup) {
return; return;
} }
QString defaultDirPath = config()->get("KeeShare/LastShareDir").toString(); QString defaultDirPath = config()->get("KeeShare/LastShareDir").toString();
const bool dirExists = !defaultDirPath.isEmpty() && QDir(defaultDirPath).exists(); const bool dirExists = !defaultDirPath.isEmpty() && QDir(defaultDirPath).exists();
if (!dirExists) { if (!dirExists) {
defaultDirPath = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first(); defaultDirPath = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first();
} }
auto reference = KeeShare::referenceOf(m_temporaryGroup); auto reference = KeeShare::referenceOf(m_temporaryGroup);
QString defaultFiletype = ""; QString defaultFiletype = "";
auto supportedExtensions = QStringList(); auto supportedExtensions = QStringList();
auto unsupportedExtensions = QStringList(); auto unsupportedExtensions = QStringList();
auto knownFilters = QStringList() << QString("%1 (*)").arg("All files"); auto knownFilters = QStringList() << QString("%1 (*)").arg("All files");
#if defined(WITH_XC_KEESHARE_INSECURE) #if defined(WITH_XC_KEESHARE_INSECURE)
defaultFiletype = KeeShare::unsignedContainerFileType(); defaultFiletype = KeeShare::unsignedContainerFileType();
supportedExtensions << KeeShare::unsignedContainerFileType(); supportedExtensions << KeeShare::unsignedContainerFileType();
knownFilters.prepend(QString("%1 (*.%2)").arg(tr("KeeShare unsigned container"), KeeShare::unsignedContainerFileType())); knownFilters.prepend(
QString("%1 (*.%2)").arg(tr("KeeShare unsigned container"), KeeShare::unsignedContainerFileType()));
#else #else
unsupportedExtensions << KeeShare::unsignedContainerFileType(); unsupportedExtensions << KeeShare::unsignedContainerFileType();
#endif #endif
#if defined(WITH_XC_KEESHARE_SECURE) #if defined(WITH_XC_KEESHARE_SECURE)
defaultFiletype = KeeShare::signedContainerFileType(); defaultFiletype = KeeShare::signedContainerFileType();
supportedExtensions << KeeShare::signedContainerFileType(); supportedExtensions << KeeShare::signedContainerFileType();
knownFilters.prepend(QString("%1 (*.%2)").arg(tr("KeeShare signed container"), KeeShare::signedContainerFileType())); knownFilters.prepend(
QString("%1 (*.%2)").arg(tr("KeeShare signed container"), KeeShare::signedContainerFileType()));
#else #else
unsupportedExtensions << KeeShare::signedContainerFileType(); unsupportedExtensions << KeeShare::signedContainerFileType();
#endif #endif
const auto filters = knownFilters.join(";;"); const auto filters = knownFilters.join(";;");
auto filename = reference.path; auto filename = reference.path;
if (filename.isEmpty()) { if (filename.isEmpty()) {
filename = m_temporaryGroup->name(); filename = m_temporaryGroup->name();
} }
switch (reference.type) { switch (reference.type) {
case KeeShareSettings::ImportFrom: case KeeShareSettings::ImportFrom:
filename = fileDialog()->getFileName( filename = fileDialog()->getFileName(this,
this, tr("Select import source"), defaultDirPath, filters, nullptr, QFileDialog::DontConfirmOverwrite, tr("Select import source"),
defaultFiletype, filename); defaultDirPath,
break; filters,
case KeeShareSettings::ExportTo: nullptr,
filename = fileDialog()->getFileName( QFileDialog::DontConfirmOverwrite,
this, tr("Select export target"), defaultDirPath, filters, nullptr, QFileDialog::Option(0), defaultFiletype, filename); defaultFiletype,
break; filename);
case KeeShareSettings::SynchronizeWith: break;
case KeeShareSettings::Inactive: case KeeShareSettings::ExportTo:
filename = fileDialog()->getFileName( filename = fileDialog()->getFileName(this,
this, tr("Select import/export file"), defaultDirPath, filters, nullptr, QFileDialog::Option(0), defaultFiletype, filename); tr("Select export target"),
break; defaultDirPath,
} filters,
nullptr,
QFileDialog::Option(0),
defaultFiletype,
filename);
break;
case KeeShareSettings::SynchronizeWith:
case KeeShareSettings::Inactive:
filename = fileDialog()->getFileName(this,
tr("Select import/export file"),
defaultDirPath,
filters,
nullptr,
QFileDialog::Option(0),
defaultFiletype,
filename);
break;
}
if (filename.isEmpty()) { if (filename.isEmpty()) {
return; return;
} }
bool validFilename = false; bool validFilename = false;
for(const auto& extension : supportedExtensions + unsupportedExtensions){ for (const auto& extension : supportedExtensions + unsupportedExtensions) {
if (filename.endsWith(extension, Qt::CaseInsensitive)) { if (filename.endsWith(extension, Qt::CaseInsensitive)) {
validFilename = true; validFilename = true;
break; break;
} }
} }
if (!validFilename){ if (!validFilename) {
filename += (!filename.endsWith(".") ? "." : "") + defaultFiletype; filename += (!filename.endsWith(".") ? "." : "") + defaultFiletype;
} }
m_ui->pathEdit->setText(filename); m_ui->pathEdit->setText(filename);
selectPath(); selectPath();
config()->set("KeeShare/LastShareDir", QFileInfo(filename).absolutePath()); config()->set("KeeShare/LastShareDir", QFileInfo(filename).absolutePath());
} }
void EditGroupWidgetKeeShare::selectPassword() void EditGroupWidgetKeeShare::selectPassword()
{ {
if (!m_temporaryGroup) { if (!m_temporaryGroup) {
return; return;
} }
auto reference = KeeShare::referenceOf(m_temporaryGroup); auto reference = KeeShare::referenceOf(m_temporaryGroup);
reference.password = m_ui->passwordEdit->text(); reference.password = m_ui->passwordEdit->text();
KeeShare::setReferenceTo(m_temporaryGroup, reference); KeeShare::setReferenceTo(m_temporaryGroup, reference);
} }
void EditGroupWidgetKeeShare::selectType() void EditGroupWidgetKeeShare::selectType()
{ {
if (!m_temporaryGroup) { if (!m_temporaryGroup) {
return; return;
} }
auto reference = KeeShare::referenceOf(m_temporaryGroup); auto reference = KeeShare::referenceOf(m_temporaryGroup);
reference.type = static_cast<KeeShareSettings::Type>(m_ui->typeComboBox->currentData().toInt()); reference.type = static_cast<KeeShareSettings::Type>(m_ui->typeComboBox->currentData().toInt());
KeeShare::setReferenceTo(m_temporaryGroup, reference); KeeShare::setReferenceTo(m_temporaryGroup, reference);
} }