From: Matthieu Gallien Date: Wed, 12 Oct 2022 16:01:15 +0000 (+0200) Subject: edit locally requires a valid token X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~12^2~11^2~204^2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=f9949ee0de1b8a42412f528dc1f64e080eb44316;p=nextcloud-desktop.git edit locally requires a valid token check on server that the token received during a request to open a local file is indeed a valid one Signed-off-by: Matthieu Gallien --- diff --git a/src/gui/application.cpp b/src/gui/application.cpp index 21cce1a67..6f891e022 100644 --- a/src/gui/application.cpp +++ b/src/gui/application.cpp @@ -61,6 +61,7 @@ #include #include #include +#include class QSocket; @@ -764,8 +765,16 @@ void Application::handleEditLocally(const QUrl &url) const // for a sample URL "nc://open/admin@nextcloud.lan:8080/Photos/lovely.jpg", QUrl::path would return "admin@nextcloud.lan:8080/Photos/lovely.jpg" const auto accountDisplayName = pathSplit.takeFirst(); const auto fileRemotePath = pathSplit.join('/'); + const auto urlQuery = QUrlQuery{url}; - FolderMan::instance()->editFileLocally(accountDisplayName, fileRemotePath); + auto token = QString{}; + if (urlQuery.hasQueryItem(QStringLiteral("token"))) { + token = urlQuery.queryItemValue(QStringLiteral("token")); + } else { + qCWarning(lcApplication) << "Invalid URL for file local editing: missing token"; + } + + FolderMan::instance()->editFileLocally(accountDisplayName, fileRemotePath, token); } QString substLang(const QString &lang) diff --git a/src/gui/folderman.cpp b/src/gui/folderman.cpp index 220313891..d76a4fccd 100644 --- a/src/gui/folderman.cpp +++ b/src/gui/folderman.cpp @@ -1422,7 +1422,7 @@ void FolderMan::setDirtyNetworkLimits() } } -void FolderMan::editFileLocally(const QString &accountDisplayName, const QString &relPath) +void FolderMan::editFileLocally(const QString &accountDisplayName, const QString &relPath, const QString &token) { const auto showError = [this](const OCC::AccountStatePtr accountState, const QString &errorMessage, const QString &subject) { if (accountState && accountState->account()) { @@ -1447,6 +1447,12 @@ void FolderMan::editFileLocally(const QString &accountDisplayName, const QString messageBox->raise(); }; + if (token.isEmpty()) { + qCWarning(lcFolderMan) << "Edit locally request is missing a valid token. Impossible to open the file."; + showError({}, tr("Edit locally request is not valid. Opening the file is forbidden."), accountDisplayName); + return; + } + const auto accountFound = AccountManager::instance()->account(accountDisplayName); if (!accountFound) { @@ -1488,23 +1494,38 @@ void FolderMan::editFileLocally(const QString &accountDisplayName, const QString showError(accountFound, tr("Could not find a file for local editing. Make sure its path is valid and it is synced locally."), relPath); return; } - folderForFile->startSync(); - _localFileEditingSyncFinishedConnections.insert(localFilePath, QObject::connect(folderForFile, &Folder::syncFinished, this, - [this, localFilePath](const OCC::SyncResult &result) { - Q_UNUSED(result); - const auto foundConnectionIt = _localFileEditingSyncFinishedConnections.find(localFilePath); - if (foundConnectionIt != std::end(_localFileEditingSyncFinishedConnections) && foundConnectionIt.value()) { - QObject::disconnect(foundConnectionIt.value()); - _localFileEditingSyncFinishedConnections.erase(foundConnectionIt); - } - // In case the VFS mode is enabled and a file is not yet hydrated, we must call QDesktopServices::openUrl - // from a separate thread, or, there will be a freeze. To avoid searching for a specific folder and checking - // if the VFS is enabled - we just always call it from a separate thread. - QtConcurrent::run([localFilePath]() { - QDesktopServices::openUrl(QUrl::fromLocalFile(localFilePath)); + + const auto checkTokenForEditLocally = new SimpleApiJob(accountFound->account(), QStringLiteral("/ocs/v2.php/apps/files/api/v1/openlocaleditor/%1").arg(token)); + checkTokenForEditLocally->setVerb(SimpleApiJob::Verb::Post); + checkTokenForEditLocally->setBody(QByteArray{"path=/"}.append(relPath.toUtf8())); + connect(checkTokenForEditLocally, &SimpleApiJob::resultReceived, checkTokenForEditLocally, [this, folderForFile, localFilePath, showError, accountFound, relPath] (int statusCode) { + constexpr auto HTTP_OK_CODE = 200; + if (statusCode != HTTP_OK_CODE) { Systray::instance()->destroyEditFileLocallyLoadingDialog(); - }); - })); + showError(accountFound, tr("Could not validate the request to open a file from server."), relPath); + qCInfo(lcFolderMan()) << "token check result" << statusCode; + return; + } + + folderForFile->startSync(); + _localFileEditingSyncFinishedConnections.insert(localFilePath, QObject::connect(folderForFile, &Folder::syncFinished, this, + [this, localFilePath](const OCC::SyncResult &result) { + Q_UNUSED(result); + const auto foundConnectionIt = _localFileEditingSyncFinishedConnections.find(localFilePath); + if (foundConnectionIt != std::end(_localFileEditingSyncFinishedConnections) && foundConnectionIt.value()) { + QObject::disconnect(foundConnectionIt.value()); + _localFileEditingSyncFinishedConnections.erase(foundConnectionIt); + } + // In case the VFS mode is enabled and a file is not yet hydrated, we must call QDesktopServices::openUrl + // from a separate thread, or, there will be a freeze. To avoid searching for a specific folder and checking + // if the VFS is enabled - we just always call it from a separate thread. + QtConcurrent::run([localFilePath]() { + QDesktopServices::openUrl(QUrl::fromLocalFile(localFilePath)); + Systray::instance()->destroyEditFileLocallyLoadingDialog(); + }); + })); + }); + checkTokenForEditLocally->start(); } void FolderMan::trayOverallStatus(const QList &folders, diff --git a/src/gui/folderman.h b/src/gui/folderman.h index 77a6b6682..2c9b920e6 100644 --- a/src/gui/folderman.h +++ b/src/gui/folderman.h @@ -214,7 +214,7 @@ public: void setDirtyNetworkLimits(); /** opens a file with default app, if the file is present **/ - void editFileLocally(const QString &accountDisplayName, const QString &relPath); + void editFileLocally(const QString &accountDisplayName, const QString &relPath, const QString &token); signals: /**