RepairInvalidSharesTest.php 5.5 KB

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