Bugfix. E2EE V2. Fix incorrect root e2ee folder path search in local db.

Signed-off-by: alex-z <blackslayer4@gmail.com>
This commit is contained in:
alex-z 2024-02-24 17:47:03 +01:00
parent 38f23827ec
commit c0e0b53ee5
18 changed files with 122 additions and 23 deletions

View File

@ -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

View File

@ -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);

View File

@ -447,7 +447,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));

View File

@ -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());

View File

@ -162,6 +162,8 @@ public:
*/
QString remotePathTrailingSlash() const;
[[nodiscard]] QString fulllRemotePathToPathInSyncJournalDb(const QString &fullRemotePath) const;
void setNavigationPaneClsid(const QUuid &clsid) { _definition.navigationPaneClsid = clsid; }
QUuid navigationPaneClsid() const { return _definition.navigationPaneClsid; }

View File

@ -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) {

View File

@ -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;
}

View File

@ -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()));
}
@ -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;
@ -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;
}

View File

@ -36,6 +36,8 @@ public:
explicit EncryptFolderJob(const AccountPtr &account,
SyncJournalDb *journal,
const QString &path,
const QString &pathNonEncrypted,
const QString &_remoteSyncRootPath,
const QByteArray &fileId,
OwncloudPropagator *propagator = nullptr,
SyncFileItemPtr item = {},
@ -47,9 +49,6 @@ public:
signals:
void finished(int status, EncryptionStatusEnums::ItemEncryptionStatus encryptionStatus);
public slots:
void setPathNonEncrypted(const QString &pathNonEncrypted);
private:
void uploadMetadata();
@ -64,6 +63,7 @@ private:
SyncJournalDb *_journal;
QString _path;
QString _pathNonEncrypted;
QString _remoteSyncRootPath;
QByteArray _fileId;
QString _errorString;
OwncloudPropagator *_propagator = nullptr;

View File

@ -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;

View File

@ -526,6 +526,8 @@ public:
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);

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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;
}
@ -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;
}

View File

@ -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;
}
@ -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;
}

View File

@ -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;
}

View File

@ -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)