Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

E2EE. Fix root metadata fetching path for non-root remote sync folder. Refactoring. Stabilizing paths. #6529

Merged
merged 1 commit into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/common/utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"

Check failure on line 19 in src/common/utility.cpp

View workflow job for this annotation

GitHub Actions / build

src/common/utility.cpp:19:10 [clang-diagnostic-error]

'config.h' file not found

#include "common/utility.h"
#include "common/filesystembase.h"
Expand Down Expand Up @@ -681,6 +681,12 @@
return bname.contains(QStringLiteral("(case clash from"));
}

QString Utility::leadingSlashPath(const QString &path)
{
static const auto slash = QLatin1Char('/');
return !path.startsWith(slash) ? QString(slash + path) : path;
}

QString Utility::trailingSlashPath(const QString &path)
{
static const auto slash = QLatin1Char('/');
Expand All @@ -690,13 +696,13 @@
QString Utility::noLeadingSlashPath(const QString &path)
{
static const auto slash = QLatin1Char('/');
return path.startsWith(slash) ? path.mid(1) : path;
return path.size() > 1 && 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;
return path.size() > 1 && path.endsWith(slash) ? path.chopped(1) : path;
}

QString Utility::fullRemotePathToRemoteSyncRootRelative(const QString &fullRemotePath, const QString &remoteSyncRoot)
Expand Down
3 changes: 2 additions & 1 deletion src/common/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#define UTILITY_H


#include "csync/ocsynclib.h"

Check failure on line 24 in src/common/utility.h

View workflow job for this annotation

GitHub Actions / build

src/common/utility.h:24:10 [clang-diagnostic-error]

'csync/ocsynclib.h' file not found
#include <QString>
#include <QByteArray>
#include <QDateTime>
Expand Down Expand Up @@ -266,7 +266,8 @@
* @brief Registers the desktop app as a handler for a custom URI to enable local editing
*/
OCSYNC_EXPORT void registerUriHandlerForLocalEditing();


OCSYNC_EXPORT QString leadingSlashPath(const QString &path);
OCSYNC_EXPORT QString trailingSlashPath(const QString &path);
OCSYNC_EXPORT QString noLeadingSlashPath(const QString &path);
OCSYNC_EXPORT QString noTrailingSlashPath(const QString &path);
Expand Down
3 changes: 3 additions & 0 deletions src/gui/filedetails/sharemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,9 @@ void ShareModel::slotDeleteE2EeShare(const SharePtr &share) const
return;
}

Q_ASSERT(folder->remotePath() == QStringLiteral("/")
|| Utility::noLeadingSlashPath(share->path()).startsWith(Utility::noLeadingSlashPath(Utility::noTrailingSlashPath(folder->remotePath()))));

const auto removeE2eeShareJob = new UpdateE2eeFolderUsersMetadataJob(account,
folder->journalDb(),
folder->remotePath(),
Expand Down
5 changes: 2 additions & 3 deletions src/gui/folderman.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check notice on line 1 in src/gui/folderman.cpp

View workflow job for this annotation

GitHub Actions / build

Run clang-format on src/gui/folderman.cpp

File src/gui/folderman.cpp does not conform to Custom style guidelines. (lines 1554)
* Copyright (C) by Klaas Freitag <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -1537,7 +1537,7 @@
{
const auto localFileNoTrailingSlash = localFile.endsWith('/') ? localFile.chopped(1) : localFile;
if (const auto folder = FolderMan::instance()->folderForPath(localFileNoTrailingSlash)) {
const auto filePathRelative = QString(localFileNoTrailingSlash).remove(folder->path());
const auto filePathRelative = Utility::noLeadingSlashPath(QString(localFileNoTrailingSlash).remove(folder->path()));

SyncJournalFileRecord rec;
if (folder->journalDb()->getFileRecord(filePathRelative, &rec)
Expand All @@ -1551,8 +1551,7 @@
folder->journalDb(),
folder->remotePath(),
UpdateE2eeFolderUsersMetadataJob::Remove,
//TODO: Might need to add a slash to "filePathRelative" once the server is working
filePathRelative,
folder->remotePathTrailingSlash() + filePathRelative,
folder->accountState()->account()->davUser());
_removeE2eeShareJob->setParent(this);
_removeE2eeShareJob->start(true);
Expand Down
7 changes: 5 additions & 2 deletions src/gui/sharemanager.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check notice on line 1 in src/gui/sharemanager.cpp

View workflow job for this annotation

GitHub Actions / build

Run clang-format on src/gui/sharemanager.cpp

File src/gui/sharemanager.cpp does not conform to Custom style guidelines. (lines 491, 509)
* Copyright (C) by Roeland Jago Douma <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -488,7 +488,7 @@
job->getSharedWithMe();
}

void ShareManager::createE2EeShareJob(const QString &path,
void ShareManager::createE2EeShareJob(const QString &fullRemotePath,
const ShareePtr sharee,
const Share::Permissions permissions,
const QString &password)
Expand All @@ -506,11 +506,14 @@
return;
}

Q_ASSERT(folder->remotePath() == QStringLiteral("/") ||
Utility::noLeadingSlashPath(fullRemotePath).startsWith(Utility::noLeadingSlashPath(Utility::noTrailingSlashPath(folder->remotePath()))));

const auto createE2eeShareJob = new UpdateE2eeFolderUsersMetadataJob(_account,
folder->journalDb(),
folder->remotePath(),
UpdateE2eeFolderUsersMetadataJob::Add,
path,
fullRemotePath,
sharee->shareWith(),
QSslCertificate{},
this);
Expand Down
4 changes: 2 additions & 2 deletions src/gui/sharemanager.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check notice on line 1 in src/gui/sharemanager.h

View workflow job for this annotation

GitHub Actions / build

Run clang-format on src/gui/sharemanager.h

File src/gui/sharemanager.h does not conform to Custom style guidelines. (lines 428)
* Copyright (C) by Roeland Jago Douma <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
Expand All @@ -15,7 +15,7 @@
#ifndef SHAREMANAGER_H
#define SHAREMANAGER_H

#include "accountfwd.h"

Check failure on line 18 in src/gui/sharemanager.h

View workflow job for this annotation

GitHub Actions / build

src/gui/sharemanager.h:18:10 [clang-diagnostic-error]

'accountfwd.h' file not found
#include "sharee.h"
#include "sharepermissions.h"

Expand Down Expand Up @@ -416,7 +416,7 @@
/**
* Tell the manager to create and start new UpdateE2eeShareMetadataJob job
*
* @param path The path of the share relative to the user folder on the server
* @param fullRemotePath The path of the share relative to the user folder on the server
* @param shareType The type of share (TypeUser, TypeGroup, TypeRemote)
* @param Permissions The share permissions
* @param folderId The id for an E2EE folder
Expand All @@ -425,7 +425,7 @@
* On success the signal shareCreated is emitted
* In case of a server error the serverError signal is emitted
*/
void createE2EeShareJob(const QString &path,
void createE2EeShareJob(const QString &fullRemotePath,
const ShareePtr sharee,
const Share::Permissions permissions,
const QString &password = "");
Expand Down
8 changes: 1 addition & 7 deletions src/gui/socketapi/socketapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -550,13 +550,7 @@ void SocketApi::processEncryptRequest(const QString &localFile)
auto path = rec._path;
// Folder records have directory paths in Foo/Bar/ convention...
// But EncryptFolderJob expects directory path Foo/Bar convention
auto choppedPath = path;
if (choppedPath.endsWith('/') && choppedPath != QStringLiteral("/")) {
choppedPath.chop(1);
}
if (choppedPath.startsWith('/') && choppedPath != QStringLiteral("/")) {
choppedPath = choppedPath.mid(1);
}
const auto choppedPath = Utility::noTrailingSlashPath(Utility::noLeadingSlashPath(path));

auto job = new OCC::EncryptFolderJob(account, folder->journalDb(), choppedPath, choppedPath, folder->remotePath(), rec.numericFileId());
job->setParent(this);
Expand Down
10 changes: 5 additions & 5 deletions src/libsync/basepropagateremotedeleteencrypted.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check notice on line 1 in src/libsync/basepropagateremotedeleteencrypted.cpp

View workflow job for this annotation

GitHub Actions / build

Run clang-format on src/libsync/basepropagateremotedeleteencrypted.cpp

File src/libsync/basepropagateremotedeleteencrypted.cpp does not conform to Custom style guidelines. (lines 60, 69, 70)
* Copyright (C) by Oleksandr Zolotov <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
Expand All @@ -12,7 +12,7 @@
* for more details.
*/

#include <QFileInfo>

Check failure on line 15 in src/libsync/basepropagateremotedeleteencrypted.cpp

View workflow job for this annotation

GitHub Actions / build

src/libsync/basepropagateremotedeleteencrypted.cpp:15:10 [clang-diagnostic-error]

'QFileInfo' file not found
#include <QLoggingCategory>
#include "foldermetadata.h"
#include "basepropagateremotedeleteencrypted.h"
Expand Down Expand Up @@ -57,17 +57,17 @@

void BasePropagateRemoteDeleteEncrypted::fetchMetadataForPath(const QString &path)
{
qCDebug(ABSTRACT_PROPAGATE_REMOVE_ENCRYPTED) << "Folder is encrypted, let's its metadata.";
_fullFolderRemotePath = _propagator->fullRemotePath(path);

qCDebug(ABSTRACT_PROPAGATE_REMOVE_ENCRYPTED) << "Folder is encrypted, let's fetch its metadata.";

SyncJournalFileRecord rec;
if (!_propagator->_journal->getRootE2eFolderRecord(Utility::fullRemotePathToRemoteSyncRootRelative(_fullFolderRemotePath, _propagator->remotePath()), &rec) || !rec.isValid()) {
if (!_propagator->_journal->getRootE2eFolderRecord(Utility::noLeadingSlashPath(path), &rec) || !rec.isValid()) {
taskFailed();
return;
}

_encryptedFolderMetadataHandler.reset(new EncryptedFolderMetadataHandler(_propagator->account(),
_fullFolderRemotePath,
_propagator->fullRemotePath(path),
_propagator->remotePath(),
_propagator->_journal,
rec.path()));

Expand Down
5 changes: 3 additions & 2 deletions src/libsync/discovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2024,10 +2024,11 @@ void ProcessDirectoryJob::chopVirtualFileSuffix(QString &str) const
DiscoverySingleDirectoryJob *ProcessDirectoryJob::startAsyncServerQuery()
{
if (_dirItem && _dirItem->isEncrypted() && _dirItem->_encryptedFileName.isEmpty()) {
_discoveryData->_topLevelE2eeFolderPaths.insert(QLatin1Char('/') + _dirItem->_file);
_discoveryData->_topLevelE2eeFolderPaths.insert(_discoveryData->_remoteFolder + _dirItem->_file);
}
auto serverJob = new DiscoverySingleDirectoryJob(_discoveryData->_account,
_discoveryData->_remoteFolder + _currentFolder._server,
_currentFolder._server,
_discoveryData->_remoteFolder,
_discoveryData->_topLevelE2eeFolderPaths,
this);
if (!_dirItem) {
Expand Down
8 changes: 6 additions & 2 deletions src/libsync/discoveryphase.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check notice on line 1 in src/libsync/discoveryphase.cpp

View workflow job for this annotation

GitHub Actions / build

Run clang-format on src/libsync/discoveryphase.cpp

File src/libsync/discoveryphase.cpp does not conform to Custom style guidelines. (lines 698, 700)
* Copyright (C) by Olivier Goffart <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -369,15 +369,18 @@
emit finished(results);
}

DiscoverySingleDirectoryJob::DiscoverySingleDirectoryJob(const AccountPtr &account,

Check warning on line 372 in src/libsync/discoveryphase.cpp

View workflow job for this annotation

GitHub Actions / build

src/libsync/discoveryphase.cpp:372:58 [bugprone-easily-swappable-parameters]

4 adjacent parameters of 'DiscoverySingleDirectoryJob' of similar type ('const int &') are easily swapped by mistake
const QString &path,
const QString &remoteRootFolderPath,
const QSet<QString> &topLevelE2eeFolderPaths,
QObject *parent)
: QObject(parent)
, _subPath(path)
, _subPath(remoteRootFolderPath + path)
, _remoteRootFolderPath(remoteRootFolderPath)
, _account(account)
, _topLevelE2eeFolderPaths(topLevelE2eeFolderPaths)
{
Q_ASSERT(!_remoteRootFolderPath.isEmpty());
}

void DiscoverySingleDirectoryJob::start()
Expand Down Expand Up @@ -692,8 +695,9 @@
}

const auto e2EeFolderMetadata = new FolderMetadata(_account,
_remoteRootFolderPath,
statusCode == 404 ? QByteArray{} : json.toJson(QJsonDocument::Compact),
RootEncryptedFolderInfo(topLevelFolderPath),
RootEncryptedFolderInfo(Utility::fullRemotePathToRemoteSyncRootRelative(topLevelFolderPath, _remoteRootFolderPath)),
job->signature());
connect(e2EeFolderMetadata, &FolderMetadata::setupComplete, this, [this, e2EeFolderMetadata] {
e2EeFolderMetadata->deleteLater();
Expand Down
2 changes: 2 additions & 0 deletions src/libsync/discoveryphase.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check notice on line 1 in src/libsync/discoveryphase.h

View workflow job for this annotation

GitHub Actions / build

Run clang-format on src/libsync/discoveryphase.h

File src/libsync/discoveryphase.h does not conform to Custom style guidelines. (lines 148)
* Copyright (C) by Olivier Goffart <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
Expand All @@ -14,7 +14,7 @@

#pragma once

#include <QObject>

Check failure on line 17 in src/libsync/discoveryphase.h

View workflow job for this annotation

GitHub Actions / build

src/libsync/discoveryphase.h:17:10 [clang-diagnostic-error]

'QObject' file not found
#include <QElapsedTimer>
#include <QStringList>
#include <csync.h>
Expand Down Expand Up @@ -145,6 +145,7 @@
public:
explicit DiscoverySingleDirectoryJob(const AccountPtr &account,
const QString &path,
const QString &remoteRootFolderPath,
/* TODO for topLevelE2eeFolderPaths, from review: I still do not get why giving the whole QSet instead of just the parent of the folder we are in
sounds to me like it would be much more efficient to just have the e2ee parent folder that we are
inside*/
Expand Down Expand Up @@ -179,6 +180,7 @@

QVector<RemoteInfo> _results;
QString _subPath;
QString _remoteRootFolderPath;
QByteArray _firstEtag;
QByteArray _fileId;
QByteArray _localFileId;
Expand Down
36 changes: 27 additions & 9 deletions src/libsync/encryptedfoldermetadatahandler.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check notice on line 1 in src/libsync/encryptedfoldermetadatahandler.cpp

View workflow job for this annotation

GitHub Actions / build

Run clang-format on src/libsync/encryptedfoldermetadatahandler.cpp

File src/libsync/encryptedfoldermetadatahandler.cpp does not conform to Custom style guidelines. (lines 35, 36, 75, 76)
* Copyright (C) 2023 by Oleksandr Zolotov <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -32,17 +32,22 @@
namespace OCC {

EncryptedFolderMetadataHandler::EncryptedFolderMetadataHandler(const AccountPtr &account,
const QString &folderPath,
const QString &folderFullRemotePath,
const QString &remoteFolderRoot,
SyncJournalDb *const journalDb,
const QString &pathForTopLevelFolder,
QObject *parent)
: QObject(parent)
, _account(account)
, _folderPath(folderPath)
, _journalDb(journalDb)
, _folderFullRemotePath(Utility::noLeadingSlashPath(Utility::noTrailingSlashPath(folderFullRemotePath)))
, _remoteFolderRoot(Utility::noLeadingSlashPath(Utility::noTrailingSlashPath(remoteFolderRoot)))
{
_rootEncryptedFolderInfo = RootEncryptedFolderInfo(
RootEncryptedFolderInfo::createRootPath(folderPath, pathForTopLevelFolder));
Q_ASSERT(!_remoteFolderRoot.isEmpty());
Q_ASSERT(_remoteFolderRoot == QStringLiteral("/") || _folderFullRemotePath.startsWith(_remoteFolderRoot));

const auto folderRelativePath = Utility::fullRemotePathToRemoteSyncRootRelative(_folderFullRemotePath, _remoteFolderRoot);
_rootEncryptedFolderInfo = RootEncryptedFolderInfo(RootEncryptedFolderInfo::createRootPath(folderRelativePath, pathForTopLevelFolder));
}

void EncryptedFolderMetadataHandler::fetchMetadata(const FetchMode fetchMode)
Expand All @@ -53,9 +58,22 @@

void EncryptedFolderMetadataHandler::fetchMetadata(const RootEncryptedFolderInfo &rootEncryptedFolderInfo, const FetchMode fetchMode)
{
Q_ASSERT(!rootEncryptedFolderInfo.path.isEmpty());
if (rootEncryptedFolderInfo.path.isEmpty()) {
qCWarning(lcFetchAndUploadE2eeFolderMetadataJob) << "Error fetching metadata for" << _folderFullRemotePath << ". Invalid rootEncryptedFolderInfo!";
emit fetchFinished(-1, tr("Error fetching metadata."));
return;
}

_rootEncryptedFolderInfo = rootEncryptedFolderInfo;
if (_rootEncryptedFolderInfo.path.isEmpty()) {
qCWarning(lcFetchAndUploadE2eeFolderMetadataJob) << "Error fetching metadata for" << _folderPath << ". Invalid _rootEncryptedFolderInfo!";
qCWarning(lcFetchAndUploadE2eeFolderMetadataJob) << "Error fetching metadata for" << _folderFullRemotePath << ". Invalid _rootEncryptedFolderInfo!";
emit fetchFinished(-1, tr("Error fetching metadata."));
return;
}
if (_remoteFolderRoot != QStringLiteral("/") && !_folderFullRemotePath.startsWith(_remoteFolderRoot)) {
qCWarning(lcFetchAndUploadE2eeFolderMetadataJob) << "Error fetching metadata for" << _folderFullRemotePath
<< " and remote root" << _remoteFolderRoot << ". Invalid _remoteFolderRoot or _folderFullRemotePath!";
emit fetchFinished(-1, tr("Error fetching metadata."));
return;
}
Expand Down Expand Up @@ -99,7 +117,7 @@
void EncryptedFolderMetadataHandler::fetchFolderEncryptedId()
{
qCDebug(lcFetchAndUploadE2eeFolderMetadataJob) << "Folder is encrypted, let's get the Id from it.";
const auto job = new LsColJob(_account, _folderPath);
const auto job = new LsColJob(_account, _folderFullRemotePath);
job->setProperties({"resourcetype", "http://owncloud.org/ns:fileid"});
connect(job, &LsColJob::directoryListingSubfolders, this, &EncryptedFolderMetadataHandler::slotFolderEncryptedIdReceived);
connect(job, &LsColJob::finishedWithError, this, &EncryptedFolderMetadataHandler::slotFolderEncryptedIdError);
Expand Down Expand Up @@ -167,17 +185,17 @@

if (statusCode != 200 && statusCode != 404) {
// neither successfully fetched, nor a folder without a metadata, fail further logic
qCDebug(lcFetchAndUploadE2eeFolderMetadataJob) << "Error fetching metadata for folder" << _folderPath;
qCDebug(lcFetchAndUploadE2eeFolderMetadataJob) << "Error fetching metadata for folder" << _folderFullRemotePath;
emit fetchFinished(statusCode, tr("Error fetching metadata."));
return;
}

const auto rawMetadata = statusCode == 404
? QByteArray{} : json.toJson(QJsonDocument::Compact);
const auto metadata(QSharedPointer<FolderMetadata>::create(_account, rawMetadata, _rootEncryptedFolderInfo, job->signature()));
const auto metadata(QSharedPointer<FolderMetadata>::create(_account, _remoteFolderRoot, rawMetadata, _rootEncryptedFolderInfo, job->signature()));
connect(metadata.data(), &FolderMetadata::setupComplete, this, [this, metadata] {
if (!metadata->isValid()) {
qCDebug(lcFetchAndUploadE2eeFolderMetadataJob) << "Error parsing or decrypting metadata for folder" << _folderPath;
qCDebug(lcFetchAndUploadE2eeFolderMetadataJob) << "Error parsing or decrypting metadata for folder" << _folderFullRemotePath;
emit fetchFinished(-1, tr("Error parsing or decrypting metadata."));
return;
}
Expand Down
5 changes: 3 additions & 2 deletions src/libsync/encryptedfoldermetadatahandler.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check notice on line 1 in src/libsync/encryptedfoldermetadatahandler.h

View workflow job for this annotation

GitHub Actions / build

Run clang-format on src/libsync/encryptedfoldermetadatahandler.h

File src/libsync/encryptedfoldermetadatahandler.h does not conform to Custom style guidelines. (lines 53)
* Copyright (C) 2023 by Oleksandr Zolotov <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -50,7 +50,7 @@
};
Q_ENUM(UnlockFolderWithResult);

explicit EncryptedFolderMetadataHandler(const AccountPtr &account, const QString &folderPath, SyncJournalDb *const journalDb, const QString &pathForTopLevelFolder, QObject *parent = nullptr);
explicit EncryptedFolderMetadataHandler(const AccountPtr &account, const QString &folderPath, const QString &remoteFolderRoot, SyncJournalDb *const journalDb, const QString &pathForTopLevelFolder, QObject *parent = nullptr);

[[nodiscard]] QSharedPointer<FolderMetadata> folderMetadata() const;

Expand Down Expand Up @@ -101,8 +101,9 @@

private:
AccountPtr _account;
QString _folderPath;
QPointer<SyncJournalDb> _journalDb;
QString _folderFullRemotePath;
QString _remoteFolderRoot;
QByteArray _folderId;
QByteArray _folderToken;

Expand Down
Loading
Loading