mirror of https://github.com/nextcloud/desktop
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:
parent
38f23827ec
commit
c0e0b53ee5
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue