Take care of mangled paths on download as well
authorKevin Ottens <kevin.ottens@nextcloud.com>
Fri, 26 Jun 2020 07:43:06 +0000 (09:43 +0200)
committerKevin Ottens <kevin.ottens@nextcloud.com>
Tue, 30 Jun 2020 09:29:08 +0000 (11:29 +0200)
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 <kevin.ottens@nextcloud.com>
src/libsync/propagatedownload.cpp
src/libsync/propagatedownloadencrypted.cpp
src/libsync/propagatedownloadencrypted.h
src/libsync/propagatorjobs.cpp
src/libsync/propagatorjobs.h

index 67a7a4264dab028d88eaff0e7d1b6bf50e880210..ac417a6227274b705bd76fc2a394b326ea77204f 100644 (file)
@@ -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
index 3c23e8fc0d2129eccf7654bca3fd162526e9fee3..4b989f59eb18690e1c4c15e3b66ed35ceb02275c 100644 (file)
@@ -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();
index b2a6b9475472d92e8db22fb01cbc80e9af4d608e..2d769c746732a574db5a27a15c9a7ffab1f02ea1 100644 (file)
@@ -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;
index 3ec7e1a031fb9c46540c5b810ce6770115566c82..9744d64ea4171ff1d359b344f7cf71ac34a8b1ac 100644 (file)
@@ -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()
index b4c37cd94cba2d38bebbb3fd33de1cb2ca787245..1a1266865ae0f3a447ef3381ee91c65d0112266d 100644 (file)
@@ -71,6 +71,9 @@ public:
     void setDeleteExistingFile(bool enabled);
 
 private:
+    void startLocalMkdir();
+    void startDemanglingName(const QString &parentPath);
+
     bool _deleteExistingFile;
 };