improve invalid path name
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit a7a1b28765
)
This commit is contained in:
parent
5934849d87
commit
8984cd5f66
@ -74,6 +74,7 @@
|
|||||||
#include <objbase.h>
|
#include <objbase.h>
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
#else
|
#else
|
||||||
|
#include <sys/statvfs.h>
|
||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -801,25 +802,97 @@ QString NormalizePath(QString path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QString BAD_PATH_CHARS = "\"?<>:;*|!\r\n";
|
QString removeDuplicates(QString a)
|
||||||
static const QString BAD_FILENAME_CHARS = BAD_PATH_CHARS + "\\/";
|
{
|
||||||
|
auto b = a.split("");
|
||||||
|
b.removeDuplicates();
|
||||||
|
return b.join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString getFileSystemType(const QString& path)
|
||||||
|
{
|
||||||
|
QString fileSystemType;
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
wchar_t volume[MAX_PATH + 1] = { 0 };
|
||||||
|
if (GetVolumeInformationW((LPCWSTR)path.utf16(), nullptr, 0, nullptr, nullptr, nullptr, volume, MAX_PATH)) {
|
||||||
|
fileSystemType = QString::fromWCharArray(volume);
|
||||||
|
}
|
||||||
|
#elif defined(Q_OS_UNIX)
|
||||||
|
struct statvfs buf;
|
||||||
|
if (statvfs(path.toUtf8().constData(), &buf) == 0) {
|
||||||
|
switch (buf.f_type) {
|
||||||
|
case 0x4d44: // "MSDOS"
|
||||||
|
fileSystemType = "FAT32";
|
||||||
|
break;
|
||||||
|
case 0x5346544e: // "NTFS"
|
||||||
|
fileSystemType = "NTFS";
|
||||||
|
break;
|
||||||
|
case 0x4244: // "HFS+" or "H+" on some systems
|
||||||
|
case 0x482b: // "HFS+" or "H+" on some systems
|
||||||
|
fileSystemType = "HFS+";
|
||||||
|
break;
|
||||||
|
case 0x41465342: // "APFS"
|
||||||
|
fileSystemType = "APFS";
|
||||||
|
break;
|
||||||
|
case 0x65735546: // "exFAT"
|
||||||
|
fileSystemType = "exFAT";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return fileSystemType;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const QString BAD_WIN_CHARS = "\"?<>:*|\r\n";
|
||||||
|
|
||||||
|
static const QString BAD_FAT32_CHARS = "<>:\"|?*+.,;=[]!";
|
||||||
|
static const QString BAD_NTFS_CHARS = "<>:\"|?*";
|
||||||
|
static const QString BAD_HFS_CHARS = ":";
|
||||||
|
static const QString BAD_EXFAT_CHARS = "<>:\"|?*";
|
||||||
|
|
||||||
|
static const QString BAD_FILENAME_CHARS =
|
||||||
|
removeDuplicates(BAD_WIN_CHARS + BAD_FAT32_CHARS + BAD_NTFS_CHARS + BAD_HFS_CHARS + BAD_EXFAT_CHARS) + "\\/";
|
||||||
|
|
||||||
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith)
|
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < string.length(); i++)
|
for (int i = 0; i < string.length(); i++)
|
||||||
if (string.at(i) < ' ' || BAD_FILENAME_CHARS.contains(string.at(i)))
|
if (string.at(i) < ' ' || BAD_FILENAME_CHARS.contains(string.at(i)))
|
||||||
string[i] = replaceWith;
|
string[i] = replaceWith;
|
||||||
|
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString RemoveInvalidPathChars(QString string, QChar replaceWith)
|
QString RemoveInvalidPathChars(QString path, QChar replaceWith)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < string.length(); i++)
|
QString invalidChars;
|
||||||
if (string.at(i) < ' ' || BAD_PATH_CHARS.contains(string.at(i)))
|
#ifdef Q_OS_WIN
|
||||||
string[i] = replaceWith;
|
invalidChars = BAD_WIN_CHARS;
|
||||||
|
#endif
|
||||||
|
|
||||||
return string;
|
QString fileSystemType = getFileSystemType(QFileInfo(path).absolutePath());
|
||||||
|
|
||||||
|
if (fileSystemType == "FAT32") {
|
||||||
|
invalidChars += BAD_FAT32_CHARS;
|
||||||
|
} else if (fileSystemType == "NTFS") {
|
||||||
|
invalidChars += BAD_NTFS_CHARS;
|
||||||
|
} else if (fileSystemType == "HFS+" || fileSystemType == "APFS") {
|
||||||
|
invalidChars += BAD_HFS_CHARS;
|
||||||
|
} else if (fileSystemType == "exFAT") {
|
||||||
|
invalidChars += BAD_EXFAT_CHARS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalidChars.size() != 0) {
|
||||||
|
for (int i = 0; i < path.length(); i++) {
|
||||||
|
if (path.at(i) < ' ' || invalidChars.contains(path.at(i))) {
|
||||||
|
path[i] = replaceWith;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DirNameFromString(QString string, QString inDir)
|
QString DirNameFromString(QString string, QString inDir)
|
||||||
|
@ -288,9 +288,7 @@ std::optional<QStringList> extractSubDir(QuaZip* zip, const QString& subdir, con
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
QString file_name = zip->getCurrentFileName();
|
QString file_name = zip->getCurrentFileName();
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
file_name = FS::RemoveInvalidPathChars(file_name);
|
file_name = FS::RemoveInvalidPathChars(file_name);
|
||||||
#endif
|
|
||||||
if (!file_name.startsWith(subdir))
|
if (!file_name.startsWith(subdir))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ void Library::getApplicableFiles(const RuntimeContext& runtimeContext,
|
|||||||
{
|
{
|
||||||
bool local = isLocal();
|
bool local = isLocal();
|
||||||
auto actualPath = [&](QString relPath) {
|
auto actualPath = [&](QString relPath) {
|
||||||
|
relPath = FS::RemoveInvalidPathChars(relPath);
|
||||||
QFileInfo out(FS::PathCombine(storagePrefix(), relPath));
|
QFileInfo out(FS::PathCombine(storagePrefix(), relPath));
|
||||||
if (local && !overridePath.isEmpty()) {
|
if (local && !overridePath.isEmpty()) {
|
||||||
QString fileName = out.fileName();
|
QString fileName = out.fileName();
|
||||||
|
@ -538,9 +538,7 @@ void FlameCreationTask::setupDownloadJob(QEventLoop& loop)
|
|||||||
}
|
}
|
||||||
for (const auto& result : results) {
|
for (const auto& result : results) {
|
||||||
auto fileName = result.fileName;
|
auto fileName = result.fileName;
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
fileName = FS::RemoveInvalidPathChars(fileName);
|
fileName = FS::RemoveInvalidPathChars(fileName);
|
||||||
#endif
|
|
||||||
auto relpath = FS::PathCombine(result.targetFolder, fileName);
|
auto relpath = FS::PathCombine(result.targetFolder, fileName);
|
||||||
|
|
||||||
if (!result.required && !selectedOptionalMods.contains(relpath)) {
|
if (!result.required && !selectedOptionalMods.contains(relpath)) {
|
||||||
|
@ -139,9 +139,7 @@ auto FlameMod::loadIndexedPackVersion(QJsonObject& obj, bool load_changelog) ->
|
|||||||
file.version = Json::requireString(obj, "displayName");
|
file.version = Json::requireString(obj, "displayName");
|
||||||
file.downloadUrl = Json::ensureString(obj, "downloadUrl");
|
file.downloadUrl = Json::ensureString(obj, "downloadUrl");
|
||||||
file.fileName = Json::requireString(obj, "fileName");
|
file.fileName = Json::requireString(obj, "fileName");
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
file.fileName = FS::RemoveInvalidPathChars(file.fileName);
|
file.fileName = FS::RemoveInvalidPathChars(file.fileName);
|
||||||
#endif
|
|
||||||
|
|
||||||
ModPlatform::IndexedVersionType::VersionType ver_type;
|
ModPlatform::IndexedVersionType::VersionType ver_type;
|
||||||
switch (Json::requireInteger(obj, "releaseType")) {
|
switch (Json::requireInteger(obj, "releaseType")) {
|
||||||
|
@ -239,9 +239,7 @@ bool ModrinthCreationTask::createInstance()
|
|||||||
|
|
||||||
for (auto file : m_files) {
|
for (auto file : m_files) {
|
||||||
auto fileName = file.path;
|
auto fileName = file.path;
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
fileName = FS::RemoveInvalidPathChars(fileName);
|
fileName = FS::RemoveInvalidPathChars(fileName);
|
||||||
#endif
|
|
||||||
auto file_path = FS::PathCombine(root_modpack_path, fileName);
|
auto file_path = FS::PathCombine(root_modpack_path, fileName);
|
||||||
if (!root_modpack_url.isParentOf(QUrl::fromLocalFile(file_path))) {
|
if (!root_modpack_url.isParentOf(QUrl::fromLocalFile(file_path))) {
|
||||||
// This means we somehow got out of the root folder, so abort here to prevent exploits
|
// This means we somehow got out of the root folder, so abort here to prevent exploits
|
||||||
|
@ -227,9 +227,7 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_t
|
|||||||
if (parent.contains("url")) {
|
if (parent.contains("url")) {
|
||||||
file.downloadUrl = Json::requireString(parent, "url");
|
file.downloadUrl = Json::requireString(parent, "url");
|
||||||
file.fileName = Json::requireString(parent, "filename");
|
file.fileName = Json::requireString(parent, "filename");
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
file.fileName = FS::RemoveInvalidPathChars(file.fileName);
|
file.fileName = FS::RemoveInvalidPathChars(file.fileName);
|
||||||
#endif
|
|
||||||
file.is_preferred = Json::requireBoolean(parent, "primary") || (files.count() == 1);
|
file.is_preferred = Json::requireBoolean(parent, "primary") || (files.count() == 1);
|
||||||
auto hash_list = Json::requireObject(parent, "hashes");
|
auto hash_list = Json::requireObject(parent, "hashes");
|
||||||
|
|
||||||
|
@ -84,9 +84,7 @@ auto HttpMetaCache::getEntry(QString base, QString resource_path) -> MetaEntryPt
|
|||||||
|
|
||||||
auto HttpMetaCache::resolveEntry(QString base, QString resource_path, QString expected_etag) -> MetaEntryPtr
|
auto HttpMetaCache::resolveEntry(QString base, QString resource_path, QString expected_etag) -> MetaEntryPtr
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
resource_path = FS::RemoveInvalidPathChars(resource_path);
|
resource_path = FS::RemoveInvalidPathChars(resource_path);
|
||||||
#endif
|
|
||||||
auto entry = getEntry(base, resource_path);
|
auto entry = getEntry(base, resource_path);
|
||||||
// it's not present? generate a default stale entry
|
// it's not present? generate a default stale entry
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
|
Loading…
Reference in New Issue
Block a user