Skip to content

Commit

Permalink
edit locally requires a valid token
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mgallien committed Oct 17, 2022
1 parent 615c02e commit f9949ee
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 19 deletions.
11 changes: 10 additions & 1 deletion src/gui/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
#include <QMessageBox>
#include <QDesktopServices>
#include <QGuiApplication>
#include <QUrlQuery>

class QSocket;

Expand Down Expand Up @@ -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)
Expand Down
55 changes: 38 additions & 17 deletions src/gui/folderman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/gui/folderman.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ class FolderMan : public QObject
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:
/**
Expand Down

0 comments on commit f9949ee

Please sign in to comment.