mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
Enforce ShareObserver to resolve relative paths
ShareObserver now uses paths which are resolved relative to the referencing database.
This commit is contained in:
parent
c5a93ca215
commit
37c53f326c
@ -151,6 +151,12 @@ namespace
|
|||||||
return {UntrustedOnce, certificate};
|
return {UntrustedOnce, certificate};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString resolvePath(const QString& path, QSharedPointer<Database> database)
|
||||||
|
{
|
||||||
|
const QFileInfo info(database->filePath());
|
||||||
|
return info.absoluteDir().absoluteFilePath(path);
|
||||||
|
}
|
||||||
|
|
||||||
} // End Namespace
|
} // End Namespace
|
||||||
|
|
||||||
ShareObserver::ShareObserver(QSharedPointer<Database> db, QObject* parent)
|
ShareObserver::ShareObserver(QSharedPointer<Database> db, QObject* parent)
|
||||||
@ -193,18 +199,20 @@ void ShareObserver::reinitialize()
|
|||||||
QList<Update> updated;
|
QList<Update> updated;
|
||||||
const QList<Group*> groups = m_db->rootGroup()->groupsRecursive(true);
|
const QList<Group*> groups = m_db->rootGroup()->groupsRecursive(true);
|
||||||
for (Group* group : groups) {
|
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) {
|
if (couple.oldReference == couple.newReference) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
const auto oldResolvedPath = resolvePath(couple.oldReference.path, m_db);
|
||||||
|
m_shareToGroup.remove(oldResolvedPath);
|
||||||
if (couple.newReference.isValid()) {
|
if (couple.newReference.isValid()) {
|
||||||
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;
|
const auto newResolvedPath = resolvePath(couple.newReference.path, m_db);
|
||||||
|
m_shareToGroup[newResolvedPath] = couple.group;
|
||||||
}
|
}
|
||||||
updated << couple;
|
updated << couple;
|
||||||
}
|
}
|
||||||
@ -216,11 +224,13 @@ void ShareObserver::reinitialize()
|
|||||||
QMap<QString, QStringList> exported;
|
QMap<QString, QStringList> exported;
|
||||||
for (const auto& update : asConst(updated)) {
|
for (const auto& update : asConst(updated)) {
|
||||||
if (!update.oldReference.path.isEmpty()) {
|
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) {
|
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()) {
|
if (update.newReference.isExporting()) {
|
||||||
exported[update.newReference.path] << update.group->name();
|
exported[update.newReference.path] << update.group->name();
|
||||||
@ -326,14 +336,16 @@ void ShareObserver::handleFileUpdated(const QString& path)
|
|||||||
notifyAbout(success, warning, error);
|
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)
|
Group* targetGroup)
|
||||||
{
|
{
|
||||||
#if !defined(WITH_XC_KEESHARE_SECURE)
|
#if !defined(WITH_XC_KEESHARE_SECURE)
|
||||||
Q_UNUSED(targetGroup);
|
Q_UNUSED(targetGroup);
|
||||||
|
Q_UNUSED(realPath);
|
||||||
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(realPath);
|
||||||
if (!zip.open(QuaZip::mdUnzip)) {
|
if (!zip.open(QuaZip::mdUnzip)) {
|
||||||
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,14 +450,16 @@ ShareObserver::Result ShareObserver::importSingedContainerInto(const KeeShareSet
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ShareObserver::Result ShareObserver::importUnsignedContainerInto(const KeeShareSettings::Reference& reference,
|
ShareObserver::Result ShareObserver::importUnsignedContainerInto(const QString& realPath,
|
||||||
|
const KeeShareSettings::Reference& reference,
|
||||||
Group* targetGroup)
|
Group* targetGroup)
|
||||||
{
|
{
|
||||||
#if !defined(WITH_XC_KEESHARE_INSECURE)
|
#if !defined(WITH_XC_KEESHARE_INSECURE)
|
||||||
Q_UNUSED(targetGroup);
|
Q_UNUSED(targetGroup);
|
||||||
|
Q_UNUSED(realPath);
|
||||||
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(realPath);
|
||||||
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")};
|
||||||
@ -524,20 +538,21 @@ ShareObserver::Result ShareObserver::importUnsignedContainerInto(const KeeShareS
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ShareObserver::Result ShareObserver::importContainerInto(const KeeShareSettings::Reference& reference,
|
ShareObserver::Result ShareObserver::importContainerInto(const QString& realPath,
|
||||||
|
const KeeShareSettings::Reference& reference,
|
||||||
Group* targetGroup)
|
Group* targetGroup)
|
||||||
{
|
{
|
||||||
const QFileInfo info(reference.path);
|
const QFileInfo info(realPath);
|
||||||
if (!info.exists()) {
|
if (!info.exists()) {
|
||||||
qCritical("File %s does not exist.", qPrintable(info.absoluteFilePath()));
|
qCritical("File %s does not exist.", qPrintable(info.absoluteFilePath()));
|
||||||
return {reference.path, Result::Warning, tr("File does not exist")};
|
return {reference.path, Result::Warning, tr("File does not exist")};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOfExportType(info, KeeShare::signedContainerFileType())) {
|
if (isOfExportType(info, KeeShare::signedContainerFileType())) {
|
||||||
return importSingedContainerInto(reference, targetGroup);
|
return importSignedContainerInto(realPath, reference, targetGroup);
|
||||||
}
|
}
|
||||||
if (isOfExportType(info, KeeShare::unsignedContainerFileType())) {
|
if (isOfExportType(info, KeeShare::unsignedContainerFileType())) {
|
||||||
return importUnsignedContainerInto(reference, targetGroup);
|
return importUnsignedContainerInto(realPath, reference, targetGroup);
|
||||||
}
|
}
|
||||||
return {reference.path, Result::Error, tr("Unknown share container type")};
|
return {reference.path, Result::Error, tr("Unknown share container type")};
|
||||||
}
|
}
|
||||||
@ -547,7 +562,8 @@ ShareObserver::Result ShareObserver::importFromReferenceContainer(const QString&
|
|||||||
if (!KeeShare::active().in) {
|
if (!KeeShare::active().in) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto shareGroup = m_shareToGroup.value(path);
|
const auto changePath = resolvePath(path, m_db);
|
||||||
|
auto shareGroup = m_shareToGroup.value(changePath);
|
||||||
if (!shareGroup) {
|
if (!shareGroup) {
|
||||||
qWarning("Source for %s does not exist", qPrintable(path));
|
qWarning("Source for %s does not exist", qPrintable(path));
|
||||||
Q_ASSERT(shareGroup);
|
Q_ASSERT(shareGroup);
|
||||||
@ -565,7 +581,8 @@ ShareObserver::Result ShareObserver::importFromReferenceContainer(const QString&
|
|||||||
|
|
||||||
Q_ASSERT(shareGroup->database() == m_db);
|
Q_ASSERT(shareGroup->database() == m_db);
|
||||||
Q_ASSERT(shareGroup == m_db->rootGroup()->findGroupByUuid(shareGroup->uuid()));
|
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)
|
void ShareObserver::resolveReferenceAttributes(Entry* targetEntry, const Database* sourceDb)
|
||||||
@ -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
|
// 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);
|
auto* targetRoot = sourceRoot->clone(Entry::CloneNoFlags, Group::CloneNoFlags);
|
||||||
const bool updateTimeinfo = targetRoot->canUpdateTimeinfo();
|
auto updateTimeinfo = targetRoot->canUpdateTimeinfo();
|
||||||
targetRoot->setUpdateTimeinfo(false);
|
targetRoot->setUpdateTimeinfo(false);
|
||||||
KeeShare::setReferenceTo(targetRoot, KeeShareSettings::Reference());
|
KeeShare::setReferenceTo(targetRoot, KeeShareSettings::Reference());
|
||||||
targetRoot->setUpdateTimeinfo(updateTimeinfo);
|
targetRoot->setUpdateTimeinfo(updateTimeinfo);
|
||||||
const auto sourceEntries = sourceRoot->entriesRecursive(false);
|
const auto sourceEntries = sourceRoot->entriesRecursive(false);
|
||||||
for (const Entry* sourceEntry : sourceEntries) {
|
for (const Entry* sourceEntry : sourceEntries) {
|
||||||
auto* targetEntry = sourceEntry->clone(Entry::CloneIncludeHistory);
|
auto* targetEntry = sourceEntry->clone(Entry::CloneIncludeHistory);
|
||||||
const bool updateTimeinfo = targetEntry->canUpdateTimeinfo();
|
updateTimeinfo = targetEntry->canUpdateTimeinfo();
|
||||||
targetEntry->setUpdateTimeinfo(false);
|
targetEntry->setUpdateTimeinfo(false);
|
||||||
targetEntry->setGroup(targetRoot);
|
targetEntry->setGroup(targetRoot);
|
||||||
targetEntry->setUpdateTimeinfo(updateTimeinfo);
|
targetEntry->setUpdateTimeinfo(updateTimeinfo);
|
||||||
@ -647,11 +664,13 @@ QSharedPointer<Database> ShareObserver::database()
|
|||||||
return m_db;
|
return m_db;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShareObserver::Result ShareObserver::exportIntoReferenceSignedContainer(const KeeShareSettings::Reference& reference,
|
ShareObserver::Result ShareObserver::exportIntoReferenceSignedContainer(const QString& realPath,
|
||||||
|
const KeeShareSettings::Reference& reference,
|
||||||
Database* targetDb)
|
Database* targetDb)
|
||||||
{
|
{
|
||||||
#if !defined(WITH_XC_KEESHARE_SECURE)
|
#if !defined(WITH_XC_KEESHARE_SECURE)
|
||||||
Q_UNUSED(targetDb);
|
Q_UNUSED(targetDb);
|
||||||
|
Q_UNUSED(realPath);
|
||||||
return {
|
return {
|
||||||
reference.path, Result::Warning, tr("Overwriting signed share container is not supported - export prevented")};
|
reference.path, Result::Warning, tr("Overwriting signed share container is not supported - export prevented")};
|
||||||
#else
|
#else
|
||||||
@ -667,7 +686,7 @@ ShareObserver::Result ShareObserver::exportIntoReferenceSignedContainer(const Ke
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto own = KeeShare::own();
|
const auto own = KeeShare::own();
|
||||||
QuaZip zip(reference.path);
|
QuaZip zip(realPath);
|
||||||
zip.setFileNameCodec("UTF-8");
|
zip.setFileNameCodec("UTF-8");
|
||||||
const bool zipOpened = zip.open(QuaZip::mdCreate);
|
const bool zipOpened = zip.open(QuaZip::mdCreate);
|
||||||
if (!zipOpened) {
|
if (!zipOpened) {
|
||||||
@ -723,16 +742,18 @@ ShareObserver::Result ShareObserver::exportIntoReferenceSignedContainer(const Ke
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ShareObserver::Result ShareObserver::exportIntoReferenceUnsignedContainer(const KeeShareSettings::Reference& reference,
|
ShareObserver::Result ShareObserver::exportIntoReferenceUnsignedContainer(const QString& realPath,
|
||||||
|
const KeeShareSettings::Reference& reference,
|
||||||
Database* targetDb)
|
Database* targetDb)
|
||||||
{
|
{
|
||||||
#if !defined(WITH_XC_KEESHARE_INSECURE)
|
#if !defined(WITH_XC_KEESHARE_INSECURE)
|
||||||
Q_UNUSED(targetDb);
|
Q_UNUSED(targetDb);
|
||||||
|
Q_UNUSED(realPath);
|
||||||
return {reference.path,
|
return {reference.path,
|
||||||
Result::Warning,
|
Result::Warning,
|
||||||
tr("Overwriting unsigned share container is not supported - export prevented")};
|
tr("Overwriting unsigned share container is not supported - export prevented")};
|
||||||
#else
|
#else
|
||||||
QFile file(reference.path);
|
QFile file(realPath);
|
||||||
const bool fileOpened = file.open(QIODevice::WriteOnly);
|
const bool fileOpened = file.open(QIODevice::WriteOnly);
|
||||||
if (!fileOpened) {
|
if (!fileOpened) {
|
||||||
::qWarning("Opening export file failed");
|
::qWarning("Opening export file failed");
|
||||||
@ -771,12 +792,12 @@ QList<ShareObserver::Result> ShareObserver::exportIntoReferenceContainers()
|
|||||||
for (auto it = references.cbegin(); it != references.cend(); ++it) {
|
for (auto it = references.cbegin(); it != references.cend(); ++it) {
|
||||||
if (it.value().count() != 1) {
|
if (it.value().count() != 1) {
|
||||||
const auto path = it.value().first().config.path;
|
const auto path = it.value().first().config.path;
|
||||||
QStringList groups;
|
QStringList groupnames;
|
||||||
for (const auto& reference : it.value()) {
|
for (const auto& reference : it.value()) {
|
||||||
groups << reference.group->name();
|
groupnames << reference.group->name();
|
||||||
}
|
}
|
||||||
results << Result{
|
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()) {
|
if (!results.isEmpty()) {
|
||||||
@ -786,16 +807,17 @@ QList<ShareObserver::Result> ShareObserver::exportIntoReferenceContainers()
|
|||||||
|
|
||||||
for (auto it = references.cbegin(); it != references.cend(); ++it) {
|
for (auto it = references.cbegin(); it != references.cend(); ++it) {
|
||||||
const auto& reference = it.value().first();
|
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));
|
QScopedPointer<Database> targetDb(exportIntoContainer(reference.config, reference.group));
|
||||||
QFileInfo info(reference.config.path);
|
QFileInfo info(resolvedPath);
|
||||||
if (isOfExportType(info, KeeShare::signedContainerFileType())) {
|
if (isOfExportType(info, KeeShare::signedContainerFileType())) {
|
||||||
results << exportIntoReferenceSignedContainer(reference.config, targetDb.data());
|
results << exportIntoReferenceSignedContainer(resolvedPath, reference.config, targetDb.data());
|
||||||
m_fileWatcher->observeFileChanges(true);
|
m_fileWatcher->observeFileChanges(true);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isOfExportType(info, KeeShare::unsignedContainerFileType())) {
|
if (isOfExportType(info, KeeShare::unsignedContainerFileType())) {
|
||||||
results << exportIntoReferenceUnsignedContainer(reference.config, targetDb.data());
|
results << exportIntoReferenceUnsignedContainer(resolvedPath, reference.config, targetDb.data());
|
||||||
m_fileWatcher->observeFileChanges(true);
|
m_fileWatcher->observeFileChanges(true);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -79,12 +79,20 @@ 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,
|
static Result exportIntoReferenceUnsignedContainer(const QString& realPath,
|
||||||
|
const KeeShareSettings::Reference& reference,
|
||||||
Database* targetDb);
|
Database* targetDb);
|
||||||
static Result exportIntoReferenceSignedContainer(const KeeShareSettings::Reference& reference, Database* targetDb);
|
static Result exportIntoReferenceSignedContainer(const QString& realPath,
|
||||||
static Result importSingedContainerInto(const KeeShareSettings::Reference& reference, Group* targetGroup);
|
const KeeShareSettings::Reference& reference,
|
||||||
static Result importUnsignedContainerInto(const KeeShareSettings::Reference& reference, Group* targetGroup);
|
Database* targetDb);
|
||||||
static Result importContainerInto(const KeeShareSettings::Reference& reference, Group* targetGroup);
|
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();
|
static Result importDatabaseInto();
|
||||||
|
|
||||||
Result importFromReferenceContainer(const QString& path);
|
Result importFromReferenceContainer(const QString& path);
|
||||||
|
Loading…
Reference in New Issue
Block a user