Hotfix/2657 prevent share overwrite (#2746)

* Fix problem with export from newly saved database

Newly created/saved databases (or used with DatabaseWidget::saveAs)
were not exported/imported correctly.
Fixed the problem by reinitializing the ShareObserver on
DatabaseWidget::saveAs.

* Introduce warnings and prevent conflicting shares

Introduced several warnings and errors to indicate improper settings.
Prevent export when a path is used multiple times (only the file path is
checked - may ignore multiple similar ways to reference a share).

* Improve KeeShare integration in DatabaseWidget

Moved initial KeeShare association to constructor.
Introduced Q_UNUSED to indicate need for assignment statement.
This commit is contained in:
ckieschnick 2019-03-16 03:39:46 +01:00 committed by Jonathan White
parent ebb87e6379
commit 11ecaf4fa4
8 changed files with 109 additions and 19 deletions

View file

@ -25,6 +25,7 @@
#include "core/Entry.h"
#include "core/FilePath.h"
#include "core/FileWatcher.h"
#include "core/Global.h"
#include "core/Group.h"
#include "core/Merger.h"
#include "core/Metadata.h"
@ -191,7 +192,7 @@ void ShareObserver::reinitialize()
const auto active = KeeShare::active();
QList<Update> updated;
QList<Group*> groups = m_db->rootGroup()->groupsRecursive(true);
const QList<Group*> groups = m_db->rootGroup()->groupsRecursive(true);
for (Group* group : groups) {
Update couple{group, m_groupToReference.value(group), KeeShare::referenceOf(group)};
if (couple.oldReference == couple.newReference) {
@ -214,7 +215,9 @@ void ShareObserver::reinitialize()
QStringList success;
QStringList warning;
QStringList error;
for (const auto& update : updated) {
QMap<QString, QStringList> imported;
QMap<QString, QStringList> exported;
for (const auto& update : asConst(updated)) {
if (!update.oldReference.path.isEmpty()) {
m_fileWatcher->removePath(update.oldReference.path);
}
@ -222,8 +225,12 @@ void ShareObserver::reinitialize()
if (!update.newReference.path.isEmpty() && update.newReference.type != KeeShareSettings::Inactive) {
m_fileWatcher->addPath(update.newReference.path);
}
if (update.newReference.isExporting()) {
exported[update.newReference.path] << update.group->name();
}
if (update.newReference.isImporting()) {
imported[update.newReference.path] << update.group->name();
const auto result = this->importFromReferenceContainer(update.newReference.path);
if (!result.isValid()) {
// tolerable result - blocked import or missing source
@ -241,6 +248,16 @@ void ShareObserver::reinitialize()
}
}
}
for (auto it = imported.cbegin(); it != imported.cend(); ++it) {
if (it.value().count() > 1) {
warning << tr("Multiple import source path to %1 in %2").arg(it.key(), it.value().join(", "));
}
}
for (auto it = exported.cbegin(); it != exported.cend(); ++it) {
if (it.value().count() > 1) {
error << tr("Conflicting export target path %1 in %2").arg(it.key(), it.value().join(", "));
}
}
notifyAbout(success, warning, error);
}
@ -733,28 +750,55 @@ ShareObserver::Result ShareObserver::exportIntoReferenceUnsignedContainer(const
QList<ShareObserver::Result> ShareObserver::exportIntoReferenceContainers()
{
QList<Result> results;
struct Reference
{
KeeShareSettings::Reference config;
const Group* group;
};
QMap<QString, QList<Reference>> references;
const auto groups = m_db->rootGroup()->groupsRecursive(true);
for (const auto* group : groups) {
const auto reference = KeeShare::referenceOf(group);
if (!reference.isExporting()) {
continue;
}
references[reference.path] << Reference{reference, group};
}
m_fileWatcher->ignoreFileChanges(reference.path);
QScopedPointer<Database> targetDb(exportIntoContainer(reference, group));
QFileInfo info(reference.path);
for (auto it = references.cbegin(); it != references.cend(); ++it) {
if (it.value().count() != 1) {
const auto path = it.value().first().config.path;
QStringList groups;
for (const auto& reference : it.value()) {
groups << reference.group->name();
}
results << Result{
path, Result::Error, tr("Conflicting export target path %1 in %2").arg(path, groups.join(", "))};
}
}
if (!results.isEmpty()) {
// We need to block export due to config
return results;
}
for (auto it = references.cbegin(); it != references.cend(); ++it) {
const auto& reference = it.value().first();
m_fileWatcher->ignoreFileChanges(reference.config.path);
QScopedPointer<Database> targetDb(exportIntoContainer(reference.config, reference.group));
QFileInfo info(reference.config.path);
if (isOfExportType(info, KeeShare::signedContainerFileType())) {
results << exportIntoReferenceSignedContainer(reference, targetDb.data());
results << exportIntoReferenceSignedContainer(reference.config, targetDb.data());
m_fileWatcher->observeFileChanges(true);
continue;
}
if (isOfExportType(info, KeeShare::unsignedContainerFileType())) {
results << exportIntoReferenceUnsignedContainer(reference, targetDb.data());
results << exportIntoReferenceUnsignedContainer(reference.config, targetDb.data());
m_fileWatcher->observeFileChanges(true);
continue;
}
Q_ASSERT(false);
results << Result{reference.path, Result::Error, tr("Unexpected export error occurred")};
results << Result{reference.config.path, Result::Error, tr("Unexpected export error occurred")};
}
return results;
}
@ -767,6 +811,7 @@ void ShareObserver::handleDatabaseSaved()
QStringList error;
QStringList warning;
QStringList success;
const auto results = exportIntoReferenceContainers();
for (const Result& result : results) {
if (!result.isValid()) {