aboutsummaryrefslogtreecommitdiffstats
path: root/tests/lib/Files/FilenameValidatorTest.php
diff options
context:
space:
mode:
Diffstat (limited to 'tests/lib/Files/FilenameValidatorTest.php')
-rw-r--r--tests/lib/Files/FilenameValidatorTest.php244
1 files changed, 224 insertions, 20 deletions
diff --git a/tests/lib/Files/FilenameValidatorTest.php b/tests/lib/Files/FilenameValidatorTest.php
index ac9ac032b64..162275a2cf8 100644
--- a/tests/lib/Files/FilenameValidatorTest.php
+++ b/tests/lib/Files/FilenameValidatorTest.php
@@ -48,9 +48,7 @@ class FilenameValidatorTest extends TestCase {
$this->database->method('supports4ByteText')->willReturn(true);
}
- /**
- * @dataProvider dataValidateFilename
- */
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataValidateFilename')]
public function testValidateFilename(
string $filename,
array $forbiddenNames,
@@ -87,9 +85,7 @@ class FilenameValidatorTest extends TestCase {
$validator->validateFilename($filename);
}
- /**
- * @dataProvider dataValidateFilename
- */
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataValidateFilename')]
public function testIsFilenameValid(
string $filename,
array $forbiddenNames,
@@ -122,7 +118,7 @@ class FilenameValidatorTest extends TestCase {
$this->assertEquals($exception === null, $validator->isFilenameValid($filename));
}
- public function dataValidateFilename(): array {
+ public static function dataValidateFilename(): array {
return [
'valid name' => [
'a: b.txt', ['.htaccess'], [], [], [], null
@@ -146,6 +142,10 @@ class FilenameValidatorTest extends TestCase {
// needed for Windows namespaces
'com1.suffix', ['.htaccess'], ['com1'], [], [], ReservedWordException::class
],
+ 'forbidden basename case insensitive' => [
+ // needed for Windows namespaces
+ 'COM1.suffix', ['.htaccess'], ['com1'], [], [], ReservedWordException::class
+ ],
'forbidden basename for hidden files' => [
// needed for Windows namespaces
'.thumbs.db', ['.htaccess'], ['.thumbs'], [], [], ReservedWordException::class
@@ -159,6 +159,9 @@ class FilenameValidatorTest extends TestCase {
'invalid extension' => [
'a: b.txt', ['.htaccess'], [], ['.txt'], [], InvalidPathException::class
],
+ 'invalid extension case insensitive' => [
+ 'a: b.TXT', ['.htaccess'], [], ['.txt'], [], InvalidPathException::class
+ ],
'empty filename' => [
'', [], [], [], [], EmptyFileNameException::class
],
@@ -182,9 +185,7 @@ class FilenameValidatorTest extends TestCase {
];
}
- /**
- * @dataProvider data4ByteUnicode
- */
+ #[\PHPUnit\Framework\Attributes\DataProvider('data4ByteUnicode')]
public function testDatabaseDoesNotSupport4ByteText($filename): void {
$database = $this->createMock(IDBConnection::class);
$database->expects($this->once())
@@ -195,24 +196,21 @@ class FilenameValidatorTest extends TestCase {
$validator->validateFilename($filename);
}
- public function data4ByteUnicode(): array {
+ public static function data4ByteUnicode(): array {
return [
['plane 1 πͺ…'],
['emoji πŸ˜Άβ€πŸŒ«οΈ'],
-
];
}
- /**
- * @dataProvider dataInvalidAsciiCharacters
- */
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataInvalidAsciiCharacters')]
public function testInvalidAsciiCharactersAreAlwaysForbidden(string $filename): void {
$this->expectException(InvalidPathException::class);
$validator = new FilenameValidator($this->l10n, $this->database, $this->config, $this->logger);
$validator->validateFilename($filename);
}
- public function dataInvalidAsciiCharacters(): array {
+ public static function dataInvalidAsciiCharacters(): array {
return [
[\chr(0)],
[\chr(1)],
@@ -249,9 +247,7 @@ class FilenameValidatorTest extends TestCase {
];
}
- /**
- * @dataProvider dataIsForbidden
- */
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataIsForbidden')]
public function testIsForbidden(string $filename, array $forbiddenNames, bool $expected): void {
/** @var FilenameValidator&MockObject */
$validator = $this->getMockBuilder(FilenameValidator::class)
@@ -265,7 +261,7 @@ class FilenameValidatorTest extends TestCase {
$this->assertEquals($expected, $validator->isForbidden($filename));
}
- public function dataIsForbidden(): array {
+ public static function dataIsForbidden(): array {
return [
'valid name' => [
'a: b.txt', ['.htaccess'], false
@@ -284,4 +280,212 @@ class FilenameValidatorTest extends TestCase {
],
];
}
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataGetForbiddenExtensions')]
+ public function testGetForbiddenExtensions(array $configValue, array $expectedValue): void {
+ $validator = new FilenameValidator($this->l10n, $this->database, $this->config, $this->logger);
+ $this->config
+ // only once - then cached
+ ->expects(self::once())
+ ->method('getSystemValue')
+ ->with('forbidden_filename_extensions', ['.filepart'])
+ ->willReturn($configValue);
+
+ self::assertEqualsCanonicalizing($expectedValue, $validator->getForbiddenExtensions());
+ }
+
+ public static function dataGetForbiddenExtensions(): array {
+ return [
+ // default
+ [['.filepart'], ['.filepart', '.part']],
+ // always include .part
+ [[], ['.part']],
+ // handle case insensitivity
+ [['.TXT'], ['.txt', '.part']],
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataGetForbiddenFilenames')]
+ public function testGetForbiddenFilenames(array $configValue, array $legacyValue, array $expectedValue): void {
+ $validator = new FilenameValidator($this->l10n, $this->database, $this->config, $this->logger);
+ $this->config
+ // only once - then cached
+ ->expects(self::exactly(2))
+ ->method('getSystemValue')
+ ->willReturnMap([
+ ['forbidden_filenames', ['.htaccess'], $configValue],
+ ['blacklisted_files', [], $legacyValue],
+ ]);
+
+ $this->logger
+ ->expects(empty($legacyValue) ? self::never() : self::once())
+ ->method('warning');
+
+ self::assertEqualsCanonicalizing($expectedValue, $validator->getForbiddenFilenames());
+ }
+
+ public static function dataGetForbiddenFilenames(): array {
+ return [
+ // default
+ [['.htaccess'], [], ['.htaccess']],
+ // with legacy values
+ [['.htaccess'], ['legacy'], ['.htaccess', 'legacy']],
+ // handle case insensitivity
+ [['FileName', '.htaccess'], ['LegAcy'], ['.htaccess', 'filename', 'legacy']],
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataGetForbiddenBasenames')]
+ public function testGetForbiddenBasenames(array $configValue, array $expectedValue): void {
+ $validator = new FilenameValidator($this->l10n, $this->database, $this->config, $this->logger);
+ $this->config
+ // only once - then cached
+ ->expects(self::once())
+ ->method('getSystemValue')
+ ->with('forbidden_filename_basenames', [])
+ ->willReturn($configValue);
+
+ self::assertEqualsCanonicalizing($expectedValue, $validator->getForbiddenBasenames());
+ }
+
+ public static function dataGetForbiddenBasenames(): array {
+ return [
+ // default
+ [[], []],
+ // with values
+ [['aux', 'com0'], ['aux', 'com0']],
+ // handle case insensitivity
+ [['AuX', 'COM1'], ['aux', 'com1']],
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataSanitizeFilename')]
+ public function testSanitizeFilename(
+ string $filename,
+ array $forbiddenNames,
+ array $forbiddenBasenames,
+ array $forbiddenExtensions,
+ array $forbiddenCharacters,
+ string $expected,
+ ): void {
+ /** @var FilenameValidator&MockObject */
+ $validator = $this->getMockBuilder(FilenameValidator::class)
+ ->onlyMethods([
+ 'getForbiddenBasenames',
+ 'getForbiddenExtensions',
+ 'getForbiddenFilenames',
+ 'getForbiddenCharacters',
+ ])
+ ->setConstructorArgs([$this->l10n, $this->database, $this->config, $this->logger])
+ ->getMock();
+
+ $validator->method('getForbiddenBasenames')
+ ->willReturn($forbiddenBasenames);
+ $validator->method('getForbiddenCharacters')
+ ->willReturn($forbiddenCharacters);
+ $validator->method('getForbiddenExtensions')
+ ->willReturn($forbiddenExtensions);
+ $validator->method('getForbiddenFilenames')
+ ->willReturn($forbiddenNames);
+
+ $this->assertEquals($expected, $validator->sanitizeFilename($filename));
+ }
+
+ public static function dataSanitizeFilename(): array {
+ return [
+ 'valid name' => [
+ 'a * b.txt', ['.htaccess'], [], [], [], 'a * b.txt'
+ ],
+ 'forbidden name in the middle is ok' => [
+ 'a.htaccess.txt', ['.htaccess'], [], [], [], 'a.htaccess.txt'
+ ],
+ 'forbidden name on the beginning' => [
+ '.htaccess.sample', ['.htaccess'], [], [], [], '.htaccess.sample'
+ ],
+ 'forbidden name' => [
+ '.htaccess', ['.htaccess'], [], [], [], '.htaccess (renamed)'
+ ],
+ 'forbidden name - name is case insensitive' => [
+ 'COM1', ['.htaccess', 'com1'], [], [], [], 'COM1 (renamed)'
+ ],
+ 'forbidden basename' => [
+ 'com1.suffix', ['.htaccess'], ['com1'], [], [], 'com1 (renamed).suffix'
+ ],
+ 'forbidden basename case insensitive' => [
+ // needed for Windows namespaces
+ 'COM1.suffix', ['.htaccess'], ['com1'], [], [], 'COM1 (renamed).suffix'
+ ],
+ 'forbidden basename for hidden files' => [
+ // needed for Windows namespaces
+ '.thumbs.db', ['.htaccess'], ['.thumbs'], [], [], '.thumbs (renamed).db'
+ ],
+ 'invalid character' => [
+ 'a: b.txt', ['.htaccess'], [], [], [':'], 'a_ b.txt',
+ ],
+ 'invalid extension' => [
+ 'a: b.txt', ['.htaccess'], [], ['.txt'], [], 'a: b'
+ ],
+ 'invalid extension case insensitive' => [
+ 'a: b.TXT', ['.htaccess'], [], ['.txt'], [], 'a: b'
+ ],
+ 'empty filename' => [
+ '', [], [], [], [], 'renamed file'
+ ],
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataSanitizeFilenameCharacterReplacement')]
+ public function testSanitizeFilenameCharacterReplacement(
+ string $filename,
+ array $forbiddenCharacters,
+ ?string $characterReplacement,
+ ?string $expected,
+ ): void {
+ /** @var FilenameValidator&MockObject */
+ $validator = $this->getMockBuilder(FilenameValidator::class)
+ ->onlyMethods([
+ 'getForbiddenBasenames',
+ 'getForbiddenExtensions',
+ 'getForbiddenFilenames',
+ 'getForbiddenCharacters',
+ ])
+ ->setConstructorArgs([$this->l10n, $this->database, $this->config, $this->logger])
+ ->getMock();
+
+ $validator->method('getForbiddenBasenames')
+ ->willReturn([]);
+ $validator->method('getForbiddenCharacters')
+ ->willReturn($forbiddenCharacters);
+ $validator->method('getForbiddenExtensions')
+ ->willReturn([]);
+ $validator->method('getForbiddenFilenames')
+ ->willReturn([]);
+
+ if ($expected === null) {
+ $this->expectException(\InvalidArgumentException::class);
+ $validator->sanitizeFilename($filename, $characterReplacement);
+ } else {
+ $this->assertEquals($expected, $validator->sanitizeFilename($filename, $characterReplacement));
+ }
+ }
+
+ public static function dataSanitizeFilenameCharacterReplacement(): array {
+ return [
+ 'default' => [
+ 'foo*bar', ['*'], null, 'foo_bar'
+ ],
+ 'default - underscore not allowed' => [
+ 'foo*bar', ['*', '_'], null, 'foo-bar'
+ ],
+ 'default - dash and underscore not allowed' => [
+ 'foo*bar', ['*', '-', '_'], null, 'foo bar'
+ ],
+ 'default - no replacement' => [
+ 'foo*bar', ['*', ' ', '_', '-'], null, null
+ ],
+ 'custom replacement' => [
+ 'foo*bar', ['*'], 'x', 'fooxbar'
+ ],
+ ];
+ }
}