Skip to content

Commit

Permalink
Merge pull request #6496 from nextcloud/backport/6486/stable-3.12
Browse files Browse the repository at this point in the history
[stable-3.12] Bugfix/e2ee v2 non-root sync
  • Loading branch information
allexzander authored Feb 28, 2024
2 parents a8f5dde + 8d2cbc0 commit 8a0d535
Show file tree
Hide file tree
Showing 18 changed files with 122 additions and 23 deletions.
24 changes: 24 additions & 0 deletions src/common/utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -693,5 +693,29 @@ QString Utility::noLeadingSlashPath(const QString &path)
return path.startsWith(slash) ? path.mid(1) : path;
}

QString Utility::noTrailingSlashPath(const QString &path)
{
static const auto slash = QLatin1Char('/');
return path.endsWith(slash) ? path.chopped(1) : path;
}

QString Utility::fullRemotePathToRemoteSyncRootRelative(const QString &fullRemotePath, const QString &remoteSyncRoot)
{
const auto remoteSyncRootNoLeadingSlashWithTrailingSlash = Utility::trailingSlashPath(noLeadingSlashPath(remoteSyncRoot));
const auto fullRemotePathNoLeadingSlash = noLeadingSlashPath(fullRemotePath);

if (remoteSyncRootNoLeadingSlashWithTrailingSlash == QStringLiteral("/")) {
return noLeadingSlashPath(noTrailingSlashPath(fullRemotePath));
}

if (!fullRemotePathNoLeadingSlash.startsWith(remoteSyncRootNoLeadingSlashWithTrailingSlash)) {
return fullRemotePath;
}

const auto relativePathToRemoteSyncRoot = fullRemotePathNoLeadingSlash.mid(remoteSyncRootNoLeadingSlashWithTrailingSlash.size());
Q_ASSERT(!relativePathToRemoteSyncRoot.isEmpty());
return noLeadingSlashPath(noTrailingSlashPath(relativePathToRemoteSyncRoot));
}


} // namespace OCC
2 changes: 2 additions & 0 deletions src/common/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ namespace Utility {

OCSYNC_EXPORT QString trailingSlashPath(const QString &path);
OCSYNC_EXPORT QString noLeadingSlashPath(const QString &path);
OCSYNC_EXPORT QString noTrailingSlashPath(const QString &path);
OCSYNC_EXPORT QString fullRemotePathToRemoteSyncRootRelative(const QString &fullRemotePath, const QString &remoteSyncRoot);

#ifdef Q_OS_WIN
OCSYNC_EXPORT bool registryKeyExists(HKEY hRootKey, const QString &subKey);
Expand Down
2 changes: 1 addition & 1 deletion src/gui/accountsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ void AccountSettings::slotMarkSubfolderEncrypted(FolderStatusModel::SubFolderInf
Q_ASSERT(!path.startsWith('/') && path.endsWith('/'));
// But EncryptFolderJob expects directory path Foo/Bar convention
const auto choppedPath = path.chopped(1);
auto job = new OCC::EncryptFolderJob(accountsState()->account(), folder->journalDb(), choppedPath, fileId);
auto job = new OCC::EncryptFolderJob(accountsState()->account(), folder->journalDb(), choppedPath, choppedPath, folder->remotePath(), fileId);
job->setParent(this);
job->setProperty(propertyFolder, QVariant::fromValue(folder));
job->setProperty(propertyPath, QVariant::fromValue(path));
Expand Down
5 changes: 5 additions & 0 deletions src/gui/folder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,11 @@ QString Folder::remotePathTrailingSlash() const
return Utility::trailingSlashPath(remotePath());
}

QString Folder::fulllRemotePathToPathInSyncJournalDb(const QString &fullRemotePath) const
{
return Utility::fullRemotePathToRemoteSyncRootRelative(fullRemotePath, remotePathTrailingSlash());
}

QUrl Folder::remoteUrl() const
{
return Utility::concatUrlPath(_accountState->account()->davUrl(), remotePath());
Expand Down
2 changes: 2 additions & 0 deletions src/gui/folder.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ class Folder : public QObject
*/
QString remotePathTrailingSlash() const;

[[nodiscard]] QString fulllRemotePathToPathInSyncJournalDb(const QString &fullRemotePath) const;

void setNavigationPaneClsid(const QUuid &clsid) { _definition.navigationPaneClsid = clsid; }
QUuid navigationPaneClsid() const { return _definition.navigationPaneClsid; }

Expand Down
2 changes: 1 addition & 1 deletion src/gui/socketapi/socketapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ void SocketApi::processEncryptRequest(const QString &localFile)
choppedPath = choppedPath.mid(1);
}

auto job = new OCC::EncryptFolderJob(account, folder->journalDb(), choppedPath, rec.numericFileId());
auto job = new OCC::EncryptFolderJob(account, folder->journalDb(), choppedPath, choppedPath, folder->remotePath(), rec.numericFileId());
job->setParent(this);
connect(job, &OCC::EncryptFolderJob::finished, this, [fileData, job](const int status) {
if (status == OCC::EncryptFolderJob::Error) {
Expand Down
2 changes: 1 addition & 1 deletion src/libsync/basepropagateremotedeleteencrypted.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void BasePropagateRemoteDeleteEncrypted::fetchMetadataForPath(const QString &pat
_fullFolderRemotePath = _propagator->fullRemotePath(path);

SyncJournalFileRecord rec;
if (!_propagator->_journal->getRootE2eFolderRecord(_fullFolderRemotePath, &rec) || !rec.isValid()) {
if (!_propagator->_journal->getRootE2eFolderRecord(Utility::fullRemotePathToRemoteSyncRootRelative(_fullFolderRemotePath, _propagator->remotePath()), &rec) || !rec.isValid()) {
taskFailed();
return;
}
Expand Down
13 changes: 5 additions & 8 deletions src/libsync/encryptfolderjob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,21 @@ namespace OCC {

Q_LOGGING_CATEGORY(lcEncryptFolderJob, "nextcloud.sync.propagator.encryptfolder", QtInfoMsg)

EncryptFolderJob::EncryptFolderJob(const AccountPtr &account, SyncJournalDb *journal, const QString &path, const QByteArray &fileId, OwncloudPropagator *propagator, SyncFileItemPtr item,
EncryptFolderJob::EncryptFolderJob(const AccountPtr &account, SyncJournalDb *journal, const QString &path, const QString &pathNonEncrypted, const QString &remoteSyncRootPath, const QByteArray &fileId, OwncloudPropagator *propagator, SyncFileItemPtr item,
QObject * parent)
: QObject(parent)
, _account(account)
, _journal(journal)
, _path(path)
, _pathNonEncrypted(pathNonEncrypted)
, _remoteSyncRootPath(remoteSyncRootPath)
, _fileId(fileId)
, _propagator(propagator)
, _item(item)
{
SyncJournalFileRecord rec;
const auto currentPath = !_pathNonEncrypted.isEmpty() ? _pathNonEncrypted : _path;
[[maybe_unused]] const auto result = _journal->getRootE2eFolderRecord(currentPath, &rec);
[[maybe_unused]] const auto result = _journal->getRootE2eFolderRecord(Utility::fullRemotePathToRemoteSyncRootRelative(currentPath, _remoteSyncRootPath), &rec);
_encryptedFolderMetadataHandler.reset(new EncryptedFolderMetadataHandler(account, _path, _journal, rec.path()));
}

Expand All @@ -57,11 +59,6 @@ QString EncryptFolderJob::errorString() const
return _errorString;
}

void EncryptFolderJob::setPathNonEncrypted(const QString &pathNonEncrypted)
{
_pathNonEncrypted = pathNonEncrypted;
}

void EncryptFolderJob::slotEncryptionFlagSuccess(const QByteArray &fileId)
{
SyncJournalFileRecord rec;
Expand Down Expand Up @@ -106,7 +103,7 @@ void EncryptFolderJob::uploadMetadata()
{
const auto currentPath = !_pathNonEncrypted.isEmpty() ? _pathNonEncrypted : _path;
SyncJournalFileRecord rec;
if (!_journal->getRootE2eFolderRecord(currentPath, &rec)) {
if (!_journal->getRootE2eFolderRecord(Utility::fullRemotePathToRemoteSyncRootRelative(currentPath, _remoteSyncRootPath), &rec)) {
emit finished(Error, EncryptionStatusEnums::ItemEncryptionStatus::NotEncrypted);
return;
}
Expand Down
6 changes: 3 additions & 3 deletions src/libsync/encryptfolderjob.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class OWNCLOUDSYNC_EXPORT EncryptFolderJob : public QObject
explicit EncryptFolderJob(const AccountPtr &account,
SyncJournalDb *journal,
const QString &path,
const QString &pathNonEncrypted,
const QString &_remoteSyncRootPath,
const QByteArray &fileId,
OwncloudPropagator *propagator = nullptr,
SyncFileItemPtr item = {},
Expand All @@ -47,9 +49,6 @@ class OWNCLOUDSYNC_EXPORT EncryptFolderJob : public QObject
signals:
void finished(int status, EncryptionStatusEnums::ItemEncryptionStatus encryptionStatus);

public slots:
void setPathNonEncrypted(const QString &pathNonEncrypted);

private:
void uploadMetadata();

Expand All @@ -64,6 +63,7 @@ private slots:
SyncJournalDb *_journal;
QString _path;
QString _pathNonEncrypted;
QString _remoteSyncRootPath;
QByteArray _fileId;
QString _errorString;
OwncloudPropagator *_propagator = nullptr;
Expand Down
9 changes: 9 additions & 0 deletions src/libsync/owncloudpropagator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1660,6 +1660,15 @@ QString OwncloudPropagator::fullRemotePath(const QString &tmp_file_name) const
return _remoteFolder + tmp_file_name;
}

QString OwncloudPropagator::fulllRemotePathToPathInSyncJournalDb(const QString &fullRemotePath) const
{
auto result = _remoteFolder != QStringLiteral("/") ? fullRemotePath.mid(_remoteFolder.size()) : fullRemotePath;
if (result.startsWith("/")) {
result = result.mid(1);
}
return result;
}

QString OwncloudPropagator::remotePath() const
{
return _remoteFolder;
Expand Down
2 changes: 2 additions & 0 deletions src/libsync/owncloudpropagator.h
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,8 @@ class OWNCLOUDSYNC_EXPORT OwncloudPropagator : public QObject
Q_REQUIRED_RESULT QString fullRemotePath(const QString &tmp_file_name) const;
[[nodiscard]] QString remotePath() const;

[[nodiscard]] QString fulllRemotePathToPathInSyncJournalDb(const QString &fullRemotePath) const;

/** Creates the job for an item.
*/
PropagateItemJob *createJob(const SyncFileItemPtr &item);
Expand Down
3 changes: 2 additions & 1 deletion src/libsync/propagatedownloadencrypted.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ PropagateDownloadEncrypted::PropagateDownloadEncrypted(OwncloudPropagator *propa
void PropagateDownloadEncrypted::start()
{
SyncJournalFileRecord rec;
if (!_propagator->_journal->getRootE2eFolderRecord(_remoteParentPath, &rec) || !rec.isValid()) {
if (!_propagator->_journal->getRootE2eFolderRecord(Utility::fullRemotePathToRemoteSyncRootRelative(_remoteParentPath, _propagator->remotePath()), &rec)
|| !rec.isValid()) {
emit failed();
return;
}
Expand Down
10 changes: 8 additions & 2 deletions src/libsync/propagateremotemkdir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,15 @@ void PropagateRemoteMkdir::finalizeMkColJob(QNetworkReply::NetworkError err, con
// We're expecting directory path in /Foo/Bar convention...
Q_ASSERT(jobPath.startsWith('/') && !jobPath.endsWith('/'));
// But encryption job expect it in Foo/Bar/ convention
auto job = new OCC::EncryptFolderJob(propagator()->account(), propagator()->_journal, jobPath.mid(1), _item->_fileId, propagator(), _item);
auto job = new OCC::EncryptFolderJob(propagator()->account(),
propagator()->_journal,
jobPath.mid(1),
_item->_file,
propagator()->remotePath(),
_item->_fileId,
propagator(),
_item);
job->setParent(this);
job->setPathNonEncrypted(_item->_file);
connect(job, &OCC::EncryptFolderJob::finished, this, &PropagateRemoteMkdir::slotEncryptFolderFinished);
job->start();
}
Expand Down
4 changes: 3 additions & 1 deletion src/libsync/propagateuploadencrypted.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ void PropagateUploadEncrypted::start()
*/
// Encrypt File!
SyncJournalFileRecord rec;
if (!_propagator->_journal->getRootE2eFolderRecord(_remoteParentAbsolutePath, &rec) || !rec.isValid()) {
if (!_propagator->_journal->getRootE2eFolderRecord(Utility::fullRemotePathToRemoteSyncRootRelative(_remoteParentAbsolutePath, _propagator->remotePath()),
&rec)
|| !rec.isValid()) {
emit error();
return;
}
Expand Down
5 changes: 3 additions & 2 deletions src/libsync/updatee2eefoldermetadatajob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ void UpdateE2eeFolderMetadataJob::start()
qCDebug(lcUpdateFileDropMetadataJob) << "Folder is encrypted, let's fetch metadata.";

SyncJournalFileRecord rec;
if (!propagator()->_journal->getRootE2eFolderRecord(_encryptedRemotePath, &rec) || !rec.isValid()) {
if (!propagator()->_journal->getRootE2eFolderRecord(Utility::fullRemotePathToRemoteSyncRootRelative(_encryptedRemotePath, propagator()->remotePath()), &rec) || !rec.isValid()) {
unlockFolder(EncryptedFolderMetadataHandler::UnlockFolderWithResult::Failure);
return;
}
Expand Down Expand Up @@ -84,7 +84,8 @@ void UpdateE2eeFolderMetadataJob::slotFetchMetadataJobFinished(int httpReturnCod
}

SyncJournalFileRecord rec;
if (!propagator()->_journal->getRootE2eFolderRecord(_encryptedRemotePath, &rec) || !rec.isValid()) {
if (!propagator()->_journal->getRootE2eFolderRecord(Utility::fullRemotePathToRemoteSyncRootRelative(_encryptedRemotePath, propagator()->remotePath()), &rec)
|| !rec.isValid()) {
unlockFolder(EncryptedFolderMetadataHandler::UnlockFolderWithResult::Failure);
return;
}
Expand Down
4 changes: 2 additions & 2 deletions src/libsync/updatee2eefolderusersmetadatajob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ UpdateE2eeFolderUsersMetadataJob::UpdateE2eeFolderUsersMetadataJob(const Account
const auto folderPath = _syncFolderRemotePath + pathSanitized;

SyncJournalFileRecord rec;
if (!_journalDb->getRootE2eFolderRecord(_path, &rec) || !rec.isValid()) {
if (!_journalDb->getRootE2eFolderRecord(Utility::fullRemotePathToRemoteSyncRootRelative(_path, _syncFolderRemotePath), &rec) || !rec.isValid()) {
qCDebug(lcUpdateE2eeFolderUsersMetadataJob) << "Could not get root E2ee folder recort for path" << _path;
return;
}
Expand Down Expand Up @@ -96,7 +96,7 @@ void UpdateE2eeFolderUsersMetadataJob::slotStartE2eeMetadataJobs()
const auto pathSanitized = _path.startsWith(QLatin1Char('/')) ? _path.mid(1) : _path;
const auto folderPath = _syncFolderRemotePath + pathSanitized;
SyncJournalFileRecord rec;
if (!_journalDb->getRootE2eFolderRecord(_path, &rec) || !rec.isValid()) {
if (!_journalDb->getRootE2eFolderRecord(Utility::fullRemotePathToRemoteSyncRootRelative(_path, _syncFolderRemotePath), &rec) || !rec.isValid()) {
emit finished(404, tr("Could not find root encrypted folder for folder %1").arg(_path));
return;
}
Expand Down
2 changes: 1 addition & 1 deletion src/libsync/vfs/cfapi/hydrationjob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ void OCC::HydrationJob::handleNewConnectionForEncryptedFile()
const auto _remoteParentPath = remotePath.left(remotePath.lastIndexOf('/'));

SyncJournalFileRecord rec;
if (!_journal->getRootE2eFolderRecord(_remoteParentPath, &rec) || !rec.isValid()) {
if (!_journal->getRootE2eFolderRecord(Utility::fullRemotePathToRemoteSyncRootRelative(_remoteParentPath, rootPath), &rec) || !rec.isValid()) {
emitFinished(Error);
return;
}
Expand Down
48 changes: 48 additions & 0 deletions test/testutility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,54 @@ private slots:
QVERIFY(!isPathWindowsDrivePartitionRoot("c:\\"));
#endif
}

void testFullRemotePathToRemoteSyncRootRelative()
{
QVector<QPair<QString, QString>> remoteFullPathsForRoot = {
{"2020", {"2020"}},
{"/2021/", {"2021"}},
{"/2022/file.docx", {"2022/file.docx"}}
};
// test against root remote path - result must stay unchanged, leading and trailing slashes must get removed
for (const auto &remoteFullPathForRoot : remoteFullPathsForRoot) {
const auto fullRemotePathOriginal = remoteFullPathForRoot.first;
const auto fullRemotePathExpected = remoteFullPathForRoot.second;
const auto fullRepotePathResult = OCC::Utility::fullRemotePathToRemoteSyncRootRelative(fullRemotePathOriginal, "/");
QCOMPARE(fullRepotePathResult, fullRemotePathExpected);
}

const auto remotePathNonRoot = QStringLiteral("/Documents/reports");
QVector<QPair<QString, QString>> remoteFullPathsForNonRoot = {
{remotePathNonRoot + "/" + "2020", {"2020"}},
{remotePathNonRoot + "/" + "2021/", {"2021"}},
{remotePathNonRoot + "/" + "2022/file.docx", {"2022/file.docx"}}
};

// test against non-root remote path - must always return a proper path as in local db
for (const auto &remoteFullPathForNonRoot : remoteFullPathsForNonRoot) {
const auto fullRemotePathOriginal = remoteFullPathForNonRoot.first;
const auto fullRemotePathExpected = remoteFullPathForNonRoot.second;
const auto fullRepotePathResult = OCC::Utility::fullRemotePathToRemoteSyncRootRelative(fullRemotePathOriginal, remotePathNonRoot);
QCOMPARE(fullRepotePathResult, fullRemotePathExpected);
}

// test against non-root remote path with trailing slash - must work the same
const auto remotePathNonRootWithTrailingSlash = QStringLiteral("/Documents/reports/");
for (const auto &remoteFullPathForNonRoot : remoteFullPathsForNonRoot) {
const auto fullRemotePathOriginal = remoteFullPathForNonRoot.first;
const auto fullRemotePathExpected = remoteFullPathForNonRoot.second;
const auto fullRepotePathResult = OCC::Utility::fullRemotePathToRemoteSyncRootRelative(fullRemotePathOriginal, remotePathNonRootWithTrailingSlash);
QCOMPARE(fullRepotePathResult, fullRemotePathExpected);
}

// test against unrelated remote path - result must stay unchanged
const auto remotePathUnrelated = QStringLiteral("/Documents1/reports");
for (const auto &remoteFullPathForNonRoot : remoteFullPathsForNonRoot) {
const auto fullRemotePathOriginal = remoteFullPathForNonRoot.first;
const auto fullRepotePathResult = OCC::Utility::fullRemotePathToRemoteSyncRootRelative(fullRemotePathOriginal, remotePathUnrelated);
QCOMPARE(fullRepotePathResult, fullRemotePathOriginal);
}
}
};

QTEST_GUILESS_MAIN(TestUtility)
Expand Down

0 comments on commit 8a0d535

Please sign in to comment.