diff --git a/app/test/testcoreutils.cpp b/app/test/testcoreutils.cpp index 23d6d78e7..b4d8117b4 100644 --- a/app/test/testcoreutils.cpp +++ b/app/test/testcoreutils.cpp @@ -176,7 +176,7 @@ void TestCoreUtils::testNameValidation() { QStringLiteral( "-project" ), true }, { QStringLiteral( "proj_ect" ), true }, { QStringLiteral( "proj.ect" ), true }, - { QStringLiteral( "proj!ect" ), true }, + { QStringLiteral( "proj!ect" ), false }, { QStringLiteral( " project" ), false }, { QStringLiteral( ".project" ), false }, diff --git a/core/coreutils.cpp b/core/coreutils.cpp index a17b38aa8..143e1f81b 100644 --- a/core/coreutils.cpp +++ b/core/coreutils.cpp @@ -271,9 +271,27 @@ bool CoreUtils::isAuthConfigFile( const QString filePath ) bool CoreUtils::isValidName( const QString &name ) { - static QRegularExpression reForbiddenmNames( R"([@#$%^&*\(\)\{\}\[\]\\\/\|\+=<>~\?:;,`\'\"]|^[\s^\.].*$|^CON$|^PRN$|^AUX$|^NUL$|^COM\d$|^LPT\d|^support$|^helpdesk$|^merginmaps$|^lutraconsulting$|^mergin$|^lutra$|^input$|^sales$|^admin$)", QRegularExpression::CaseInsensitiveOption ); - QRegularExpressionMatch matchForbiddenNames = reForbiddenmNames.match( name ); - return !matchForbiddenNames.hasMatch(); + if ( name.length() > 255 ) + return false; + + // name must not start with whitespace, '^' or '.' + static QRegularExpression invalidFirstCharacterRe( R"(^[\s^\.].*$)", QRegularExpression::CaseInsensitiveOption ); + if ( invalidFirstCharacterRe.match( name ).hasMatch() ) + return false; + + // name must not be a reserved Windows device filename (CON, PRN, AUX, NUL, COM1-9, LPT1-9) + static QRegularExpression invalidFilenameRe( R"(^CON$|^PRN$|^AUX$|^NUL$|^COM\d$|^LPT\d)", QRegularExpression::CaseInsensitiveOption ); + if ( invalidFilenameRe.match( name ).hasMatch() ) + return false; + + // name must not be a word reserved by Mergin Maps / Lutra Consulting + static QRegularExpression reservedWordRe( R"(^support$|^helpdesk$|^merginmaps$|^lutraconsulting$|^mergin$|^lutra$|^input$|^sales$|^admin$)", QRegularExpression::CaseInsensitiveOption ); + if ( reservedWordRe.match( name ).hasMatch() ) + return false; + + // name must contain only word characters, whitespace, '-' or '.' + static QRegularExpression validCharactersRe( R"(^[\w\s\-\.]+$)", QRegularExpression::UseUnicodePropertiesOption ); + return validCharactersRe.match( name ).hasMatch(); } QString CoreUtils::nameAbbr( const QString &name, const QString &email )