CommonTest.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace Test\Files\Storage;
  8. use OC\Files\Storage\Wrapper\Jail;
  9. use OC\Files\Storage\Wrapper\Wrapper;
  10. use OCP\Files\InvalidPathException;
  11. use PHPUnit\Framework\MockObject\MockObject;
  12. /**
  13. * Class CommonTest
  14. *
  15. * @group DB
  16. *
  17. * @package Test\Files\Storage
  18. */
  19. class CommonTest extends Storage {
  20. /**
  21. * @var string tmpDir
  22. */
  23. private $tmpDir;
  24. private array $invalidCharsBackup;
  25. protected function setUp(): void {
  26. parent::setUp();
  27. $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder();
  28. $this->instance = new \OC\Files\Storage\CommonTest(['datadir' => $this->tmpDir]);
  29. $this->invalidCharsBackup = \OC::$server->getConfig()->getSystemValue('forbidden_chars', []);
  30. }
  31. protected function tearDown(): void {
  32. \OC_Helper::rmdirr($this->tmpDir);
  33. \OC::$server->getConfig()->setSystemValue('forbidden_chars', $this->invalidCharsBackup);
  34. parent::tearDown();
  35. }
  36. /**
  37. * @dataProvider dataVerifyPath
  38. */
  39. public function testVerifyPath(string $filename, array $additionalChars, bool $throws) {
  40. /** @var \OC\Files\Storage\CommonTest|MockObject $instance */
  41. $instance = $this->getMockBuilder(\OC\Files\Storage\CommonTest::class)
  42. ->onlyMethods(['copyFromStorage', 'rmdir', 'unlink'])
  43. ->setConstructorArgs([['datadir' => $this->tmpDir]])
  44. ->getMock();
  45. $instance->method('copyFromStorage')
  46. ->willThrowException(new \Exception('copy'));
  47. \OC::$server->getConfig()->setSystemValue('forbidden_chars', $additionalChars);
  48. if ($throws) {
  49. $this->expectException(InvalidPathException::class);
  50. } else {
  51. $this->expectNotToPerformAssertions();
  52. }
  53. $instance->verifyPath('/', $filename);
  54. }
  55. public function dataVerifyPath(): array {
  56. return [
  57. // slash is always forbidden
  58. 'invalid slash' => ['a/b.txt', [], true],
  59. // backslash is also forbidden
  60. 'invalid backslash' => ['a\\b.txt', [], true],
  61. // by default colon is not forbidden
  62. 'valid name' => ['a: b.txt', [], false],
  63. // colon can be added to the list of forbidden character
  64. 'invalid custom character' => ['a: b.txt', [':'], true],
  65. // make sure to not split the list entries as they migh contain Unicode sequences
  66. // in this example the "face in clouds" emoji contains the clouds emoji so only having clouds is ok
  67. 'valid unicode sequence' => ['🌫️.txt', ['😶‍🌫️'], false],
  68. // This is the reverse: clouds are forbidden -> so is also the face in the clouds emoji
  69. 'valid unicode sequence' => ['😶‍🌫️.txt', ['🌫️'], true],
  70. ];
  71. }
  72. public function testMoveFromStorageWrapped() {
  73. /** @var \OC\Files\Storage\CommonTest|MockObject $instance */
  74. $instance = $this->getMockBuilder(\OC\Files\Storage\CommonTest::class)
  75. ->onlyMethods(['copyFromStorage', 'rmdir', 'unlink'])
  76. ->setConstructorArgs([['datadir' => $this->tmpDir]])
  77. ->getMock();
  78. $instance->method('copyFromStorage')
  79. ->willThrowException(new \Exception('copy'));
  80. $source = new Wrapper([
  81. 'storage' => $instance,
  82. ]);
  83. $instance->file_put_contents('foo.txt', 'bar');
  84. $instance->moveFromStorage($source, 'foo.txt', 'bar.txt');
  85. $this->assertTrue($instance->file_exists('bar.txt'));
  86. }
  87. public function testMoveFromStorageJailed() {
  88. /** @var \OC\Files\Storage\CommonTest|MockObject $instance */
  89. $instance = $this->getMockBuilder(\OC\Files\Storage\CommonTest::class)
  90. ->onlyMethods(['copyFromStorage', 'rmdir', 'unlink'])
  91. ->setConstructorArgs([['datadir' => $this->tmpDir]])
  92. ->getMock();
  93. $instance->method('copyFromStorage')
  94. ->willThrowException(new \Exception('copy'));
  95. $source = new Jail([
  96. 'storage' => $instance,
  97. 'root' => 'foo'
  98. ]);
  99. $source = new Wrapper([
  100. 'storage' => $source
  101. ]);
  102. $instance->mkdir('foo');
  103. $instance->file_put_contents('foo/foo.txt', 'bar');
  104. $instance->moveFromStorage($source, 'foo.txt', 'bar.txt');
  105. $this->assertTrue($instance->file_exists('bar.txt'));
  106. }
  107. public function testMoveFromStorageNestedJail() {
  108. /** @var \OC\Files\Storage\CommonTest|MockObject $instance */
  109. $instance = $this->getMockBuilder(\OC\Files\Storage\CommonTest::class)
  110. ->onlyMethods(['copyFromStorage', 'rmdir', 'unlink'])
  111. ->setConstructorArgs([['datadir' => $this->tmpDir]])
  112. ->getMock();
  113. $instance->method('copyFromStorage')
  114. ->willThrowException(new \Exception('copy'));
  115. $source = new Jail([
  116. 'storage' => $instance,
  117. 'root' => 'foo'
  118. ]);
  119. $source = new Wrapper([
  120. 'storage' => $source
  121. ]);
  122. $source = new Jail([
  123. 'storage' => $source,
  124. 'root' => 'bar'
  125. ]);
  126. $source = new Wrapper([
  127. 'storage' => $source
  128. ]);
  129. $instance->mkdir('foo');
  130. $instance->mkdir('foo/bar');
  131. $instance->file_put_contents('foo/bar/foo.txt', 'bar');
  132. $instance->moveFromStorage($source, 'foo.txt', 'bar.txt');
  133. $this->assertTrue($instance->file_exists('bar.txt'));
  134. }
  135. }