From 3182c613ac96b07c2a2ebec3793facfdc21268d4 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Fri, 26 Jun 2020 09:43:06 +0200 Subject: [PATCH] Take care of mangled paths on download as well This means adjusting PropagateDownloadEncrypted so that it knows where the file will end (otherwise it would create temporary files in non existant paths for instance). In turn we have to adjust PropagateDownloadFile accordingly so that it resolves the local folder the file will end up in. And last we adjust PropagateLocalMkdir to resolve paths as well and demangle as needed. Signed-off-by: Kevin Ottens --- src/libsync/propagatedownload.cpp | 27 +++++++++--- src/libsync/propagatedownloadencrypted.cpp | 5 ++- src/libsync/propagatedownloadencrypted.h | 3 +- src/libsync/propagatorjobs.cpp | 49 +++++++++++++++++++++- src/libsync/propagatorjobs.h | 3 ++ 5 files changed, 77 insertions(+), 10 deletions(-) diff --git a/src/libsync/propagatedownload.cpp b/src/libsync/propagatedownload.cpp index 67a7a4264..ac417a622 100644 --- a/src/libsync/propagatedownload.cpp +++ b/src/libsync/propagatedownload.cpp @@ -343,8 +343,27 @@ void PropagateDownloadFile::start() qCDebug(lcPropagateDownload) << _item->_file << propagator()->_activeJobList.count(); - if (propagator()->account()->capabilities().clientSideEncryptionAvailable()) { - _downloadEncryptedHelper = new PropagateDownloadEncrypted(propagator(), _item, this); + const auto rootPath = [=]() { + const auto result = propagator()->_remoteFolder; + if (result.startsWith('/')) { + return result.mid(1); + } else { + return result; + } + }(); + const auto remotePath = QString(rootPath + _item->_file); + const auto remoteParentPath = remotePath.left(remotePath.lastIndexOf('/')); + + const auto account = propagator()->account(); + if (!account->capabilities().clientSideEncryptionAvailable() || + !account->e2e()->isFolderEncrypted(remoteParentPath + '/')) { + startAfterIsEncryptedIsChecked(); + } else { + SyncJournalFileRecord parentRec; + propagator()->_journal->getFileRecordByE2eMangledName(remoteParentPath, &parentRec); + const auto parentPath = parentRec.isValid() ? parentRec._path : remoteParentPath; + + _downloadEncryptedHelper = new PropagateDownloadEncrypted(propagator(), parentPath, _item, this); connect(_downloadEncryptedHelper, &PropagateDownloadEncrypted::folderStatusNotEncrypted, [this] { startAfterIsEncryptedIsChecked(); }); @@ -357,8 +376,6 @@ void PropagateDownloadFile::start() tr("File %1 can not be downloaded because encryption information is missing.").arg(QDir::toNativeSeparators(_item->_file))); }); _downloadEncryptedHelper->start(); - } else { - startAfterIsEncryptedIsChecked(); } } @@ -503,7 +520,7 @@ void PropagateDownloadFile::startDownload() if (_item->_directDownloadUrl.isEmpty()) { // Normal job, download from oC instance _job = new GETFileJob(propagator()->account(), - propagator()->_remoteFolder + _item->_file, + propagator()->_remoteFolder + (_isEncrypted ? _item->_encryptedFileName : _item->_file), &_tmpFile, headers, expectedEtagForResume, _resumeStart, this); } else { // We were provided a direct URL, use that one diff --git a/src/libsync/propagatedownloadencrypted.cpp b/src/libsync/propagatedownloadencrypted.cpp index 3c23e8fc0..4b989f59e 100644 --- a/src/libsync/propagatedownloadencrypted.cpp +++ b/src/libsync/propagatedownloadencrypted.cpp @@ -6,9 +6,10 @@ Q_LOGGING_CATEGORY(lcPropagateDownloadEncrypted, "nextcloud.sync.propagator.down namespace OCC { -PropagateDownloadEncrypted::PropagateDownloadEncrypted(OwncloudPropagator *propagator, SyncFileItemPtr item, QObject *parent) +PropagateDownloadEncrypted::PropagateDownloadEncrypted(OwncloudPropagator *propagator, const QString &localParentPath, SyncFileItemPtr item, QObject *parent) : QObject(parent) , _propagator(propagator) + , _localParentPath(localParentPath) , _item(item) , _info(_item->_file) { @@ -89,7 +90,7 @@ void PropagateDownloadEncrypted::checkFolderEncryptedMetadata(const QJsonDocumen if (encryptedFilename == file.encryptedFilename) { _encryptedInfo = file; _item->_encryptedFileName = _item->_file; - _item->_file = _item->_file.section(QLatin1Char('/'), 0, -2) + QLatin1Char('/') + _encryptedInfo.originalFilename; + _item->_file = _localParentPath + QLatin1Char('/') + _encryptedInfo.originalFilename; qCDebug(lcPropagateDownloadEncrypted) << "Found matching encrypted metadata for file, starting download"; emit folderStatusEncrypted(); diff --git a/src/libsync/propagatedownloadencrypted.h b/src/libsync/propagatedownloadencrypted.h index b2a6b9475..2d769c746 100644 --- a/src/libsync/propagatedownloadencrypted.h +++ b/src/libsync/propagatedownloadencrypted.h @@ -15,7 +15,7 @@ namespace OCC { class PropagateDownloadEncrypted : public QObject { Q_OBJECT public: - PropagateDownloadEncrypted(OwncloudPropagator *propagator, SyncFileItemPtr item, QObject *parent = nullptr); + PropagateDownloadEncrypted(OwncloudPropagator *propagator, const QString &localParentPath, SyncFileItemPtr item, QObject *parent = nullptr); void start(); void checkFolderId(const QStringList &list); bool decryptFile(QFile& tmpFile); @@ -37,6 +37,7 @@ signals: private: OwncloudPropagator *_propagator; + QString _localParentPath; SyncFileItemPtr _item; QFileInfo _info; EncryptedFile _encryptedInfo; diff --git a/src/libsync/propagatorjobs.cpp b/src/libsync/propagatorjobs.cpp index 3ec7e1a03..9744d64ea 100644 --- a/src/libsync/propagatorjobs.cpp +++ b/src/libsync/propagatorjobs.cpp @@ -13,6 +13,8 @@ * for more details. */ +#include "account.h" +#include "propagatedownloadencrypted.h" #include "propagatorjobs.h" #include "owncloudpropagator.h" #include "owncloudpropagator_p.h" @@ -156,6 +158,36 @@ void PropagateLocalMkdir::start() if (propagator()->_abortRequested.fetchAndAddRelaxed(0)) return; + const auto rootPath = [=]() { + const auto result = propagator()->_remoteFolder; + if (result.startsWith('/')) { + return result.mid(1); + } else { + return result; + } + }(); + const auto remotePath = QString(rootPath + _item->_file); + const auto remoteParentPath = remotePath.left(remotePath.lastIndexOf('/')); + + const auto account = propagator()->account(); + if (!account->capabilities().clientSideEncryptionAvailable() || + !account->e2e()->isFolderEncrypted(remoteParentPath + '/')) { + startLocalMkdir(); + } else { + SyncJournalFileRecord parentRec; + propagator()->_journal->getFileRecordByE2eMangledName(remoteParentPath, &parentRec); + const auto parentPath = parentRec.isValid() ? parentRec._path : remoteParentPath; + startDemanglingName(parentPath); + } +} + +void PropagateLocalMkdir::setDeleteExistingFile(bool enabled) +{ + _deleteExistingFile = enabled; +} + +void PropagateLocalMkdir::startLocalMkdir() +{ QDir newDir(propagator()->getFilePath(_item->_file)); QString newDirStr = QDir::toNativeSeparators(newDir.path()); @@ -211,9 +243,22 @@ void PropagateLocalMkdir::start() done(resultStatus); } -void PropagateLocalMkdir::setDeleteExistingFile(bool enabled) +void PropagateLocalMkdir::startDemanglingName(const QString &parentPath) { - _deleteExistingFile = enabled; + auto downloadEncryptedHelper = new PropagateDownloadEncrypted(propagator(), parentPath, _item, this); + connect(downloadEncryptedHelper, &PropagateDownloadEncrypted::folderStatusEncrypted, + this, &PropagateLocalMkdir::startLocalMkdir); + connect(downloadEncryptedHelper, &PropagateDownloadEncrypted::folderStatusNotEncrypted, this, [this] { + // We were wrong after all? Actually might happen due to legacy clients creating broken encrypted folders + qCDebug(lcPropagateLocalMkdir) << "Parent of" << _item->_file << "wasn't encrypted, creating with the original name"; + startLocalMkdir(); + }); + connect(downloadEncryptedHelper, &PropagateDownloadEncrypted::failed, [this] { + // This also might happen due to legacy clients creating broken encrypted folders... + qCDebug(lcPropagateLocalMkdir) << "Directory" << _item->_file << "doesn't exist in its parent metadata, creating with the original name"; + startLocalMkdir(); + }); + downloadEncryptedHelper->start(); } void PropagateLocalRename::start() diff --git a/src/libsync/propagatorjobs.h b/src/libsync/propagatorjobs.h index b4c37cd94..1a1266865 100644 --- a/src/libsync/propagatorjobs.h +++ b/src/libsync/propagatorjobs.h @@ -71,6 +71,9 @@ public: void setDeleteExistingFile(bool enabled); private: + void startLocalMkdir(); + void startDemanglingName(const QString &parentPath); + bool _deleteExistingFile; }; -- 2.30.2