UpdaterTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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-only
  6. */
  7. namespace OCA\Files_Sharing\Tests;
  8. use OC\Files\FileInfo;
  9. use OC\Files\Filesystem;
  10. use OC\Files\View;
  11. use OCA\Files_Sharing\Helper;
  12. use OCA\Files_Trashbin\AppInfo\Application;
  13. use OCP\AppFramework\Bootstrap\IBootContext;
  14. use OCP\Constants;
  15. use OCP\Share\IShare;
  16. /**
  17. * Class UpdaterTest
  18. *
  19. * @group DB
  20. */
  21. class UpdaterTest extends TestCase {
  22. public const TEST_FOLDER_NAME = '/folder_share_updater_test';
  23. public static function setUpBeforeClass(): void {
  24. parent::setUpBeforeClass();
  25. Helper::registerHooks();
  26. }
  27. protected function setUp(): void {
  28. parent::setUp();
  29. $this->folder = self::TEST_FOLDER_NAME;
  30. $this->filename = '/share-updater-test.txt';
  31. // save file with content
  32. $this->view->file_put_contents($this->filename, $this->data);
  33. $this->view->mkdir($this->folder);
  34. $this->view->file_put_contents($this->folder . '/' . $this->filename, $this->data);
  35. }
  36. protected function tearDown(): void {
  37. if ($this->view) {
  38. $this->view->unlink($this->filename);
  39. $this->view->deleteAll($this->folder);
  40. }
  41. parent::tearDown();
  42. }
  43. /**
  44. * test deletion of a folder which contains share mount points. Share mount
  45. * points should be unshared before the folder gets deleted so
  46. * that the mount point doesn't end up at the trash bin
  47. */
  48. public function testDeleteParentFolder(): void {
  49. $status = \OC::$server->getAppManager()->isEnabledForUser('files_trashbin');
  50. (new \OC_App())->enable('files_trashbin');
  51. // register trashbin hooks
  52. $trashbinApp = new Application();
  53. $trashbinApp->boot($this->createMock(IBootContext::class));
  54. $fileinfo = Filesystem::getFileInfo($this->folder);
  55. $this->assertTrue($fileinfo instanceof FileInfo);
  56. $this->share(
  57. IShare::TYPE_USER,
  58. $this->folder,
  59. self::TEST_FILES_SHARING_API_USER1,
  60. self::TEST_FILES_SHARING_API_USER2,
  61. Constants::PERMISSION_ALL
  62. );
  63. $this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
  64. $view = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
  65. // check if user2 can see the shared folder
  66. $this->assertTrue($view->file_exists($this->folder));
  67. $foldersShared = $this->shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER1, IShare::TYPE_USER);
  68. $this->assertCount(1, $foldersShared);
  69. $view->mkdir('localFolder');
  70. $view->file_put_contents('localFolder/localFile.txt', 'local file');
  71. $view->rename($this->folder, 'localFolder/' . $this->folder);
  72. // share mount point should now be moved to the subfolder
  73. $this->assertFalse($view->file_exists($this->folder));
  74. $this->assertTrue($view->file_exists('localFolder/' . $this->folder));
  75. $view->unlink('localFolder');
  76. $this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
  77. // shared folder should be unshared
  78. $foldersShared = $this->shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER1, IShare::TYPE_USER);
  79. $this->assertCount(0, $foldersShared);
  80. // trashbin should contain the local file but not the mount point
  81. $rootView = new View('/' . self::TEST_FILES_SHARING_API_USER2);
  82. $trashContent = \OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_FILES_SHARING_API_USER2);
  83. $this->assertSame(1, count($trashContent));
  84. $firstElement = reset($trashContent);
  85. $timestamp = $firstElement['mtime'];
  86. $this->assertTrue($rootView->file_exists('files_trashbin/files/localFolder.d' . $timestamp . '/localFile.txt'));
  87. $this->assertFalse($rootView->file_exists('files_trashbin/files/localFolder.d' . $timestamp . '/' . $this->folder));
  88. //cleanup
  89. $rootView->deleteAll('files_trashin');
  90. if ($status === false) {
  91. \OC::$server->getAppManager()->disableApp('files_trashbin');
  92. }
  93. Filesystem::getLoader()->removeStorageWrapper('oc_trashbin');
  94. }
  95. public function shareFolderProvider() {
  96. return [
  97. ['/'],
  98. ['/my_shares'],
  99. ];
  100. }
  101. /**
  102. * if a file gets shared the etag for the recipients root should change
  103. *
  104. * @dataProvider shareFolderProvider
  105. *
  106. * @param string $shareFolder share folder to use
  107. */
  108. public function testShareFile($shareFolder): void {
  109. $config = \OC::$server->getConfig();
  110. $oldShareFolder = $config->getSystemValue('share_folder');
  111. $config->setSystemValue('share_folder', $shareFolder);
  112. $this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
  113. $beforeShareRoot = Filesystem::getFileInfo('');
  114. $etagBeforeShareRoot = $beforeShareRoot->getEtag();
  115. Filesystem::mkdir($shareFolder);
  116. $beforeShareDir = Filesystem::getFileInfo($shareFolder);
  117. $etagBeforeShareDir = $beforeShareDir->getEtag();
  118. $this->loginHelper(self::TEST_FILES_SHARING_API_USER1);
  119. $share = $this->share(
  120. IShare::TYPE_USER,
  121. $this->folder,
  122. self::TEST_FILES_SHARING_API_USER1,
  123. self::TEST_FILES_SHARING_API_USER2,
  124. Constants::PERMISSION_ALL
  125. );
  126. $this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
  127. $afterShareRoot = Filesystem::getFileInfo('');
  128. $etagAfterShareRoot = $afterShareRoot->getEtag();
  129. $afterShareDir = Filesystem::getFileInfo($shareFolder);
  130. $etagAfterShareDir = $afterShareDir->getEtag();
  131. $this->assertTrue(is_string($etagBeforeShareRoot));
  132. $this->assertTrue(is_string($etagBeforeShareDir));
  133. $this->assertTrue(is_string($etagAfterShareRoot));
  134. $this->assertTrue(is_string($etagAfterShareDir));
  135. $this->assertTrue($etagBeforeShareRoot !== $etagAfterShareRoot);
  136. $this->assertTrue($etagBeforeShareDir !== $etagAfterShareDir);
  137. // cleanup
  138. $this->loginHelper(self::TEST_FILES_SHARING_API_USER1);
  139. $this->shareManager->deleteShare($share);
  140. $config->setSystemValue('share_folder', $oldShareFolder);
  141. }
  142. /**
  143. * if a folder gets renamed all children mount points should be renamed too
  144. */
  145. public function testRename(): void {
  146. $fileinfo = Filesystem::getFileInfo($this->folder);
  147. $share = $this->share(
  148. IShare::TYPE_USER,
  149. $this->folder,
  150. self::TEST_FILES_SHARING_API_USER1,
  151. self::TEST_FILES_SHARING_API_USER2,
  152. Constants::PERMISSION_ALL
  153. );
  154. $this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
  155. // make sure that the shared folder exists
  156. $this->assertTrue(Filesystem::file_exists($this->folder));
  157. Filesystem::mkdir('oldTarget');
  158. Filesystem::mkdir('oldTarget/subfolder');
  159. Filesystem::mkdir('newTarget');
  160. Filesystem::rename($this->folder, 'oldTarget/subfolder/' . $this->folder);
  161. // re-login to make sure that the new mount points are initialized
  162. $this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
  163. Filesystem::rename('/oldTarget', '/newTarget/oldTarget');
  164. // re-login to make sure that the new mount points are initialized
  165. $this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
  166. $this->assertTrue(Filesystem::file_exists('/newTarget/oldTarget/subfolder/' . $this->folder));
  167. // cleanup
  168. $this->shareManager->deleteShare($share);
  169. }
  170. /**
  171. * If a folder gets moved into shared folder, children shares should have their uid_owner and permissions adjusted
  172. * user1
  173. * |-folder1 --> shared with user2
  174. * user2
  175. * |-folder2 --> shared with user3 and moved into folder1
  176. * |-subfolder1 --> shared with user3
  177. * |-file1.txt --> shared with user3
  178. * |-subfolder2
  179. * |-file2.txt --> shared with user3
  180. */
  181. public function testMovedIntoShareChangeOwner(): void {
  182. $this->markTestSkipped('Skipped because this is failing with S3 as primary as file id are change when moved.');
  183. // user1 creates folder1
  184. $viewUser1 = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files');
  185. $folder1 = 'folder1';
  186. $viewUser1->mkdir($folder1);
  187. // user1 shares folder1 to user2
  188. $folder1Share = $this->share(
  189. IShare::TYPE_USER,
  190. $folder1,
  191. self::TEST_FILES_SHARING_API_USER1,
  192. self::TEST_FILES_SHARING_API_USER2,
  193. Constants::PERMISSION_READ | Constants::PERMISSION_SHARE
  194. );
  195. $this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
  196. $viewUser2 = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
  197. // Create user2 files
  198. $folder2 = 'folder2';
  199. $viewUser2->mkdir($folder2);
  200. $file1 = 'folder2/file1.txt';
  201. $viewUser2->touch($file1);
  202. $subfolder1 = 'folder2/subfolder1';
  203. $viewUser2->mkdir($subfolder1);
  204. $subfolder2 = 'folder2/subfolder2';
  205. $viewUser2->mkdir($subfolder2);
  206. $file2 = 'folder2/subfolder2/file2.txt';
  207. $viewUser2->touch($file2);
  208. // user2 shares folder2 to user3
  209. $folder2Share = $this->share(
  210. IShare::TYPE_USER,
  211. $folder2,
  212. self::TEST_FILES_SHARING_API_USER2,
  213. self::TEST_FILES_SHARING_API_USER3,
  214. Constants::PERMISSION_ALL
  215. );
  216. // user2 shares folder2/file1 to user3
  217. $file1Share = $this->share(
  218. IShare::TYPE_USER,
  219. $file1,
  220. self::TEST_FILES_SHARING_API_USER2,
  221. self::TEST_FILES_SHARING_API_USER3,
  222. Constants::PERMISSION_READ | Constants::PERMISSION_SHARE
  223. );
  224. // user2 shares subfolder1 to user3
  225. $subfolder1Share = $this->share(
  226. IShare::TYPE_USER,
  227. $subfolder1,
  228. self::TEST_FILES_SHARING_API_USER2,
  229. self::TEST_FILES_SHARING_API_USER3,
  230. Constants::PERMISSION_ALL
  231. );
  232. // user2 shares subfolder2/file2.txt to user3
  233. $file2Share = $this->share(
  234. IShare::TYPE_USER,
  235. $file2,
  236. self::TEST_FILES_SHARING_API_USER2,
  237. self::TEST_FILES_SHARING_API_USER3,
  238. Constants::PERMISSION_READ | Constants::PERMISSION_SHARE
  239. );
  240. // user2 moves folder2 into folder1
  241. $viewUser2->rename($folder2, $folder1 . '/' . $folder2);
  242. $folder2Share = $this->shareManager->getShareById($folder2Share->getFullId());
  243. $file1Share = $this->shareManager->getShareById($file1Share->getFullId());
  244. $subfolder1Share = $this->shareManager->getShareById($subfolder1Share->getFullId());
  245. $file2Share = $this->shareManager->getShareById($file2Share->getFullId());
  246. // Expect uid_owner of both shares to be user1
  247. $this->assertEquals(self::TEST_FILES_SHARING_API_USER1, $folder2Share->getShareOwner());
  248. $this->assertEquals(self::TEST_FILES_SHARING_API_USER1, $file1Share->getShareOwner());
  249. $this->assertEquals(self::TEST_FILES_SHARING_API_USER1, $subfolder1Share->getShareOwner());
  250. $this->assertEquals(self::TEST_FILES_SHARING_API_USER1, $file2Share->getShareOwner());
  251. // Expect permissions to be limited by the permissions of the destination share
  252. $this->assertEquals(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, $folder2Share->getPermissions());
  253. $this->assertEquals(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, $file1Share->getPermissions());
  254. $this->assertEquals(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, $subfolder1Share->getPermissions());
  255. $this->assertEquals(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, $file2Share->getPermissions());
  256. // user2 moves folder2 out of folder1
  257. $viewUser2->rename($folder1 . '/' . $folder2, $folder2);
  258. $folder2Share = $this->shareManager->getShareById($folder2Share->getFullId());
  259. $file1Share = $this->shareManager->getShareById($file1Share->getFullId());
  260. $subfolder1Share = $this->shareManager->getShareById($subfolder1Share->getFullId());
  261. $file2Share = $this->shareManager->getShareById($file2Share->getFullId());
  262. // Expect uid_owner of both shares to be user2
  263. $this->assertEquals(self::TEST_FILES_SHARING_API_USER2, $folder2Share->getShareOwner());
  264. $this->assertEquals(self::TEST_FILES_SHARING_API_USER2, $file1Share->getShareOwner());
  265. $this->assertEquals(self::TEST_FILES_SHARING_API_USER2, $subfolder1Share->getShareOwner());
  266. $this->assertEquals(self::TEST_FILES_SHARING_API_USER2, $file2Share->getShareOwner());
  267. // Expect permissions to not change
  268. $this->assertEquals(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, $folder2Share->getPermissions());
  269. $this->assertEquals(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, $file1Share->getPermissions());
  270. $this->assertEquals(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, $subfolder1Share->getPermissions());
  271. $this->assertEquals(Constants::PERMISSION_READ | Constants::PERMISSION_SHARE, $file2Share->getPermissions());
  272. // cleanup
  273. $this->shareManager->deleteShare($folder1Share);
  274. $this->shareManager->deleteShare($folder2Share);
  275. $this->shareManager->deleteShare($file1Share);
  276. $this->shareManager->deleteShare($subfolder1Share);
  277. $this->shareManager->deleteShare($file2Share);
  278. }
  279. }