Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enforce ShareObserver to resolve relative paths #3031

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 50 additions & 28 deletions src/keeshare/ShareObserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@ namespace
return {UntrustedOnce, certificate};
}

QString resolvePath(const QString& path, QSharedPointer<Database> database)
{
const QFileInfo info(database->filePath());
return info.absoluteDir().absoluteFilePath(path);
}

} // End Namespace

ShareObserver::ShareObserver(QSharedPointer<Database> db, QObject* parent)
Expand Down Expand Up @@ -193,18 +199,20 @@ void ShareObserver::reinitialize()
QList<Update> updated;
const QList<Group*> groups = m_db->rootGroup()->groupsRecursive(true);
for (Group* group : groups) {
Update couple{group, m_groupToReference.value(group), KeeShare::referenceOf(group)};
const Update couple{group, m_groupToReference.value(group), KeeShare::referenceOf(group)};
if (couple.oldReference == couple.newReference) {
continue;
}

m_groupToReference.remove(couple.group);
m_referenceToGroup.remove(couple.oldReference);
m_shareToGroup.remove(couple.oldReference.path);
const auto oldResolvedPath = resolvePath(couple.oldReference.path, m_db);
m_shareToGroup.remove(oldResolvedPath);
if (couple.newReference.isValid()) {
m_groupToReference[couple.group] = couple.newReference;
m_referenceToGroup[couple.newReference] = couple.group;
m_shareToGroup[couple.newReference.path] = couple.group;
const auto newResolvedPath = resolvePath(couple.newReference.path, m_db);
m_shareToGroup[newResolvedPath] = couple.group;
}
updated << couple;
}
Expand All @@ -216,11 +224,13 @@ void ShareObserver::reinitialize()
QMap<QString, QStringList> exported;
for (const auto& update : asConst(updated)) {
if (!update.oldReference.path.isEmpty()) {
m_fileWatcher->removePath(update.oldReference.path);
const auto oldResolvedPath = resolvePath(update.oldReference.path, m_db);
m_fileWatcher->removePath(oldResolvedPath);
}

if (!update.newReference.path.isEmpty() && update.newReference.type != KeeShareSettings::Inactive) {
m_fileWatcher->addPath(update.newReference.path);
const auto newResolvedPath = resolvePath(update.newReference.path, m_db);
m_fileWatcher->addPath(newResolvedPath);
}
if (update.newReference.isExporting()) {
exported[update.newReference.path] << update.group->name();
Expand Down Expand Up @@ -326,14 +336,16 @@ void ShareObserver::handleFileUpdated(const QString& path)
notifyAbout(success, warning, error);
}

ShareObserver::Result ShareObserver::importSingedContainerInto(const KeeShareSettings::Reference& reference,
ShareObserver::Result ShareObserver::importSignedContainerInto(const QString& realPath,
const KeeShareSettings::Reference& reference,
Group* targetGroup)
{
#if !defined(WITH_XC_KEESHARE_SECURE)
Q_UNUSED(targetGroup);
Q_UNUSED(realPath);
return {reference.path, Result::Warning, tr("Signed share container are not supported - import prevented")};
#else
QuaZip zip(reference.path);
QuaZip zip(realPath);
if (!zip.open(QuaZip::mdUnzip)) {
qCritical("Unable to open file %s.", qPrintable(reference.path));
return {reference.path, Result::Error, tr("File is not readable")};
Expand Down Expand Up @@ -438,14 +450,16 @@ ShareObserver::Result ShareObserver::importSingedContainerInto(const KeeShareSet
#endif
}

ShareObserver::Result ShareObserver::importUnsignedContainerInto(const KeeShareSettings::Reference& reference,
ShareObserver::Result ShareObserver::importUnsignedContainerInto(const QString& realPath,
const KeeShareSettings::Reference& reference,
Group* targetGroup)
{
#if !defined(WITH_XC_KEESHARE_INSECURE)
Q_UNUSED(targetGroup);
Q_UNUSED(realPath);
return {reference.path, Result::Warning, tr("Unsigned share container are not supported - import prevented")};
#else
QFile file(reference.path);
QFile file(realPath);
if (!file.open(QIODevice::ReadOnly)) {
qCritical("Unable to open file %s.", qPrintable(reference.path));
return {reference.path, Result::Error, tr("File is not readable")};
Expand Down Expand Up @@ -524,20 +538,21 @@ ShareObserver::Result ShareObserver::importUnsignedContainerInto(const KeeShareS
#endif
}

ShareObserver::Result ShareObserver::importContainerInto(const KeeShareSettings::Reference& reference,
ShareObserver::Result ShareObserver::importContainerInto(const QString& realPath,
const KeeShareSettings::Reference& reference,
Group* targetGroup)
{
const QFileInfo info(reference.path);
const QFileInfo info(realPath);
if (!info.exists()) {
qCritical("File %s does not exist.", qPrintable(info.absoluteFilePath()));
return {reference.path, Result::Warning, tr("File does not exist")};
}

if (isOfExportType(info, KeeShare::signedContainerFileType())) {
return importSingedContainerInto(reference, targetGroup);
return importSignedContainerInto(realPath, reference, targetGroup);
}
if (isOfExportType(info, KeeShare::unsignedContainerFileType())) {
return importUnsignedContainerInto(reference, targetGroup);
return importUnsignedContainerInto(realPath, reference, targetGroup);
}
return {reference.path, Result::Error, tr("Unknown share container type")};
}
Expand All @@ -547,7 +562,8 @@ ShareObserver::Result ShareObserver::importFromReferenceContainer(const QString&
if (!KeeShare::active().in) {
return {};
}
auto shareGroup = m_shareToGroup.value(path);
const auto changePath = resolvePath(path, m_db);
auto shareGroup = m_shareToGroup.value(changePath);
if (!shareGroup) {
qWarning("Source for %s does not exist", qPrintable(path));
Q_ASSERT(shareGroup);
Expand All @@ -565,7 +581,8 @@ ShareObserver::Result ShareObserver::importFromReferenceContainer(const QString&

Q_ASSERT(shareGroup->database() == m_db);
Q_ASSERT(shareGroup == m_db->rootGroup()->findGroupByUuid(shareGroup->uuid()));
return importContainerInto(reference, shareGroup);
const auto resolvedPath = resolvePath(reference.path, m_db);
return importContainerInto(resolvedPath, reference, shareGroup);
}

void ShareObserver::resolveReferenceAttributes(Entry* targetEntry, const Database* sourceDb)
Expand Down Expand Up @@ -603,14 +620,14 @@ Database* ShareObserver::exportIntoContainer(const KeeShareSettings::Reference&

// Copy the source root as the root of the export database, memory manage the old root node
auto* targetRoot = sourceRoot->clone(Entry::CloneNoFlags, Group::CloneNoFlags);
const bool updateTimeinfo = targetRoot->canUpdateTimeinfo();
auto updateTimeinfo = targetRoot->canUpdateTimeinfo();
targetRoot->setUpdateTimeinfo(false);
KeeShare::setReferenceTo(targetRoot, KeeShareSettings::Reference());
targetRoot->setUpdateTimeinfo(updateTimeinfo);
const auto sourceEntries = sourceRoot->entriesRecursive(false);
for (const Entry* sourceEntry : sourceEntries) {
auto* targetEntry = sourceEntry->clone(Entry::CloneIncludeHistory);
const bool updateTimeinfo = targetEntry->canUpdateTimeinfo();
updateTimeinfo = targetEntry->canUpdateTimeinfo();
targetEntry->setUpdateTimeinfo(false);
targetEntry->setGroup(targetRoot);
targetEntry->setUpdateTimeinfo(updateTimeinfo);
Expand Down Expand Up @@ -647,11 +664,13 @@ QSharedPointer<Database> ShareObserver::database()
return m_db;
}

ShareObserver::Result ShareObserver::exportIntoReferenceSignedContainer(const KeeShareSettings::Reference& reference,
ShareObserver::Result ShareObserver::exportIntoReferenceSignedContainer(const QString& realPath,
const KeeShareSettings::Reference& reference,
Database* targetDb)
{
#if !defined(WITH_XC_KEESHARE_SECURE)
Q_UNUSED(targetDb);
Q_UNUSED(realPath);
return {
reference.path, Result::Warning, tr("Overwriting signed share container is not supported - export prevented")};
#else
Expand All @@ -667,7 +686,7 @@ ShareObserver::Result ShareObserver::exportIntoReferenceSignedContainer(const Ke
}
}
const auto own = KeeShare::own();
QuaZip zip(reference.path);
QuaZip zip(realPath);
zip.setFileNameCodec("UTF-8");
const bool zipOpened = zip.open(QuaZip::mdCreate);
if (!zipOpened) {
Expand Down Expand Up @@ -723,16 +742,18 @@ ShareObserver::Result ShareObserver::exportIntoReferenceSignedContainer(const Ke
#endif
}

ShareObserver::Result ShareObserver::exportIntoReferenceUnsignedContainer(const KeeShareSettings::Reference& reference,
ShareObserver::Result ShareObserver::exportIntoReferenceUnsignedContainer(const QString& realPath,
const KeeShareSettings::Reference& reference,
Database* targetDb)
{
#if !defined(WITH_XC_KEESHARE_INSECURE)
Q_UNUSED(targetDb);
Q_UNUSED(realPath);
return {reference.path,
Result::Warning,
tr("Overwriting unsigned share container is not supported - export prevented")};
#else
QFile file(reference.path);
QFile file(realPath);
const bool fileOpened = file.open(QIODevice::WriteOnly);
if (!fileOpened) {
::qWarning("Opening export file failed");
Expand Down Expand Up @@ -771,12 +792,12 @@ QList<ShareObserver::Result> ShareObserver::exportIntoReferenceContainers()
for (auto it = references.cbegin(); it != references.cend(); ++it) {
if (it.value().count() != 1) {
const auto path = it.value().first().config.path;
QStringList groups;
QStringList groupnames;
for (const auto& reference : it.value()) {
groups << reference.group->name();
groupnames << reference.group->name();
}
results << Result{
path, Result::Error, tr("Conflicting export target path %1 in %2").arg(path, groups.join(", "))};
path, Result::Error, tr("Conflicting export target path %1 in %2").arg(path, groupnames.join(", "))};
}
}
if (!results.isEmpty()) {
Expand All @@ -786,16 +807,17 @@ QList<ShareObserver::Result> ShareObserver::exportIntoReferenceContainers()

for (auto it = references.cbegin(); it != references.cend(); ++it) {
const auto& reference = it.value().first();
m_fileWatcher->ignoreFileChanges(reference.config.path);
const QString resolvedPath = resolvePath(reference.config.path, m_db);
m_fileWatcher->ignoreFileChanges(resolvedPath);
QScopedPointer<Database> targetDb(exportIntoContainer(reference.config, reference.group));
QFileInfo info(reference.config.path);
QFileInfo info(resolvedPath);
if (isOfExportType(info, KeeShare::signedContainerFileType())) {
results << exportIntoReferenceSignedContainer(reference.config, targetDb.data());
results << exportIntoReferenceSignedContainer(resolvedPath, reference.config, targetDb.data());
m_fileWatcher->observeFileChanges(true);
continue;
}
if (isOfExportType(info, KeeShare::unsignedContainerFileType())) {
results << exportIntoReferenceUnsignedContainer(reference.config, targetDb.data());
results << exportIntoReferenceUnsignedContainer(resolvedPath, reference.config, targetDb.data());
m_fileWatcher->observeFileChanges(true);
continue;
}
Expand Down
18 changes: 13 additions & 5 deletions src/keeshare/ShareObserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,20 @@ private slots:
static void resolveReferenceAttributes(Entry* targetEntry, const Database* sourceDb);

static Database* exportIntoContainer(const KeeShareSettings::Reference& reference, const Group* sourceRoot);
static Result exportIntoReferenceUnsignedContainer(const KeeShareSettings::Reference& reference,
static Result exportIntoReferenceUnsignedContainer(const QString& realPath,
const KeeShareSettings::Reference& reference,
Database* targetDb);
static Result exportIntoReferenceSignedContainer(const KeeShareSettings::Reference& reference, Database* targetDb);
static Result importSingedContainerInto(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 exportIntoReferenceSignedContainer(const QString& realPath,
const KeeShareSettings::Reference& reference,
Database* targetDb);
static Result importSignedContainerInto(const QString& realPath,
const KeeShareSettings::Reference& reference,
Group* targetGroup);
static Result importUnsignedContainerInto(const QString& realPath,
const KeeShareSettings::Reference& reference,
Group* targetGroup);
static Result
importContainerInto(const QString& realPath, const KeeShareSettings::Reference& reference, Group* targetGroup);
static Result importDatabaseInto();

Result importFromReferenceContainer(const QString& path);
Expand Down