UpdaterTest.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Björn Schießle <bjoern@schiessle.org>
  6. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  7. * @author Joas Schilling <coding@schilljs.com>
  8. * @author Lukas Reschke <lukas@statuscode.ch>
  9. * @author Morris Jobke <hey@morrisjobke.de>
  10. * @author Robin Appelman <robin@icewind.nl>
  11. * @author Roeland Jago Douma <roeland@famdouma.nl>
  12. * @author Thomas Müller <thomas.mueller@tmit.eu>
  13. * @author Tobia De Koninck <tobia@ledfan.be>
  14. * @author Vincent Petry <vincent@nextcloud.com>
  15. *
  16. * @license AGPL-3.0
  17. *
  18. * This code is free software: you can redistribute it and/or modify
  19. * it under the terms of the GNU Affero General Public License, version 3,
  20. * as published by the Free Software Foundation.
  21. *
  22. * This program is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU Affero General Public License for more details.
  26. *
  27. * You should have received a copy of the GNU Affero General Public License, version 3,
  28. * along with this program. If not, see <http://www.gnu.org/licenses/>
  29. *
  30. */
  31. namespace OCA\Files_Sharing\Tests;
  32. use OCA\Files_Trashbin\AppInfo\Application;
  33. use OCP\AppFramework\Bootstrap\IBootContext;
  34. use OCP\Share\IShare;
  35. /**
  36. * Class UpdaterTest
  37. *
  38. * @group DB
  39. */
  40. class UpdaterTest extends TestCase {
  41. public const TEST_FOLDER_NAME = '/folder_share_updater_test';
  42. public static function setUpBeforeClass(): void {
  43. parent::setUpBeforeClass();
  44. \OCA\Files_Sharing\Helper::registerHooks();
  45. }
  46. protected function setUp(): void {
  47. parent::setUp();
  48. $this->folder = self::TEST_FOLDER_NAME;
  49. $this->filename = '/share-updater-test.txt';
  50. // save file with content
  51. $this->view->file_put_contents($this->filename, $this->data);
  52. $this->view->mkdir($this->folder);
  53. $this->view->file_put_contents($this->folder . '/' . $this->filename, $this->data);
  54. }
  55. protected function tearDown(): void {
  56. if ($this->view) {
  57. $this->view->unlink($this->filename);
  58. $this->view->deleteAll($this->folder);
  59. }
  60. parent::tearDown();
  61. }
  62. /**
  63. * test deletion of a folder which contains share mount points. Share mount
  64. * points should be unshared before the folder gets deleted so
  65. * that the mount point doesn't end up at the trash bin
  66. */
  67. public function testDeleteParentFolder() {
  68. $status = \OC::$server->getAppManager()->isEnabledForUser('files_trashbin');
  69. (new \OC_App())->enable('files_trashbin');
  70. // register trashbin hooks
  71. $trashbinApp = new Application();
  72. $trashbinApp->boot($this->createMock(IBootContext::class));
  73. $fileinfo = \OC\Files\Filesystem::getFileInfo($this->folder);
  74. $this->assertTrue($fileinfo instanceof \OC\Files\FileInfo);
  75. $this->share(
  76. IShare::TYPE_USER,
  77. $this->folder,
  78. self::TEST_FILES_SHARING_API_USER1,
  79. self::TEST_FILES_SHARING_API_USER2,
  80. \OCP\Constants::PERMISSION_ALL
  81. );
  82. $this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
  83. $view = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
  84. // check if user2 can see the shared folder
  85. $this->assertTrue($view->file_exists($this->folder));
  86. $foldersShared = $this->shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER1, IShare::TYPE_USER);
  87. $this->assertCount(1, $foldersShared);
  88. $view->mkdir('localFolder');
  89. $view->file_put_contents('localFolder/localFile.txt', 'local file');
  90. $view->rename($this->folder, 'localFolder/' . $this->folder);
  91. // share mount point should now be moved to the subfolder
  92. $this->assertFalse($view->file_exists($this->folder));
  93. $this->assertTrue($view->file_exists('localFolder/' .$this->folder));
  94. $view->unlink('localFolder');
  95. $this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
  96. // shared folder should be unshared
  97. $foldersShared = $this->shareManager->getSharesBy(self::TEST_FILES_SHARING_API_USER1, IShare::TYPE_USER);
  98. $this->assertCount(0, $foldersShared);
  99. // trashbin should contain the local file but not the mount point
  100. $rootView = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2);
  101. $trashContent = \OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_FILES_SHARING_API_USER2);
  102. $this->assertSame(1, count($trashContent));
  103. $firstElement = reset($trashContent);
  104. $timestamp = $firstElement['mtime'];
  105. $this->assertTrue($rootView->file_exists('files_trashbin/files/localFolder.d' . $timestamp . '/localFile.txt'));
  106. $this->assertFalse($rootView->file_exists('files_trashbin/files/localFolder.d' . $timestamp . '/' . $this->folder));
  107. //cleanup
  108. $rootView->deleteAll('files_trashin');
  109. if ($status === false) {
  110. \OC::$server->getAppManager()->disableApp('files_trashbin');
  111. }
  112. \OC\Files\Filesystem::getLoader()->removeStorageWrapper('oc_trashbin');
  113. }
  114. public function shareFolderProvider() {
  115. return [
  116. ['/'],
  117. ['/my_shares'],
  118. ];
  119. }
  120. /**
  121. * if a file gets shared the etag for the recipients root should change
  122. *
  123. * @dataProvider shareFolderProvider
  124. *
  125. * @param string $shareFolder share folder to use
  126. */
  127. public function testShareFile($shareFolder) {
  128. $config = \OC::$server->getConfig();
  129. $oldShareFolder = $config->getSystemValue('share_folder');
  130. $config->setSystemValue('share_folder', $shareFolder);
  131. $this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
  132. $beforeShareRoot = \OC\Files\Filesystem::getFileInfo('');
  133. $etagBeforeShareRoot = $beforeShareRoot->getEtag();
  134. \OC\Files\Filesystem::mkdir($shareFolder);
  135. $beforeShareDir = \OC\Files\Filesystem::getFileInfo($shareFolder);
  136. $etagBeforeShareDir = $beforeShareDir->getEtag();
  137. $this->loginHelper(self::TEST_FILES_SHARING_API_USER1);
  138. $share = $this->share(
  139. IShare::TYPE_USER,
  140. $this->folder,
  141. self::TEST_FILES_SHARING_API_USER1,
  142. self::TEST_FILES_SHARING_API_USER2,
  143. \OCP\Constants::PERMISSION_ALL
  144. );
  145. $this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
  146. $afterShareRoot = \OC\Files\Filesystem::getFileInfo('');
  147. $etagAfterShareRoot = $afterShareRoot->getEtag();
  148. $afterShareDir = \OC\Files\Filesystem::getFileInfo($shareFolder);
  149. $etagAfterShareDir = $afterShareDir->getEtag();
  150. $this->assertTrue(is_string($etagBeforeShareRoot));
  151. $this->assertTrue(is_string($etagBeforeShareDir));
  152. $this->assertTrue(is_string($etagAfterShareRoot));
  153. $this->assertTrue(is_string($etagAfterShareDir));
  154. $this->assertTrue($etagBeforeShareRoot !== $etagAfterShareRoot);
  155. $this->assertTrue($etagBeforeShareDir !== $etagAfterShareDir);
  156. // cleanup
  157. $this->loginHelper(self::TEST_FILES_SHARING_API_USER1);
  158. $this->shareManager->deleteShare($share);
  159. $config->setSystemValue('share_folder', $oldShareFolder);
  160. }
  161. /**
  162. * if a folder gets renamed all children mount points should be renamed too
  163. */
  164. public function testRename() {
  165. $fileinfo = \OC\Files\Filesystem::getFileInfo($this->folder);
  166. $share = $this->share(
  167. IShare::TYPE_USER,
  168. $this->folder,
  169. self::TEST_FILES_SHARING_API_USER1,
  170. self::TEST_FILES_SHARING_API_USER2,
  171. \OCP\Constants::PERMISSION_ALL
  172. );
  173. $this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
  174. // make sure that the shared folder exists
  175. $this->assertTrue(\OC\Files\Filesystem::file_exists($this->folder));
  176. \OC\Files\Filesystem::mkdir('oldTarget');
  177. \OC\Files\Filesystem::mkdir('oldTarget/subfolder');
  178. \OC\Files\Filesystem::mkdir('newTarget');
  179. \OC\Files\Filesystem::rename($this->folder, 'oldTarget/subfolder/' . $this->folder);
  180. // re-login to make sure that the new mount points are initialized
  181. $this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
  182. \OC\Files\Filesystem::rename('/oldTarget', '/newTarget/oldTarget');
  183. // re-login to make sure that the new mount points are initialized
  184. $this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
  185. $this->assertTrue(\OC\Files\Filesystem::file_exists('/newTarget/oldTarget/subfolder/' . $this->folder));
  186. // cleanup
  187. $this->shareManager->deleteShare($share);
  188. }
  189. /**
  190. * If a folder gets moved into shared folder, children shares should have their uid_owner and permissions adjusted
  191. * user1
  192. * |-folder1 --> shared with user2
  193. * user2
  194. * |-folder2 --> shared with user3 and moved into folder1
  195. * |-subfolder1 --> shared with user3
  196. * |-file1.txt --> shared with user3
  197. * |-subfolder2
  198. * |-file2.txt --> shared with user3
  199. */
  200. public function testMovedIntoShareChangeOwner() {
  201. $this->markTestSkipped('Skipped because this is failing with S3 as primary as file id are change when moved.');
  202. // user1 creates folder1
  203. $viewUser1 = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files');
  204. $folder1 = 'folder1';
  205. $viewUser1->mkdir($folder1);
  206. // user1 shares folder1 to user2
  207. $folder1Share = $this->share(
  208. IShare::TYPE_USER,
  209. $folder1,
  210. self::TEST_FILES_SHARING_API_USER1,
  211. self::TEST_FILES_SHARING_API_USER2,
  212. \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_SHARE
  213. );
  214. $this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
  215. $viewUser2 = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
  216. // Create user2 files
  217. $folder2 = 'folder2';
  218. $viewUser2->mkdir($folder2);
  219. $file1 = 'folder2/file1.txt';
  220. $viewUser2->touch($file1);
  221. $subfolder1 = 'folder2/subfolder1';
  222. $viewUser2->mkdir($subfolder1);
  223. $subfolder2 = 'folder2/subfolder2';
  224. $viewUser2->mkdir($subfolder2);
  225. $file2 = 'folder2/subfolder2/file2.txt';
  226. $viewUser2->touch($file2);
  227. // user2 shares folder2 to user3
  228. $folder2Share = $this->share(
  229. IShare::TYPE_USER,
  230. $folder2,
  231. self::TEST_FILES_SHARING_API_USER2,
  232. self::TEST_FILES_SHARING_API_USER3,
  233. \OCP\Constants::PERMISSION_ALL
  234. );
  235. // user2 shares folder2/file1 to user3
  236. $file1Share = $this->share(
  237. IShare::TYPE_USER,
  238. $file1,
  239. self::TEST_FILES_SHARING_API_USER2,
  240. self::TEST_FILES_SHARING_API_USER3,
  241. \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_SHARE
  242. );
  243. // user2 shares subfolder1 to user3
  244. $subfolder1Share = $this->share(
  245. IShare::TYPE_USER,
  246. $subfolder1,
  247. self::TEST_FILES_SHARING_API_USER2,
  248. self::TEST_FILES_SHARING_API_USER3,
  249. \OCP\Constants::PERMISSION_ALL
  250. );
  251. // user2 shares subfolder2/file2.txt to user3
  252. $file2Share = $this->share(
  253. IShare::TYPE_USER,
  254. $file2,
  255. self::TEST_FILES_SHARING_API_USER2,
  256. self::TEST_FILES_SHARING_API_USER3,
  257. \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_SHARE
  258. );
  259. // user2 moves folder2 into folder1
  260. $viewUser2->rename($folder2, $folder1.'/'.$folder2);
  261. $folder2Share = $this->shareManager->getShareById($folder2Share->getFullId());
  262. $file1Share = $this->shareManager->getShareById($file1Share->getFullId());
  263. $subfolder1Share = $this->shareManager->getShareById($subfolder1Share->getFullId());
  264. $file2Share = $this->shareManager->getShareById($file2Share->getFullId());
  265. // Expect uid_owner of both shares to be user1
  266. $this->assertEquals(self::TEST_FILES_SHARING_API_USER1, $folder2Share->getShareOwner());
  267. $this->assertEquals(self::TEST_FILES_SHARING_API_USER1, $file1Share->getShareOwner());
  268. $this->assertEquals(self::TEST_FILES_SHARING_API_USER1, $subfolder1Share->getShareOwner());
  269. $this->assertEquals(self::TEST_FILES_SHARING_API_USER1, $file2Share->getShareOwner());
  270. // Expect permissions to be limited by the permissions of the destination share
  271. $this->assertEquals(\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_SHARE, $folder2Share->getPermissions());
  272. $this->assertEquals(\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_SHARE, $file1Share->getPermissions());
  273. $this->assertEquals(\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_SHARE, $subfolder1Share->getPermissions());
  274. $this->assertEquals(\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_SHARE, $file2Share->getPermissions());
  275. // user2 moves folder2 out of folder1
  276. $viewUser2->rename($folder1.'/'.$folder2, $folder2);
  277. $folder2Share = $this->shareManager->getShareById($folder2Share->getFullId());
  278. $file1Share = $this->shareManager->getShareById($file1Share->getFullId());
  279. $subfolder1Share = $this->shareManager->getShareById($subfolder1Share->getFullId());
  280. $file2Share = $this->shareManager->getShareById($file2Share->getFullId());
  281. // Expect uid_owner of both shares to be user2
  282. $this->assertEquals(self::TEST_FILES_SHARING_API_USER2, $folder2Share->getShareOwner());
  283. $this->assertEquals(self::TEST_FILES_SHARING_API_USER2, $file1Share->getShareOwner());
  284. $this->assertEquals(self::TEST_FILES_SHARING_API_USER2, $subfolder1Share->getShareOwner());
  285. $this->assertEquals(self::TEST_FILES_SHARING_API_USER2, $file2Share->getShareOwner());
  286. // Expect permissions to not change
  287. $this->assertEquals(\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_SHARE, $folder2Share->getPermissions());
  288. $this->assertEquals(\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_SHARE, $file1Share->getPermissions());
  289. $this->assertEquals(\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_SHARE, $subfolder1Share->getPermissions());
  290. $this->assertEquals(\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_SHARE, $file2Share->getPermissions());
  291. // cleanup
  292. $this->shareManager->deleteShare($folder1Share);
  293. $this->shareManager->deleteShare($folder2Share);
  294. $this->shareManager->deleteShare($file1Share);
  295. $this->shareManager->deleteShare($subfolder1Share);
  296. $this->shareManager->deleteShare($file2Share);
  297. }
  298. }