Skip to content

Commit

Permalink
Add the restricted file names sanitization
Browse files Browse the repository at this point in the history
  • Loading branch information
winseros committed May 16, 2024
1 parent 72910ce commit 9292ebf
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 24 deletions.
42 changes: 30 additions & 12 deletions pbom/io/bb/__test__/sanitizedstring_test.cpp
Original file line number Diff line number Diff line change
@@ -1,26 +1,44 @@
#include "io/bb/sanitizedstring.h"
#include <QString>
#include <QRegularExpression>
#include <gtest/gtest.h>

namespace pboman3::io::test {
struct CtorParam {
struct SanitizedStringTestParam {
const QString sourceText;
const QString expectedText;
const QString expectedTextOrPattern;
};

class CtorTest : public testing::TestWithParam<CtorParam> {
class SanitizedStringRestrictedCharactersTest : public testing::TestWithParam<SanitizedStringTestParam> {
};

TEST_P(CtorTest, Deals_With_Restricted_Characters) {
TEST_P(SanitizedStringRestrictedCharactersTest, Deals_With_Restricted_Characters) {
SanitizedString ss(GetParam().sourceText);
ASSERT_EQ(static_cast<QString>(ss), GetParam().expectedText);
ASSERT_EQ(static_cast<QString>(ss), GetParam().expectedTextOrPattern);
}

INSTANTIATE_TEST_SUITE_P(SanitizedStringTest, CtorTest, testing::Values(
CtorParam{"\t1\t", "%91%9"},
CtorParam{"?1?", "%3f1%3f"},
CtorParam{"*1*", "%2a1%2a"},
CtorParam{"1///", "1%2f%2f%2f"},
CtorParam{"\\2", "%5c2"}
));
INSTANTIATE_TEST_SUITE_P(TestSuite, SanitizedStringRestrictedCharactersTest, testing::Values(
SanitizedStringTestParam{"\t1\t", "%91%9"},
SanitizedStringTestParam{"?1?", "%3f1%3f"},
SanitizedStringTestParam{"*1*", "%2a1%2a"},
SanitizedStringTestParam{"1///", "1%2f%2f%2f"},
SanitizedStringTestParam{"\\2", "%5c2"}
));

class SanitizedStringRestrictedKeywordsTest : public testing::TestWithParam<SanitizedStringTestParam> {
};

TEST_P(SanitizedStringRestrictedKeywordsTest, Deals_With_Restricted_Keywords) {
SanitizedString ss(GetParam().sourceText);
QRegularExpression re(GetParam().expectedTextOrPattern);
const QRegularExpressionMatch match = re.match(static_cast<QString>(ss));
ASSERT_TRUE(match.hasMatch());
}

INSTANTIATE_TEST_SUITE_P(TestSuite, SanitizedStringRestrictedKeywordsTest, testing::Values(
SanitizedStringTestParam{"COn", "^COn-\\d{1,4}"},
SanitizedStringTestParam{"COM1", "^COM1-\\d{1,4}"},
SanitizedStringTestParam{"lPt2", "^lPt2-\\d{1,4}"},
SanitizedStringTestParam{"NUL", "^NUL-\\d{1,4}"}
));
}
47 changes: 38 additions & 9 deletions pbom/io/bb/sanitizedstring.cpp
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
#include "sanitizedstring.h"
#include "util/filenames.h"
#include <QRandomGenerator>

namespace pboman3::io {
SanitizedString::SanitizedString(const QString& text)
: originalText_(nullptr) {
originalText_ = &text;
const QList<QString> SanitizedString::restrictedFileNames_ = {
"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3",
"COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7",
"LPT8", "LPT9"
};

if (qsizetype firstInvalidCharIndex; needsSanitization(text, &firstInvalidCharIndex)) {
sanitizedText_ = doSanitization(text, firstInvalidCharIndex);
SanitizedString::SanitizedString(const QString& text) {
if (qsizetype firstInvalidCharIndex; needsCharacterSanitization(text, &firstInvalidCharIndex)) {
sanitizedText_ = doCharacterSanitization(text, firstInvalidCharIndex);
} else if (QString keyWord; needsKeywordSanitization(text, &keyWord)) {
sanitizedText_ = doKeywordSanitization(text, keyWord);
} else {
sanitizedText_ = text;
}
}

SanitizedString::operator const QString&() {
return sanitizedText_.isEmpty() ? *originalText_ : sanitizedText_;
return sanitizedText_;
}

bool SanitizedString::needsSanitization(const QString& text, qsizetype* firstInvalidCharIndex) {
bool SanitizedString::needsCharacterSanitization(const QString& text, qsizetype* firstInvalidCharIndex) {
auto it = text.constBegin();
while (it != text.constEnd()) {
if (!isCharLegal(*it)) {
Expand All @@ -26,7 +35,19 @@ namespace pboman3::io {
return false;
}

QString SanitizedString::doSanitization(const QString& text, qsizetype firstInvalidCharIndex) {
bool SanitizedString::needsKeywordSanitization(const QString& text, QString* keyword) {
const QString& fileNameWithoutExtension = util::FileNames::getFileNameWithoutExtension(text);
const auto found = std::find_if(restrictedFileNames_.constBegin(), restrictedFileNames_.constEnd(), [&text](const QString& kwd){
return QString::compare(kwd, text, Qt::CaseInsensitive) == 0;
});
if (found != restrictedFileNames_.constEnd()){
*keyword = *found;
return true;
}
return false;
}

QString SanitizedString::doCharacterSanitization(const QString& text, qsizetype firstInvalidCharIndex) {
QString sanitized;
sanitized.reserve(static_cast<qsizetype>(static_cast<double>(text.size()) * 1.2));

Expand All @@ -49,13 +70,21 @@ namespace pboman3::io {
return sanitized;
}

QString SanitizedString::doKeywordSanitization(const QString& text, const QString& keyword) {
QString result(text);
const qint32 rnd = QRandomGenerator::global()->bounded(1000);
result.insert(keyword.length(), "-" + QString::number(rnd));
return result;
}

bool SanitizedString::isCharLegal(const QChar& chr) {
if (chr == '<' || chr == '>' || chr == ':' || chr == ':' || chr == '"' || chr == '\\' || chr == '/' ||
chr == '|' || chr == '?' || chr == '*' || chr == '{' || chr == '}') {
return false;
}

const auto res = chr.isLetterOrNumber() || ((chr.isSpace() || chr.isSymbol() || chr.isPunct()) && chr.isPrint());
const auto res =
chr.isLetterOrNumber() || ((chr.isSpace() || chr.isSymbol() || chr.isPunct()) && chr.isPrint());
return res;
}

Expand Down
12 changes: 9 additions & 3 deletions pbom/io/bb/sanitizedstring.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <QString>
#include <QList>

namespace pboman3::io {
class SanitizedString {
Expand All @@ -10,12 +11,17 @@ namespace pboman3::io {
operator const QString&();

private:
const QString* originalText_;
static const QList<QString> restrictedFileNames_;

QString sanitizedText_;

static bool needsSanitization(const QString& text, qsizetype* firstInvalidCharIndex);
static bool needsCharacterSanitization(const QString& text, qsizetype* firstInvalidCharIndex);

static QString doCharacterSanitization(const QString& text, qsizetype firstInvalidCharIndex);

static bool needsKeywordSanitization(const QString& text, QString* keyword);

static QString doSanitization(const QString& text, qsizetype firstInvalidCharIndex);
static QString doKeywordSanitization(const QString& text, const QString& keyword);

static bool isCharLegal(const QChar& chr);

Expand Down

0 comments on commit 9292ebf

Please sign in to comment.