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 <matthieu.gallien@nextcloud.com>
This commit is contained in:
Matthieu Gallien 2022-10-12 18:01:15 +02:00
parent 615c02e3d3
commit f9949ee0de
No known key found for this signature in database
GPG Key ID: 7D0F74F05C22F553
3 changed files with 49 additions and 19 deletions

View File

@ -61,6 +61,7 @@
#include <QMessageBox>
#include <QDesktopServices>
#include <QGuiApplication>
#include <QUrlQuery>
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)

View File

@ -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<Folder *> &folders,

View File

@ -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:
/**