diff --git a/src/libsync/propagatedownload.cpp b/src/libsync/propagatedownload.cpp index 67a7a4264d..ac417a6227 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 3c23e8fc0d..4b989f59eb 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 b2a6b94754..2d769c7467 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 3ec7e1a031..9744d64ea4 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 b4c37cd94c..1a1266865a 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; };