diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/lib/Files/FilenameValidatorTest.php | 88 | ||||
-rw-r--r-- | tests/lib/Files/PathVerificationTest.php | 51 | ||||
-rw-r--r-- | tests/lib/Files/Storage/CommonTest.php | 67 |
3 files changed, 107 insertions, 99 deletions
diff --git a/tests/lib/Files/FilenameValidatorTest.php b/tests/lib/Files/FilenameValidatorTest.php index 42705a23f02..223e86ccd0a 100644 --- a/tests/lib/Files/FilenameValidatorTest.php +++ b/tests/lib/Files/FilenameValidatorTest.php @@ -13,9 +13,11 @@ use OC\Files\FilenameValidator; use OCP\Files\EmptyFileNameException; use OCP\Files\FileNameTooLongException; use OCP\Files\InvalidCharacterInPathException; +use OCP\Files\InvalidDirectoryException; use OCP\Files\InvalidPathException; use OCP\Files\ReservedWordException; use OCP\IConfig; +use OCP\IDBConnection; use OCP\IL10N; use OCP\L10N\IFactory; use PHPUnit\Framework\MockObject\MockObject; @@ -26,6 +28,7 @@ class FilenameValidatorTest extends TestCase { protected IFactory&MockObject $l10n; protected IConfig&MockObject $config; + protected IDBConnection&MockObject $database; protected LoggerInterface&MockObject $logger; protected function setUp(): void { @@ -41,6 +44,8 @@ class FilenameValidatorTest extends TestCase { $this->config = $this->createMock(IConfig::class); $this->logger = $this->createMock(LoggerInterface::class); + $this->database = $this->createMock(IDBConnection::class); + $this->database->method('supports4ByteText')->willReturn(true); } /** @@ -62,7 +67,7 @@ class FilenameValidatorTest extends TestCase { 'getForbiddenExtensions', 'getForbiddenFilenames', ]) - ->setConstructorArgs([$this->l10n, $this->config, $this->logger]) + ->setConstructorArgs([$this->l10n, $this->database, $this->config, $this->logger]) ->getMock(); $validator->method('getForbiddenBasenames') @@ -101,7 +106,7 @@ class FilenameValidatorTest extends TestCase { 'getForbiddenFilenames', 'getForbiddenCharacters', ]) - ->setConstructorArgs([$this->l10n, $this->config, $this->logger]) + ->setConstructorArgs([$this->l10n, $this->database, $this->config, $this->logger]) ->getMock(); $validator->method('getForbiddenBasenames') @@ -122,6 +127,9 @@ class FilenameValidatorTest extends TestCase { 'valid name' => [ 'a: b.txt', ['.htaccess'], [], [], [], null ], + 'forbidden name in the middle is ok' => [ + 'a.htaccess.txt', ['.htaccess'], [], [], null + ], 'valid name with some more parameters' => [ 'a: b.txt', ['.htaccess'], [], ['exe'], ['~'], null ], @@ -155,10 +163,13 @@ class FilenameValidatorTest extends TestCase { '', [], [], [], [], EmptyFileNameException::class ], 'reserved unix name "."' => [ - '.', [], [], [], [], InvalidPathException::class + '.', [], [], [], [], InvalidDirectoryException::class ], 'reserved unix name ".."' => [ - '..', [], [], [], [], ReservedWordException::class + '..', [], [], [], [], InvalidDirectoryException::class + ], + 'weird but valid tripple dot name' => [ + '...', [], [], [], null // is valid ], 'too long filename "."' => [ str_repeat('a', 251), [], [], [], [], FileNameTooLongException::class @@ -172,13 +183,80 @@ class FilenameValidatorTest extends TestCase { } /** + * @dataProvider data4ByteUnicode + */ + public function testDatabaseDoesNotSupport4ByteText($filename): void { + $database = $this->createMock(IDBConnection::class); + $database->expects($this->once()) + ->method('supports4ByteText') + ->willReturn(false); + $this->expectException(InvalidCharacterInPathException::class); + $validator = new FilenameValidator($this->l10n, $database, $this->config, $this->logger); + $validator->validateFilename($filename); + } + + public function data4ByteUnicode(): array { + return [ + ['plane 1 πͺ
'], + ['emoji πΆβπ«οΈ'], + + ]; + } + + /** + * @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 { + return [ + [\chr(0)], + [\chr(1)], + [\chr(2)], + [\chr(3)], + [\chr(4)], + [\chr(5)], + [\chr(6)], + [\chr(7)], + [\chr(8)], + [\chr(9)], + [\chr(10)], + [\chr(11)], + [\chr(12)], + [\chr(13)], + [\chr(14)], + [\chr(15)], + [\chr(16)], + [\chr(17)], + [\chr(18)], + [\chr(19)], + [\chr(20)], + [\chr(21)], + [\chr(22)], + [\chr(23)], + [\chr(24)], + [\chr(25)], + [\chr(26)], + [\chr(27)], + [\chr(28)], + [\chr(29)], + [\chr(30)], + [\chr(31)], + ]; + } + + /** * @dataProvider dataIsForbidden */ public function testIsForbidden(string $filename, array $forbiddenNames, array $forbiddenBasenames, bool $expected): void { /** @var FilenameValidator&MockObject */ $validator = $this->getMockBuilder(FilenameValidator::class) ->onlyMethods(['getForbiddenFilenames', 'getForbiddenBasenames']) - ->setConstructorArgs([$this->l10n, $this->config, $this->logger]) + ->setConstructorArgs([$this->l10n, $this->database, $this->config, $this->logger]) ->getMock(); $validator->method('getForbiddenBasenames') diff --git a/tests/lib/Files/PathVerificationTest.php b/tests/lib/Files/PathVerificationTest.php index 4addd583354..0fd0c330ea5 100644 --- a/tests/lib/Files/PathVerificationTest.php +++ b/tests/lib/Files/PathVerificationTest.php @@ -107,57 +107,6 @@ class PathVerificationTest extends \Test\TestCase { } /** - * @dataProvider providesInvalidCharsPosix - */ - public function testPathVerificationInvalidCharsPosix($fileName) { - $this->expectException(\OCP\Files\InvalidCharacterInPathException::class); - - $storage = new Local(['datadir' => '']); - - $fileName = " 123{$fileName}456 "; - self::invokePrivate($storage, 'verifyPosixPath', [$fileName]); - } - - public function providesInvalidCharsPosix() { - return [ - [\chr(0)], - [\chr(1)], - [\chr(2)], - [\chr(3)], - [\chr(4)], - [\chr(5)], - [\chr(6)], - [\chr(7)], - [\chr(8)], - [\chr(9)], - [\chr(10)], - [\chr(11)], - [\chr(12)], - [\chr(13)], - [\chr(14)], - [\chr(15)], - [\chr(16)], - [\chr(17)], - [\chr(18)], - [\chr(19)], - [\chr(20)], - [\chr(21)], - [\chr(22)], - [\chr(23)], - [\chr(24)], - [\chr(25)], - [\chr(26)], - [\chr(27)], - [\chr(28)], - [\chr(29)], - [\chr(30)], - [\chr(31)], - ['/'], - ['\\'], - ]; - } - - /** * @dataProvider providesValidPosixPaths */ public function testPathVerificationValidPaths($fileName) { diff --git a/tests/lib/Files/Storage/CommonTest.php b/tests/lib/Files/Storage/CommonTest.php index bd22d93fb69..321894cc23b 100644 --- a/tests/lib/Files/Storage/CommonTest.php +++ b/tests/lib/Files/Storage/CommonTest.php @@ -9,7 +9,10 @@ namespace Test\Files\Storage; use OC\Files\Storage\Wrapper\Jail; use OC\Files\Storage\Wrapper\Wrapper; +use OCP\Files\IFilenameValidator; +use OCP\Files\InvalidCharacterInPathException; use OCP\Files\InvalidPathException; +use OCP\ITempManager; use PHPUnit\Framework\MockObject\MockObject; /** @@ -20,65 +23,43 @@ use PHPUnit\Framework\MockObject\MockObject; * @package Test\Files\Storage */ class CommonTest extends Storage { - /** - * @var string tmpDir - */ - private $tmpDir; - private array $invalidCharsBackup; + private string $tmpDir; + private IFilenameValidator&MockObject $filenameValidator; protected function setUp(): void { parent::setUp(); - $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder(); + $this->filenameValidator = $this->createMock(IFilenameValidator::class); + $this->overwriteService(IFilenameValidator::class, $this->filenameValidator); + $this->tmpDir = \OCP\Server::get(ITempManager::class)->getTemporaryFolder(); $this->instance = new \OC\Files\Storage\CommonTest(['datadir' => $this->tmpDir]); - $this->invalidCharsBackup = \OC::$server->getConfig()->getSystemValue('forbidden_chars', []); } protected function tearDown(): void { \OC_Helper::rmdirr($this->tmpDir); - \OC::$server->getConfig()->setSystemValue('forbidden_chars', $this->invalidCharsBackup); + $this->restoreService(IFilenameValidator::class); parent::tearDown(); } - /** - * @dataProvider dataVerifyPath - */ - public function testVerifyPath(string $filename, array $additionalChars, bool $throws) { - /** @var \OC\Files\Storage\CommonTest|MockObject $instance */ - $instance = $this->getMockBuilder(\OC\Files\Storage\CommonTest::class) - ->onlyMethods(['copyFromStorage', 'rmdir', 'unlink']) - ->setConstructorArgs([['datadir' => $this->tmpDir]]) - ->getMock(); - $instance->method('copyFromStorage') - ->willThrowException(new \Exception('copy')); + public function testVerifyPath() { + $this->filenameValidator + ->expects($this->once()) + ->method('validateFilename') + ->with('invalid:char.txt') + ->willThrowException(new InvalidCharacterInPathException()); + $this->expectException(InvalidPathException::class); - \OC::$server->getConfig()->setSystemValue('forbidden_chars', $additionalChars); - - if ($throws) { - $this->expectException(InvalidPathException::class); - } else { - $this->expectNotToPerformAssertions(); - } - $instance->verifyPath('/', $filename); + $this->instance->verifyPath('/', 'invalid:char.txt'); } - public function dataVerifyPath(): array { - return [ - // slash is always forbidden - 'invalid slash' => ['a/b.txt', [], true], - // backslash is also forbidden - 'invalid backslash' => ['a\\b.txt', [], true], - // by default colon is not forbidden - 'valid name' => ['a: b.txt', [], false], - // colon can be added to the list of forbidden character - 'invalid custom character' => ['a: b.txt', [':'], true], - // make sure to not split the list entries as they migh contain Unicode sequences - // in this example the "face in clouds" emoji contains the clouds emoji so only having clouds is ok - 'valid unicode sequence' => ['π«οΈ.txt', ['πΆβπ«οΈ'], false], - // This is the reverse: clouds are forbidden -> so is also the face in the clouds emoji - 'valid unicode sequence' => ['πΆβπ«οΈ.txt', ['π«οΈ'], true], - ]; + public function testVerifyPathSucceed() { + $this->filenameValidator + ->expects($this->once()) + ->method('validateFilename') + ->with('valid-char.txt'); + + $this->instance->verifyPath('/', 'valid-char.txt'); } public function testMoveFromStorageWrapped() { |