1
0

RepairInvalidSharesTest.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-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\Repair;
  8. use OC\Repair\RepairInvalidShares;
  9. use OCP\IConfig;
  10. use OCP\Migration\IOutput;
  11. use OCP\Migration\IRepairStep;
  12. use OCP\Share\IShare;
  13. use Test\TestCase;
  14. /**
  15. * Tests for repairing invalid shares
  16. *
  17. * @group DB
  18. *
  19. * @see \OC\Repair\RepairInvalidShares
  20. */
  21. class RepairInvalidSharesTest extends TestCase {
  22. /** @var IRepairStep */
  23. private $repair;
  24. /** @var \OCP\IDBConnection */
  25. private $connection;
  26. protected function setUp(): void {
  27. parent::setUp();
  28. $config = $this->getMockBuilder(IConfig::class)
  29. ->disableOriginalConstructor()
  30. ->getMock();
  31. $config->expects($this->any())
  32. ->method('getSystemValueString')
  33. ->with('version')
  34. ->willReturn('12.0.0.0');
  35. $this->connection = \OC::$server->getDatabaseConnection();
  36. $this->deleteAllShares();
  37. /** @var \OCP\IConfig $config */
  38. $this->repair = new RepairInvalidShares($config, $this->connection);
  39. }
  40. protected function tearDown(): void {
  41. $this->deleteAllShares();
  42. parent::tearDown();
  43. }
  44. protected function deleteAllShares() {
  45. $qb = $this->connection->getQueryBuilder();
  46. $qb->delete('share')->execute();
  47. }
  48. /**
  49. * Test remove shares where the parent share does not exist anymore
  50. */
  51. public function testSharesNonExistingParent(): void {
  52. $qb = $this->connection->getQueryBuilder();
  53. $shareValues = [
  54. 'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
  55. 'share_with' => $qb->expr()->literal('recipientuser1'),
  56. 'uid_owner' => $qb->expr()->literal('user1'),
  57. 'item_type' => $qb->expr()->literal('folder'),
  58. 'item_source' => $qb->expr()->literal(123),
  59. 'item_target' => $qb->expr()->literal('/123'),
  60. 'file_source' => $qb->expr()->literal(123),
  61. 'file_target' => $qb->expr()->literal('/test'),
  62. 'permissions' => $qb->expr()->literal(1),
  63. 'stime' => $qb->expr()->literal(time()),
  64. 'expiration' => $qb->expr()->literal('2015-09-25 00:00:00')
  65. ];
  66. // valid share
  67. $qb = $this->connection->getQueryBuilder();
  68. $qb->insert('share')
  69. ->values($shareValues)
  70. ->execute();
  71. $parent = $this->getLastShareId();
  72. // share with existing parent
  73. $qb = $this->connection->getQueryBuilder();
  74. $qb->insert('share')
  75. ->values(array_merge($shareValues, [
  76. 'parent' => $qb->expr()->literal($parent),
  77. ]))->execute();
  78. $validChild = $this->getLastShareId();
  79. // share with non-existing parent
  80. $qb = $this->connection->getQueryBuilder();
  81. $qb->insert('share')
  82. ->values(array_merge($shareValues, [
  83. 'parent' => $qb->expr()->literal($parent + 100),
  84. ]))->execute();
  85. $invalidChild = $this->getLastShareId();
  86. $query = $this->connection->getQueryBuilder();
  87. $result = $query->select('id')
  88. ->from('share')
  89. ->orderBy('id', 'ASC')
  90. ->execute();
  91. $rows = $result->fetchAll();
  92. $this->assertEquals([['id' => $parent], ['id' => $validChild], ['id' => $invalidChild]], $rows);
  93. $result->closeCursor();
  94. /** @var IOutput | \PHPUnit\Framework\MockObject\MockObject $outputMock */
  95. $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput')
  96. ->disableOriginalConstructor()
  97. ->getMock();
  98. $this->repair->run($outputMock);
  99. $query = $this->connection->getQueryBuilder();
  100. $result = $query->select('id')
  101. ->from('share')
  102. ->orderBy('id', 'ASC')
  103. ->execute();
  104. $rows = $result->fetchAll();
  105. $this->assertEquals([['id' => $parent], ['id' => $validChild]], $rows);
  106. $result->closeCursor();
  107. }
  108. public function fileSharePermissionsProvider() {
  109. return [
  110. // unchanged for folder
  111. [
  112. 'folder',
  113. 31,
  114. 31,
  115. ],
  116. // unchanged for read-write + share
  117. [
  118. 'file',
  119. \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_SHARE,
  120. \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_SHARE,
  121. ],
  122. // fixed for all perms
  123. [
  124. 'file',
  125. \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_SHARE,
  126. \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_SHARE,
  127. ],
  128. ];
  129. }
  130. /**
  131. * Test adjusting file share permissions
  132. *
  133. * @dataProvider fileSharePermissionsProvider
  134. */
  135. public function testFileSharePermissions($itemType, $testPerms, $expectedPerms): void {
  136. $qb = $this->connection->getQueryBuilder();
  137. $qb->insert('share')
  138. ->values([
  139. 'share_type' => $qb->expr()->literal(IShare::TYPE_LINK),
  140. 'uid_owner' => $qb->expr()->literal('user1'),
  141. 'item_type' => $qb->expr()->literal($itemType),
  142. 'item_source' => $qb->expr()->literal(123),
  143. 'item_target' => $qb->expr()->literal('/123'),
  144. 'file_source' => $qb->expr()->literal(123),
  145. 'file_target' => $qb->expr()->literal('/test'),
  146. 'permissions' => $qb->expr()->literal($testPerms),
  147. 'stime' => $qb->expr()->literal(time()),
  148. ])
  149. ->execute();
  150. $shareId = $this->getLastShareId();
  151. /** @var IOutput | \PHPUnit\Framework\MockObject\MockObject $outputMock */
  152. $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput')
  153. ->disableOriginalConstructor()
  154. ->getMock();
  155. $this->repair->run($outputMock);
  156. $results = $this->connection->getQueryBuilder()
  157. ->select('*')
  158. ->from('share')
  159. ->orderBy('permissions', 'ASC')
  160. ->execute()
  161. ->fetchAll();
  162. $this->assertCount(1, $results);
  163. $updatedShare = $results[0];
  164. $this->assertEquals($expectedPerms, $updatedShare['permissions']);
  165. }
  166. /**
  167. * @return int
  168. */
  169. protected function getLastShareId() {
  170. return $this->connection->lastInsertId('*PREFIX*share');
  171. }
  172. }