mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-28 08:52:19 -07:00
[Client/Server] Keep non-deck files out of the deck storage (#7352)
The local deck and replay browsers list every file in the folder, so a stray file (e.g. a PNG screenshot of a deck) can be parsed as a garbage plaintext deck, opened in the editor, and uploaded. The server also accepts oversized deck payloads with only silent truncation. Hide files that are not in a supported deck/replay format in the two QFileSystemModel views (directories stay visible), skip them when opening, reject them when uploading, and make the server reject deck uploads larger than MAX_FILE_LENGTH instead of truncating them. Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
fa8220df3c
commit
2632f8a040
3 changed files with 35 additions and 0 deletions
|
|
@ -14,6 +14,7 @@
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
|
#include <QDir>
|
||||||
#include <QFileSystemModel>
|
#include <QFileSystemModel>
|
||||||
#include <QGroupBox>
|
#include <QGroupBox>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
|
@ -49,6 +50,12 @@ namespace
|
||||||
// How long to wait after the last visibility change before reading back the
|
// How long to wait after the last visibility change before reading back the
|
||||||
// Public/Private column, in milliseconds.
|
// Public/Private column, in milliseconds.
|
||||||
constexpr int VISIBILITY_REFRESH_DELAY = 500;
|
constexpr int VISIBILITY_REFRESH_DELAY = 500;
|
||||||
|
|
||||||
|
// Whether the file's name matches one of the deck formats Cockatrice can load.
|
||||||
|
bool isSupportedDeckFile(const QString &filePath)
|
||||||
|
{
|
||||||
|
return QDir::match(DeckLoader::ACCEPTED_FILE_EXTENSIONS, QFileInfo(filePath).fileName());
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TabDeckStorage::TabDeckStorage(TabSupervisor *_tabSupervisor,
|
TabDeckStorage::TabDeckStorage(TabSupervisor *_tabSupervisor,
|
||||||
|
|
@ -58,6 +65,8 @@ TabDeckStorage::TabDeckStorage(TabSupervisor *_tabSupervisor,
|
||||||
{
|
{
|
||||||
localDirModel = new QFileSystemModel(this);
|
localDirModel = new QFileSystemModel(this);
|
||||||
localDirModel->setRootPath(SettingsCache::instance().paths().getDeckPath());
|
localDirModel->setRootPath(SettingsCache::instance().paths().getDeckPath());
|
||||||
|
localDirModel->setNameFilters(DeckLoader::ACCEPTED_FILE_EXTENSIONS);
|
||||||
|
localDirModel->setNameFilterDisables(false);
|
||||||
localDirModel->sort(0, Qt::AscendingOrder);
|
localDirModel->sort(0, Qt::AscendingOrder);
|
||||||
|
|
||||||
localDirView = new QTreeView;
|
localDirView = new QTreeView;
|
||||||
|
|
@ -312,6 +321,10 @@ void TabDeckStorage::actOpenLocalDeck()
|
||||||
}
|
}
|
||||||
QString filePath = localDirModel->filePath(curLeft);
|
QString filePath = localDirModel->filePath(curLeft);
|
||||||
|
|
||||||
|
if (!isSupportedDeckFile(filePath)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<LoadedDeck> deckOpt = DeckLoader::loadFromFile(filePath, DeckFileFormat::Cockatrice, true);
|
std::optional<LoadedDeck> deckOpt = DeckLoader::loadFromFile(filePath, DeckFileFormat::Cockatrice, true);
|
||||||
if (!deckOpt) {
|
if (!deckOpt) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -376,6 +389,11 @@ void TabDeckStorage::actUpload()
|
||||||
|
|
||||||
void TabDeckStorage::uploadDeck(const QString &filePath, const QString &targetPath)
|
void TabDeckStorage::uploadDeck(const QString &filePath, const QString &targetPath)
|
||||||
{
|
{
|
||||||
|
if (!isSupportedDeckFile(filePath)) {
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Invalid deck file"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QFile deckFile(filePath);
|
QFile deckFile(filePath);
|
||||||
QFileInfo deckFileInfo(deckFile);
|
QFileInfo deckFileInfo(deckFile);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
|
#include <QDir>
|
||||||
#include <QFileSystemModel>
|
#include <QFileSystemModel>
|
||||||
#include <QGroupBox>
|
#include <QGroupBox>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
|
@ -34,6 +35,12 @@
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(TabReplaysLog, "replays_tab");
|
inline Q_LOGGING_CATEGORY(TabReplaysLog, "replays_tab");
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// File name filters for the local replay files Cockatrice can load.
|
||||||
|
const QStringList REPLAY_FILE_NAME_FILTERS = {"*.cor"};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, const ServerInfo_User *currentUserInfo)
|
TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, const ServerInfo_User *currentUserInfo)
|
||||||
: Tab(_tabSupervisor), client(_client)
|
: Tab(_tabSupervisor), client(_client)
|
||||||
{
|
{
|
||||||
|
|
@ -62,6 +69,8 @@ QGroupBox *TabReplays::createLeftLayout()
|
||||||
{
|
{
|
||||||
localDirModel = new QFileSystemModel(this);
|
localDirModel = new QFileSystemModel(this);
|
||||||
localDirModel->setRootPath(SettingsCache::instance().paths().getReplaysPath());
|
localDirModel->setRootPath(SettingsCache::instance().paths().getReplaysPath());
|
||||||
|
localDirModel->setNameFilters(REPLAY_FILE_NAME_FILTERS);
|
||||||
|
localDirModel->setNameFilterDisables(false);
|
||||||
localDirModel->sort(0, Qt::AscendingOrder);
|
localDirModel->sort(0, Qt::AscendingOrder);
|
||||||
|
|
||||||
localDirView = new QTreeView;
|
localDirView = new QTreeView;
|
||||||
|
|
@ -263,6 +272,10 @@ void TabReplays::actOpenLocalReplay()
|
||||||
}
|
}
|
||||||
QString filePath = localDirModel->filePath(curLeft);
|
QString filePath = localDirModel->filePath(curLeft);
|
||||||
|
|
||||||
|
if (!QDir::match(REPLAY_FILE_NAME_FILTERS, QFileInfo(filePath).fileName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
QFile f(filePath);
|
QFile f(filePath);
|
||||||
if (!f.open(QIODevice::ReadOnly)) {
|
if (!f.open(QIODevice::ReadOnly)) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -982,6 +982,10 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckUpload(const Comman
|
||||||
return Response::RespInvalidData;
|
return Response::RespInvalidData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cmd.deck_list().size() > static_cast<std::string::size_type>(MAX_FILE_LENGTH)) {
|
||||||
|
return Response::RespInvalidData;
|
||||||
|
}
|
||||||
|
|
||||||
sqlInterface->checkSql();
|
sqlInterface->checkSql();
|
||||||
|
|
||||||
QString deckStr = fileFromStdString(cmd.deck_list());
|
QString deckStr = fileFromStdString(cmd.deck_list());
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue