Restrict filenames to alphanumeric characters

This commit is contained in:
Bart De Vries 2023-07-06 14:56:33 +02:00
parent dc311cac7b
commit 46fc8904ec
4 changed files with 26 additions and 4 deletions

View File

@ -13,6 +13,7 @@
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
#include <QFileInfo> #include <QFileInfo>
#include <QRegularExpression>
#include <QSqlDatabase> #include <QSqlDatabase>
#include <QSqlError> #include <QSqlError>
#include <QStandardPaths> #include <QStandardPaths>
@ -191,7 +192,8 @@ bool Database::migrateTo8()
QString name = query.value(QStringLiteral("name")).toString(); QString name = query.value(QStringLiteral("name")).toString();
// Generate directory name for enclosures based on feed name // Generate directory name for enclosures based on feed name
QString dirBaseName = name.left(maxFilenameLength); QString dirBaseName = name.remove(QRegularExpression(QStringLiteral("[^a-zA-Z0-9 ._()-]"))).simplified().left(maxFilenameLength);
dirBaseName = dirBaseName.isEmpty() ? QStringLiteral("Noname") : dirBaseName;
QString dirName = dirBaseName; QString dirName = dirBaseName;
// Check for duplicate names // Check for duplicate names
@ -226,8 +228,11 @@ bool Database::migrateTo8()
if (QFileInfo::exists(legacyPath) && QFileInfo(legacyPath).isFile()) { if (QFileInfo::exists(legacyPath) && QFileInfo(legacyPath).isFile()) {
// Generate filename based on episode name and url hash with feedname as subdirectory // Generate filename based on episode name and url hash with feedname as subdirectory
QString enclosureFilenameBase = queryTitle.left(maxFilenameLength) + QStringLiteral(".") QString enclosureFilenameBase = queryTitle.remove(QRegularExpression(QStringLiteral("[^a-zA-Z0-9 ._()-]"))).simplified().left(maxFilenameLength);
enclosureFilenameBase = enclosureFilenameBase.isEmpty() ? QStringLiteral("Noname") : enclosureFilenameBase;
enclosureFilenameBase += QStringLiteral(".")
+ QString::fromStdString(QCryptographicHash::hash(queryUrl.toUtf8(), QCryptographicHash::Md5).toHex().toStdString()).left(6); + QString::fromStdString(QCryptographicHash::hash(queryUrl.toUtf8(), QCryptographicHash::Md5).toHex().toStdString()).left(6);
QString enclosureFilenameExt = QFileInfo(QUrl::fromUserInput(queryUrl).fileName()).suffix(); QString enclosureFilenameExt = QFileInfo(QUrl::fromUserInput(queryUrl).fileName()).suffix();
QString enclosureFilename = QString enclosureFilename =

View File

@ -14,6 +14,7 @@
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
#include <QFileInfo> #include <QFileInfo>
#include <QRegularExpression>
#include <QStandardPaths> #include <QStandardPaths>
#include "enclosure.h" #include "enclosure.h"
@ -138,8 +139,9 @@ QString StorageManager::enclosureDirPath(const QString &feedname) const
QString StorageManager::enclosurePath(const QString &name, const QString &url, const QString &feedname) const QString StorageManager::enclosurePath(const QString &name, const QString &url, const QString &feedname) const
{ {
// Generate filename based on episode name and url hash with feedname as subdirectory // Generate filename based on episode name and url hash with feedname as subdirectory
QString enclosureFilenameBase = name.left(maxFilenameLength) + QStringLiteral(".") QString enclosureFilenameBase = sanitizedFilePath(name) + QStringLiteral(".")
+ QString::fromStdString(QCryptographicHash::hash(url.toUtf8(), QCryptographicHash::Md5).toHex().toStdString()).left(6); + QString::fromStdString(QCryptographicHash::hash(url.toUtf8(), QCryptographicHash::Md5).toHex().toStdString()).left(6);
QString enclosureFilenameExt = QFileInfo(QUrl::fromUserInput(url).fileName()).suffix(); QString enclosureFilenameExt = QFileInfo(QUrl::fromUserInput(url).fileName()).suffix();
QString enclosureFilename = !enclosureFilenameExt.isEmpty() ? enclosureFilenameBase + QStringLiteral(".") + enclosureFilenameExt : enclosureFilenameBase; QString enclosureFilename = !enclosureFilenameExt.isEmpty() ? enclosureFilenameBase + QStringLiteral(".") + enclosureFilenameExt : enclosureFilenameBase;
@ -205,3 +207,16 @@ QString StorageManager::passwordFilePath(const QString &username) const
{ {
return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/") + username; return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/") + username;
} }
QString StorageManager::sanitizedFilePath(const QString &path) const
{
// NOTE: Any changes here require a database migration!
// Only keep alphanumeric ascii characters; this avoid any kind of issues
// with the many types of filesystems out there. Then remove excess whitespace
// and limit the length of the string.
QString newPath = path;
newPath = newPath.remove(QRegularExpression(QStringLiteral("[^a-zA-Z0-9 ._()-]"))).simplified().left(maxFilenameLength);
return newPath.isEmpty() ? QStringLiteral("Noname") : newPath;
}

View File

@ -56,6 +56,8 @@ public:
QString passwordFilePath(const QString &username) const; QString passwordFilePath(const QString &username) const;
QString sanitizedFilePath(const QString &path) const;
Q_SIGNALS: Q_SIGNALS:
void error(Error::Type type, const QString &url, const QString &id, const int errorId, const QString &errorString, const QString &title); void error(Error::Type type, const QString &url, const QString &id, const int errorId, const QString &errorString, const QString &title);

View File

@ -698,7 +698,7 @@ QString UpdateFeedJob::generateFeedDirname(const QString &name) const
{ {
// Generate directory name for enclosures based on feed name // Generate directory name for enclosures based on feed name
// NOTE: Any changes here require a database migration! // NOTE: Any changes here require a database migration!
QString dirBaseName = name.left(StorageManager::maxFilenameLength); QString dirBaseName = StorageManager::instance().sanitizedFilePath(name);
QString dirName = dirBaseName; QString dirName = dirBaseName;
QStringList dirNameList; QStringList dirNameList;