diff --git a/src/gui/folderwizard.cpp b/src/gui/folderwizard.cpp index 27345b46f..78dab8c8b 100644 --- a/src/gui/folderwizard.cpp +++ b/src/gui/folderwizard.cpp @@ -332,8 +332,10 @@ void FolderWizardRemotePath::slotUpdateDirectories(const QStringList &list) path.remove(webdavFolder); // Don't allow to select subfolders of encrypted subfolders - if (_account->capabilities().clientSideEncryptionAvailable() && - _account->e2e()->isAnyParentFolderEncrypted(path)) { + const auto isAnyAncestorEncrypted = std::any_of(std::cbegin(_encryptedPaths), std::cend(_encryptedPaths), [=](const QString &encryptedPath) { + return path.size() > encryptedPath.size() && path.startsWith(encryptedPath); + }); + if (isAnyAncestorEncrypted) { continue; } @@ -345,8 +347,21 @@ void FolderWizardRemotePath::slotUpdateDirectories(const QStringList &list) root->setExpanded(true); } +void FolderWizardRemotePath::slotGatherEncryptedPaths(const QString &path, const QMap &properties) +{ + const auto it = properties.find("is-encrypted"); + if (it == properties.cend() || *it != QStringLiteral("1")) { + return; + } + + const auto webdavFolder = QUrl(_account->davUrl()).path(); + Q_ASSERT(path.startsWith(webdavFolder)); + _encryptedPaths << path.mid(webdavFolder.size()); +} + void FolderWizardRemotePath::slotRefreshFolders() { + _encryptedPaths.clear(); runLsColJob("/"); _ui.folderTreeWidget->clear(); _ui.folderEntry->clear(); @@ -364,8 +379,7 @@ void FolderWizardRemotePath::slotCurrentItemChanged(QTreeWidgetItem *item) QString dir = item->data(0, Qt::UserRole).toString(); // We don't want to allow creating subfolders in encrypted folders outside of the sync logic - const auto encrypted = _account->capabilities().clientSideEncryptionAvailable() && - _account->e2e()->isFolderEncrypted(dir + '/'); + const auto encrypted = _encryptedPaths.contains(dir); _ui.addFolderButton->setEnabled(!encrypted); if (!dir.startsWith(QLatin1Char('/'))) { @@ -413,11 +427,17 @@ void FolderWizardRemotePath::slotTypedPathFound(const QStringList &subpaths) LsColJob *FolderWizardRemotePath::runLsColJob(const QString &path) { auto *job = new LsColJob(_account, path, this); - job->setProperties(QList() << "resourcetype"); + auto props = QList() << "resourcetype"; + if (_account->capabilities().clientSideEncryptionAvailable()) { + props << "http://nextcloud.org/ns:is-encrypted"; + } + job->setProperties(props); connect(job, &LsColJob::directoryListingSubfolders, this, &FolderWizardRemotePath::slotUpdateDirectories); connect(job, &LsColJob::finishedWithError, this, &FolderWizardRemotePath::slotHandleLsColNetworkError); + connect(job, &LsColJob::directoryListingIterated, + this, &FolderWizardRemotePath::slotGatherEncryptedPaths); job->start(); return job; diff --git a/src/gui/folderwizard.h b/src/gui/folderwizard.h index 80cb2b8c1..58ffa69c0 100644 --- a/src/gui/folderwizard.h +++ b/src/gui/folderwizard.h @@ -96,6 +96,7 @@ protected slots: void slotHandleMkdirNetworkError(QNetworkReply *); void slotHandleLsColNetworkError(QNetworkReply *); void slotUpdateDirectories(const QStringList &); + void slotGatherEncryptedPaths(const QString &, const QMap &); void slotRefreshFolders(); void slotItemExpanded(QTreeWidgetItem *); void slotCurrentItemChanged(QTreeWidgetItem *); @@ -111,6 +112,7 @@ private: bool _warnWasVisible; AccountPtr _account; QTimer _lscolTimer; + QStringList _encryptedPaths; }; /** diff --git a/src/gui/selectivesyncdialog.cpp b/src/gui/selectivesyncdialog.cpp index 8a3e08e09..919a74ae8 100644 --- a/src/gui/selectivesyncdialog.cpp +++ b/src/gui/selectivesyncdialog.cpp @@ -106,13 +106,21 @@ QSize SelectiveSyncWidget::sizeHint() const void SelectiveSyncWidget::refreshFolders() { + _encryptedPaths.clear(); + auto *job = new LsColJob(_account, _folderPath, this); - job->setProperties(QList() << "resourcetype" - << "http://owncloud.org/ns:size"); + auto props = QList() << "resourcetype" + << "http://owncloud.org/ns:size"; + if (_account->capabilities().clientSideEncryptionAvailable()) { + props << "http://nextcloud.org/ns:is-encrypted"; + } + job->setProperties(props); connect(job, &LsColJob::directoryListingSubfolders, this, &SelectiveSyncWidget::slotUpdateDirectories); connect(job, &LsColJob::finishedWithError, this, &SelectiveSyncWidget::slotLscolFinishedWithError); + connect(job, &LsColJob::directoryListingIterated, + this, &SelectiveSyncWidget::slotGatherEncryptedPaths); job->start(); _folderTree->clear(); _loading->show(); @@ -250,8 +258,10 @@ void SelectiveSyncWidget::slotUpdateDirectories(QStringList list) path.remove(pathToRemove); // Don't allow to select subfolders of encrypted subfolders - if (_account->capabilities().clientSideEncryptionAvailable() && - _account->e2e()->isAnyParentFolderEncrypted(_rootName + '/' + path)) { + const auto isAnyAncestorEncrypted = std::any_of(std::cbegin(_encryptedPaths), std::cend(_encryptedPaths), [=](const QString &encryptedPath) { + return path.size() > encryptedPath.size() && path.startsWith(encryptedPath); + }); + if (isAnyAncestorEncrypted) { continue; } @@ -288,6 +298,19 @@ void SelectiveSyncWidget::slotLscolFinishedWithError(QNetworkReply *r) _loading->resize(_loading->sizeHint()); // because it's not in a layout } +void SelectiveSyncWidget::slotGatherEncryptedPaths(const QString &path, const QMap &properties) +{ + const auto it = properties.find("is-encrypted"); + if (it == properties.cend() || *it != QStringLiteral("1")) { + return; + } + + const auto webdavFolder = QUrl(_account->davUrl()).path(); + Q_ASSERT(path.startsWith(webdavFolder)); + // This dialog use the postfix / convention for folder paths + _encryptedPaths << path.mid(webdavFolder.size()) + '/'; +} + void SelectiveSyncWidget::slotItemExpanded(QTreeWidgetItem *item) { QString dir = item->data(0, Qt::UserRole).toString(); diff --git a/src/gui/selectivesyncdialog.h b/src/gui/selectivesyncdialog.h index 7480f8986..44e2c1ea6 100644 --- a/src/gui/selectivesyncdialog.h +++ b/src/gui/selectivesyncdialog.h @@ -59,6 +59,7 @@ private slots: void slotItemExpanded(QTreeWidgetItem *); void slotItemChanged(QTreeWidgetItem *, int); void slotLscolFinishedWithError(QNetworkReply *); + void slotGatherEncryptedPaths(const QString &, const QMap &); private: void refreshFolders(); @@ -78,6 +79,8 @@ private: // During account setup we want to filter out excluded folders from the // view without having a Folder.SyncEngine.ExcludedFiles instance. ExcludedFiles _excludedFiles; + + QStringList _encryptedPaths; }; /**