diff options
225 files changed, 14442 insertions, 14441 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index d3e31a586de..3a8302b6098 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,15 +1,16 @@ -# .git-blame-ignore-revs - -# SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors -# SPDX-License-Identifier: AGPL-3.0-or-later - -# Format control structures -caff1023ea72bb2ea94130e18a2a6e2ccf819e5f -# Update to coding-standard 1.1.1 -aa5f037af71c915424c6dcfd5ad2dc82797dc0d6 -# Update to coding-standard 1.2.3 -af6de04e9e141466dc229e444ff3f146f4a34765 -0bd284cb81b6866338aaaa67aa1d81ef9bfbb2ab -8af7ecb2576071f170ecbb0aa2311b26581e40e2 -# Automated refactorings -49dd79eabb2b8902559a7a4e8f8fcad54f46b604 +# .git-blame-ignore-revs + +# SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later + +# Format control structures +caff1023ea72bb2ea94130e18a2a6e2ccf819e5f +# Update to coding-standard 1.1.1 +aa5f037af71c915424c6dcfd5ad2dc82797dc0d6 +# Update to coding-standard 1.2.3 +af6de04e9e141466dc229e444ff3f146f4a34765 +0bd284cb81b6866338aaaa67aa1d81ef9bfbb2ab +8af7ecb2576071f170ecbb0aa2311b26581e40e2 +# Automated refactorings +275a8ce1dc69e3ae6e27a34d3c8501c1e3078f09 +49dd79eabb2b8902559a7a4e8f8fcad54f46b604 diff --git a/apps/admin_audit/lib/AppInfo/Application.php b/apps/admin_audit/lib/AppInfo/Application.php index b6af8dbed04..dc68527d822 100644 --- a/apps/admin_audit/lib/AppInfo/Application.php +++ b/apps/admin_audit/lib/AppInfo/Application.php @@ -232,6 +232,6 @@ class Application extends App implements IBootstrap { private function trashbinHooks(IAuditLogger $logger): void { $trashActions = new Trashbin($logger); Util::connectHook('\OCP\Trashbin', 'preDelete', $trashActions, 'delete'); - Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', $trashActions, 'restore'); + Util::connectHook(\OCA\Files_Trashbin\Trashbin::class, 'post_restore', $trashActions, 'restore'); } } diff --git a/apps/comments/tests/Unit/AppInfo/ApplicationTest.php b/apps/comments/tests/Unit/AppInfo/ApplicationTest.php index 4b87982ab45..fa23936425c 100644 --- a/apps/comments/tests/Unit/AppInfo/ApplicationTest.php +++ b/apps/comments/tests/Unit/AppInfo/ApplicationTest.php @@ -35,12 +35,12 @@ class ApplicationTest extends TestCase { $c = $app->getContainer(); $services = [ - 'OCA\Comments\Controller\NotificationsController', - 'OCA\Comments\Activity\Filter', - 'OCA\Comments\Activity\Listener', - 'OCA\Comments\Activity\Provider', - 'OCA\Comments\Activity\Setting', - 'OCA\Comments\Notification\Listener', + \OCA\Comments\Controller\NotificationsController::class, + \OCA\Comments\Activity\Filter::class, + \OCA\Comments\Activity\Listener::class, + \OCA\Comments\Activity\Provider::class, + \OCA\Comments\Activity\Setting::class, + \OCA\Comments\Notification\Listener::class, Notifier::class, ]; diff --git a/apps/comments/tests/Unit/Notification/ListenerTest.php b/apps/comments/tests/Unit/Notification/ListenerTest.php index 4cdb5f93b15..f7ebbfaa12c 100644 --- a/apps/comments/tests/Unit/Notification/ListenerTest.php +++ b/apps/comments/tests/Unit/Notification/ListenerTest.php @@ -102,7 +102,7 @@ class ListenerTest extends TestCase { ->willReturn($notification); $this->notificationManager->expects($this->exactly(6)) ->method($notificationMethod) - ->with($this->isInstanceOf('\OCP\Notification\INotification')); + ->with($this->isInstanceOf(\OCP\Notification\INotification::class)); $this->userManager->expects($this->exactly(6)) ->method('userExists') diff --git a/apps/dav/lib/CalDAV/Search/Xml/Request/CalendarSearchReport.php b/apps/dav/lib/CalDAV/Search/Xml/Request/CalendarSearchReport.php index 639d0b32655..f77b27147ba 100644 --- a/apps/dav/lib/CalDAV/Search/Xml/Request/CalendarSearchReport.php +++ b/apps/dav/lib/CalDAV/Search/Xml/Request/CalendarSearchReport.php @@ -67,12 +67,12 @@ class CalendarSearchReport implements XmlDeserializable { */ public static function xmlDeserialize(Reader $reader) { $elems = $reader->parseInnerTree([ - '{http://nextcloud.com/ns}comp-filter' => 'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\CompFilter', - '{http://nextcloud.com/ns}prop-filter' => 'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\PropFilter', - '{http://nextcloud.com/ns}param-filter' => 'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\ParamFilter', - '{http://nextcloud.com/ns}search-term' => 'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\SearchTermFilter', - '{http://nextcloud.com/ns}limit' => 'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\LimitFilter', - '{http://nextcloud.com/ns}offset' => 'OCA\\DAV\\CalDAV\\Search\\Xml\\Filter\\OffsetFilter', + '{http://nextcloud.com/ns}comp-filter' => \OCA\DAV\CalDAV\Search\Xml\Filter\CompFilter::class, + '{http://nextcloud.com/ns}prop-filter' => \OCA\DAV\CalDAV\Search\Xml\Filter\PropFilter::class, + '{http://nextcloud.com/ns}param-filter' => \OCA\DAV\CalDAV\Search\Xml\Filter\ParamFilter::class, + '{http://nextcloud.com/ns}search-term' => \OCA\DAV\CalDAV\Search\Xml\Filter\SearchTermFilter::class, + '{http://nextcloud.com/ns}limit' => \OCA\DAV\CalDAV\Search\Xml\Filter\LimitFilter::class, + '{http://nextcloud.com/ns}offset' => \OCA\DAV\CalDAV\Search\Xml\Filter\OffsetFilter::class, '{DAV:}prop' => 'Sabre\\Xml\\Element\\KeyValue', ]); diff --git a/apps/dav/tests/unit/CalDAV/PublicCalendarRootTest.php b/apps/dav/tests/unit/CalDAV/PublicCalendarRootTest.php index 4333754222b..20473616761 100644 --- a/apps/dav/tests/unit/CalDAV/PublicCalendarRootTest.php +++ b/apps/dav/tests/unit/CalDAV/PublicCalendarRootTest.php @@ -52,7 +52,7 @@ class PublicCalendarRootTest extends TestCase { parent::setUp(); $db = \OC::$server->getDatabaseConnection(); - $this->principal = $this->createMock('OCA\DAV\Connector\Sabre\Principal'); + $this->principal = $this->createMock(\OCA\DAV\Connector\Sabre\Principal::class); $this->userManager = $this->createMock(IUserManager::class); $this->groupManager = $this->createMock(IGroupManager::class); $this->random = \OC::$server->getSecureRandom(); diff --git a/apps/dav/tests/unit/CalDAV/Search/Request/CalendarSearchReportTest.php b/apps/dav/tests/unit/CalDAV/Search/Request/CalendarSearchReportTest.php index cbfd4639ed7..0a93fb7a4c8 100644 --- a/apps/dav/tests/unit/CalDAV/Search/Request/CalendarSearchReportTest.php +++ b/apps/dav/tests/unit/CalDAV/Search/Request/CalendarSearchReportTest.php @@ -12,7 +12,7 @@ use Test\TestCase; class CalendarSearchReportTest extends TestCase { private $elementMap = [ '{http://nextcloud.com/ns}calendar-search' => - 'OCA\\DAV\\CalDAV\\Search\\Xml\\Request\\CalendarSearchReport', + \OCA\DAV\CalDAV\Search\Xml\Request\CalendarSearchReport::class, ]; public function testFoo(): void { diff --git a/apps/dav/tests/unit/CalDAV/Search/SearchPluginTest.php b/apps/dav/tests/unit/CalDAV/Search/SearchPluginTest.php index ae4519e2542..4c7d7faaf93 100644 --- a/apps/dav/tests/unit/CalDAV/Search/SearchPluginTest.php +++ b/apps/dav/tests/unit/CalDAV/Search/SearchPluginTest.php @@ -51,7 +51,7 @@ class SearchPluginTest extends TestCase { $this->assertEquals( $server->xml->elementMap['{http://nextcloud.com/ns}calendar-search'], - 'OCA\\DAV\\CalDAV\\Search\\Xml\\Request\\CalendarSearchReport' + \OCA\DAV\CalDAV\Search\Xml\Request\CalendarSearchReport::class ); } diff --git a/apps/dav/tests/unit/Connector/Sabre/CommentsPropertiesPluginTest.php b/apps/dav/tests/unit/Connector/Sabre/CommentsPropertiesPluginTest.php index 1cda0e4dbdb..830a4a7f417 100644 --- a/apps/dav/tests/unit/Connector/Sabre/CommentsPropertiesPluginTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/CommentsPropertiesPluginTest.php @@ -42,7 +42,7 @@ class CommentsPropertiesPluginTest extends \Test\TestCase { public function nodeProvider() { $mocks = []; - foreach (['\OCA\DAV\Connector\Sabre\File', '\OCA\DAV\Connector\Sabre\Directory', '\Sabre\DAV\INode'] as $class) { + foreach ([\OCA\DAV\Connector\Sabre\File::class, \OCA\DAV\Connector\Sabre\Directory::class, '\Sabre\DAV\INode'] as $class) { $mocks[] = $this->getMockBuilder($class) ->disableOriginalConstructor() ->getMock(); diff --git a/apps/dav/tests/unit/Connector/Sabre/DirectoryTest.php b/apps/dav/tests/unit/Connector/Sabre/DirectoryTest.php index fb180b7c65d..46dde7e0641 100644 --- a/apps/dav/tests/unit/Connector/Sabre/DirectoryTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/DirectoryTest.php @@ -65,8 +65,8 @@ class DirectoryTest extends \Test\TestCase { protected function setUp(): void { parent::setUp(); - $this->view = $this->createMock('OC\Files\View'); - $this->info = $this->createMock('OC\Files\FileInfo'); + $this->view = $this->createMock(\OC\Files\View::class); + $this->info = $this->createMock(\OC\Files\FileInfo::class); $this->info->method('isReadable') ->willReturn(true); $this->info->method('getType') @@ -283,8 +283,8 @@ class DirectoryTest extends \Test\TestCase { $storage->expects($this->any()) ->method('instanceOfStorage') ->willReturnMap([ - '\OCA\Files_Sharing\SharedStorage' => false, - '\OC\Files\Storage\Wrapper\Quota' => false, + \OCA\Files_Sharing\SharedStorage::class => false, + \OC\Files\Storage\Wrapper\Quota::class => false, ]); $storage->expects($this->once()) @@ -334,8 +334,8 @@ class DirectoryTest extends \Test\TestCase { $storage->expects($this->any()) ->method('instanceOfStorage') ->willReturnMap([ - ['\OCA\Files_Sharing\SharedStorage', false], - ['\OC\Files\Storage\Wrapper\Quota', true], + [\OCA\Files_Sharing\SharedStorage::class, false], + [\OC\Files\Storage\Wrapper\Quota::class, true], ]); $storage->expects($this->once()) diff --git a/apps/dav/tests/unit/Connector/Sabre/FileTest.php b/apps/dav/tests/unit/Connector/Sabre/FileTest.php index 6f9a214fab9..baea3202610 100644 --- a/apps/dav/tests/unit/Connector/Sabre/FileTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/FileTest.php @@ -109,11 +109,11 @@ class FileTest extends TestCase { ], [ new \OCP\Files\EntityTooLargeException(), - 'OCA\DAV\Connector\Sabre\Exception\EntityTooLarge' + \OCA\DAV\Connector\Sabre\Exception\EntityTooLarge::class ], [ new \OCP\Files\InvalidContentException(), - 'OCA\DAV\Connector\Sabre\Exception\UnsupportedMediaType' + \OCA\DAV\Connector\Sabre\Exception\UnsupportedMediaType::class ], [ new \OCP\Files\InvalidPathException(), @@ -121,15 +121,15 @@ class FileTest extends TestCase { ], [ new \OCP\Files\ForbiddenException('', true), - 'OCA\DAV\Connector\Sabre\Exception\Forbidden' + \OCA\DAV\Connector\Sabre\Exception\Forbidden::class ], [ new \OCP\Files\LockNotAcquiredException('/test.txt', 1), - 'OCA\DAV\Connector\Sabre\Exception\FileLocked' + \OCA\DAV\Connector\Sabre\Exception\FileLocked::class ], [ new \OCP\Lock\LockedException('/test.txt'), - 'OCA\DAV\Connector\Sabre\Exception\FileLocked' + \OCA\DAV\Connector\Sabre\Exception\FileLocked::class ], [ new \OCP\Encryption\Exceptions\GenericEncryptionException(), @@ -454,7 +454,7 @@ class FileTest extends TestCase { \OCP\Util::connectHook( Filesystem::CLASSNAME, Filesystem::signal_create, - '\Test\HookHelper', + \Test\HookHelper::class, 'cancellingCallback' ); diff --git a/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php b/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php index 9d8f4e8d4c4..74d36a06f1f 100644 --- a/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php @@ -124,7 +124,7 @@ class FilesPluginTest extends TestCase { public function testGetPropertiesForFile(): void { /** @var \OCA\DAV\Connector\Sabre\File | \PHPUnit\Framework\MockObject\MockObject $node */ - $node = $this->createTestNode('\OCA\DAV\Connector\Sabre\File'); + $node = $this->createTestNode(\OCA\DAV\Connector\Sabre\File::class); $propFind = new PropFind( '/dummyPath', @@ -181,7 +181,7 @@ class FilesPluginTest extends TestCase { public function testGetPropertiesStorageNotAvailable(): void { /** @var \OCA\DAV\Connector\Sabre\File | \PHPUnit\Framework\MockObject\MockObject $node */ - $node = $this->createTestNode('\OCA\DAV\Connector\Sabre\File'); + $node = $this->createTestNode(\OCA\DAV\Connector\Sabre\File::class); $propFind = new PropFind( '/dummyPath', @@ -228,7 +228,7 @@ class FilesPluginTest extends TestCase { ); /** @var \OCA\DAV\Connector\Sabre\File | \PHPUnit\Framework\MockObject\MockObject $node */ - $node = $this->createTestNode('\OCA\DAV\Connector\Sabre\File'); + $node = $this->createTestNode(\OCA\DAV\Connector\Sabre\File::class); $node->expects($this->any()) ->method('getDavPermissions') ->willReturn('DWCKMSR'); @@ -243,7 +243,7 @@ class FilesPluginTest extends TestCase { public function testGetPropertiesForDirectory(): void { /** @var \OCA\DAV\Connector\Sabre\Directory | \PHPUnit\Framework\MockObject\MockObject $node */ - $node = $this->createTestNode('\OCA\DAV\Connector\Sabre\Directory'); + $node = $this->createTestNode(\OCA\DAV\Connector\Sabre\Directory::class); $propFind = new PropFind( '/dummyPath', @@ -345,7 +345,7 @@ class FilesPluginTest extends TestCase { } public function testUpdateProps(): void { - $node = $this->createTestNode('\OCA\DAV\Connector\Sabre\File'); + $node = $this->createTestNode(\OCA\DAV\Connector\Sabre\File::class); $testDate = 'Fri, 13 Feb 2015 00:01:02 GMT'; $testCreationDate = '2007-08-31T16:47+00:00'; @@ -615,7 +615,7 @@ class FilesPluginTest extends TestCase { public function testHasPreview(): void { /** @var \OCA\DAV\Connector\Sabre\Directory | \PHPUnit\Framework\MockObject\MockObject $node */ - $node = $this->createTestNode('\OCA\DAV\Connector\Sabre\Directory'); + $node = $this->createTestNode(\OCA\DAV\Connector\Sabre\Directory::class); $propFind = new PropFind( '/dummyPath', diff --git a/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php b/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php index 76a70a93e13..4a47d4c94b0 100644 --- a/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php @@ -293,9 +293,9 @@ class FilesReportPluginTest extends \Test\TestCase { $result = $this->plugin->findNodesByFileIds($reportTargetNode, ['111', '222']); $this->assertCount(2, $result); - $this->assertInstanceOf('\OCA\DAV\Connector\Sabre\Directory', $result[0]); + $this->assertInstanceOf(\OCA\DAV\Connector\Sabre\Directory::class, $result[0]); $this->assertEquals('first node', $result[0]->getName()); - $this->assertInstanceOf('\OCA\DAV\Connector\Sabre\File', $result[1]); + $this->assertInstanceOf(\OCA\DAV\Connector\Sabre\File::class, $result[1]); $this->assertEquals('second node', $result[1]->getName()); } @@ -346,9 +346,9 @@ class FilesReportPluginTest extends \Test\TestCase { $result = $this->plugin->findNodesByFileIds($reportTargetNode, ['111', '222']); $this->assertCount(2, $result); - $this->assertInstanceOf('\OCA\DAV\Connector\Sabre\Directory', $result[0]); + $this->assertInstanceOf(\OCA\DAV\Connector\Sabre\Directory::class, $result[0]); $this->assertEquals('first node', $result[0]->getName()); - $this->assertInstanceOf('\OCA\DAV\Connector\Sabre\File', $result[1]); + $this->assertInstanceOf(\OCA\DAV\Connector\Sabre\File::class, $result[1]); $this->assertEquals('second node', $result[1]->getName()); } diff --git a/apps/dav/tests/unit/Connector/Sabre/RequestTest/DeleteTest.php b/apps/dav/tests/unit/Connector/Sabre/RequestTest/DeleteTest.php index e7f20fbadfa..24a017b3a8b 100644 --- a/apps/dav/tests/unit/Connector/Sabre/RequestTest/DeleteTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/RequestTest/DeleteTest.php @@ -29,7 +29,7 @@ class DeleteTest extends RequestTestCase { $mount->getStorage()->unlink($mount->getInternalPath($internalPath)); // cache entry still exists - $this->assertInstanceOf('\OCP\Files\FileInfo', $view->getFileInfo('foo.txt')); + $this->assertInstanceOf(\OCP\Files\FileInfo::class, $view->getFileInfo('foo.txt')); $response = $this->request($view, $user, 'pass', 'DELETE', '/foo.txt'); diff --git a/apps/dav/tests/unit/Connector/Sabre/RequestTest/EncryptionMasterKeyUploadTest.php b/apps/dav/tests/unit/Connector/Sabre/RequestTest/EncryptionMasterKeyUploadTest.php index cbaa0c3101b..575e37652ba 100644 --- a/apps/dav/tests/unit/Connector/Sabre/RequestTest/EncryptionMasterKeyUploadTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/RequestTest/EncryptionMasterKeyUploadTest.php @@ -23,7 +23,7 @@ class EncryptionMasterKeyUploadTest extends UploadTest { protected function setupUser($name, $password) { $this->createUser($name, $password); $tmpFolder = \OC::$server->getTempManager()->getTemporaryFolder(); - $this->registerMount($name, '\OC\Files\Storage\Local', '/' . $name, ['datadir' => $tmpFolder]); + $this->registerMount($name, \OC\Files\Storage\Local::class, '/' . $name, ['datadir' => $tmpFolder]); // we use the master key \OC::$server->getConfig()->setAppValue('encryption', 'useMasterKey', '1'); $this->setupForUser($name, $password); diff --git a/apps/dav/tests/unit/Connector/Sabre/RequestTest/EncryptionUploadTest.php b/apps/dav/tests/unit/Connector/Sabre/RequestTest/EncryptionUploadTest.php index f830c54fd0d..86242c32e78 100644 --- a/apps/dav/tests/unit/Connector/Sabre/RequestTest/EncryptionUploadTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/RequestTest/EncryptionUploadTest.php @@ -23,7 +23,7 @@ class EncryptionUploadTest extends UploadTest { protected function setupUser($name, $password) { $this->createUser($name, $password); $tmpFolder = \OC::$server->getTempManager()->getTemporaryFolder(); - $this->registerMount($name, '\OC\Files\Storage\Local', '/' . $name, ['datadir' => $tmpFolder]); + $this->registerMount($name, \OC\Files\Storage\Local::class, '/' . $name, ['datadir' => $tmpFolder]); // we use per-user keys \OC::$server->getConfig()->setAppValue('encryption', 'useMasterKey', '0'); $this->setupForUser($name, $password); diff --git a/apps/dav/tests/unit/Connector/Sabre/RequestTest/RequestTestCase.php b/apps/dav/tests/unit/Connector/Sabre/RequestTest/RequestTestCase.php index 29574d53bca..599e9a8e5ef 100644 --- a/apps/dav/tests/unit/Connector/Sabre/RequestTest/RequestTestCase.php +++ b/apps/dav/tests/unit/Connector/Sabre/RequestTest/RequestTestCase.php @@ -58,7 +58,7 @@ abstract class RequestTestCase extends TestCase { protected function setupUser($name, $password) { $this->createUser($name, $password); $tmpFolder = \OC::$server->getTempManager()->getTemporaryFolder(); - $this->registerMount($name, '\OC\Files\Storage\Local', '/' . $name, ['datadir' => $tmpFolder]); + $this->registerMount($name, \OC\Files\Storage\Local::class, '/' . $name, ['datadir' => $tmpFolder]); $this->loginAsUser($name); return new View('/' . $name . '/files'); } diff --git a/apps/dav/tests/unit/Connector/Sabre/RequestTest/UploadTest.php b/apps/dav/tests/unit/Connector/Sabre/RequestTest/UploadTest.php index 60decd4c846..80e758ba89c 100644 --- a/apps/dav/tests/unit/Connector/Sabre/RequestTest/UploadTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/RequestTest/UploadTest.php @@ -30,7 +30,7 @@ class UploadTest extends RequestTestCase { $this->assertEquals('asd', $view->file_get_contents('foo.txt')); $info = $view->getFileInfo('foo.txt'); - $this->assertInstanceOf('\OC\Files\FileInfo', $info); + $this->assertInstanceOf(\OC\Files\FileInfo::class, $info); $this->assertEquals(3, $info->getSize()); } @@ -46,7 +46,7 @@ class UploadTest extends RequestTestCase { $this->assertEquals('asd', $view->file_get_contents('foo.txt')); $info = $view->getFileInfo('foo.txt'); - $this->assertInstanceOf('\OC\Files\FileInfo', $info); + $this->assertInstanceOf(\OC\Files\FileInfo::class, $info); $this->assertEquals(3, $info->getSize()); } diff --git a/apps/dav/tests/unit/Controller/BirthdayCalendarControllerTest.php b/apps/dav/tests/unit/Controller/BirthdayCalendarControllerTest.php index c7c2bf0e431..ad5d42cae59 100644 --- a/apps/dav/tests/unit/Controller/BirthdayCalendarControllerTest.php +++ b/apps/dav/tests/unit/Controller/BirthdayCalendarControllerTest.php @@ -83,7 +83,7 @@ class BirthdayCalendarControllerTest extends TestCase { ); $response = $this->controller->enable(); - $this->assertInstanceOf('OCP\AppFramework\Http\JSONResponse', $response); + $this->assertInstanceOf(\OCP\AppFramework\Http\JSONResponse::class, $response); } public function testDisable(): void { @@ -97,6 +97,6 @@ class BirthdayCalendarControllerTest extends TestCase { ->method('deleteAllBirthdayCalendars'); $response = $this->controller->disable(); - $this->assertInstanceOf('OCP\AppFramework\Http\JSONResponse', $response); + $this->assertInstanceOf(\OCP\AppFramework\Http\JSONResponse::class, $response); } } diff --git a/apps/dav/tests/unit/SystemTag/SystemTagPluginTest.php b/apps/dav/tests/unit/SystemTag/SystemTagPluginTest.php index 67e7afa9c54..db4feda0d40 100644 --- a/apps/dav/tests/unit/SystemTag/SystemTagPluginTest.php +++ b/apps/dav/tests/unit/SystemTag/SystemTagPluginTest.php @@ -575,8 +575,8 @@ class SystemTagPluginTest extends \Test\TestCase { public function nodeClassProvider() { return [ - ['\OCA\DAV\SystemTag\SystemTagsByIdCollection'], - ['\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection'], + [\OCA\DAV\SystemTag\SystemTagsByIdCollection::class], + [\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection::class], ]; } diff --git a/apps/dav/tests/unit/SystemTag/SystemTagsByIdCollectionTest.php b/apps/dav/tests/unit/SystemTag/SystemTagsByIdCollectionTest.php index db55d82adc9..9629b1fcf70 100644 --- a/apps/dav/tests/unit/SystemTag/SystemTagsByIdCollectionTest.php +++ b/apps/dav/tests/unit/SystemTag/SystemTagsByIdCollectionTest.php @@ -89,7 +89,7 @@ class SystemTagsByIdCollectionTest extends \Test\TestCase { $childNode = $this->getNode()->getChild('123'); - $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $childNode); + $this->assertInstanceOf(\OCA\DAV\SystemTag\SystemTagNode::class, $childNode); $this->assertEquals('123', $childNode->getName()); $this->assertEquals($tag, $childNode->getSystemTag()); } @@ -145,8 +145,8 @@ class SystemTagsByIdCollectionTest extends \Test\TestCase { $this->assertCount(2, $children); - $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $children[0]); - $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $children[1]); + $this->assertInstanceOf(\OCA\DAV\SystemTag\SystemTagNode::class, $children[0]); + $this->assertInstanceOf(\OCA\DAV\SystemTag\SystemTagNode::class, $children[1]); $this->assertEquals($tag1, $children[0]->getSystemTag()); $this->assertEquals($tag2, $children[1]->getSystemTag()); } @@ -164,8 +164,8 @@ class SystemTagsByIdCollectionTest extends \Test\TestCase { $this->assertCount(2, $children); - $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $children[0]); - $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $children[1]); + $this->assertInstanceOf(\OCA\DAV\SystemTag\SystemTagNode::class, $children[0]); + $this->assertInstanceOf(\OCA\DAV\SystemTag\SystemTagNode::class, $children[1]); $this->assertEquals($tag1, $children[0]->getSystemTag()); $this->assertEquals($tag2, $children[1]->getSystemTag()); } diff --git a/apps/dav/tests/unit/SystemTag/SystemTagsObjectMappingCollectionTest.php b/apps/dav/tests/unit/SystemTag/SystemTagsObjectMappingCollectionTest.php index c2e62f73828..252700de2a7 100644 --- a/apps/dav/tests/unit/SystemTag/SystemTagsObjectMappingCollectionTest.php +++ b/apps/dav/tests/unit/SystemTag/SystemTagsObjectMappingCollectionTest.php @@ -163,7 +163,7 @@ class SystemTagsObjectMappingCollectionTest extends \Test\TestCase { $childNode = $this->getNode()->getChild('555'); - $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $childNode); + $this->assertInstanceOf(\OCA\DAV\SystemTag\SystemTagMappingNode::class, $childNode); $this->assertEquals('555', $childNode->getName()); } @@ -251,8 +251,8 @@ class SystemTagsObjectMappingCollectionTest extends \Test\TestCase { $this->assertCount(2, $children); - $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[0]); - $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[1]); + $this->assertInstanceOf(\OCA\DAV\SystemTag\SystemTagMappingNode::class, $children[0]); + $this->assertInstanceOf(\OCA\DAV\SystemTag\SystemTagMappingNode::class, $children[1]); $this->assertEquals(111, $children[0]->getObjectId()); $this->assertEquals('files', $children[0]->getObjectType()); diff --git a/apps/dav/tests/unit/SystemTag/SystemTagsObjectTypeCollectionTest.php b/apps/dav/tests/unit/SystemTag/SystemTagsObjectTypeCollectionTest.php index b202f340e32..d2868113efa 100644 --- a/apps/dav/tests/unit/SystemTag/SystemTagsObjectTypeCollectionTest.php +++ b/apps/dav/tests/unit/SystemTag/SystemTagsObjectTypeCollectionTest.php @@ -111,7 +111,7 @@ class SystemTagsObjectTypeCollectionTest extends \Test\TestCase { ->willReturn($this->createMock(\OCP\Files\Node::class)); $childNode = $this->node->getChild('555'); - $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection', $childNode); + $this->assertInstanceOf(\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection::class, $childNode); $this->assertEquals('555', $childNode->getName()); } diff --git a/apps/encryption/lib/Command/FixEncryptedVersion.php b/apps/encryption/lib/Command/FixEncryptedVersion.php index 6635bb6cba9..16181f22942 100644 --- a/apps/encryption/lib/Command/FixEncryptedVersion.php +++ b/apps/encryption/lib/Command/FixEncryptedVersion.php @@ -242,7 +242,7 @@ class FixEncryptedVersion extends Command { return true; } - if ($storage->instanceOfStorage('OCA\Files_Sharing\ISharedStorage')) { + if ($storage->instanceOfStorage(\OCA\Files_Sharing\ISharedStorage::class)) { $output->writeln("<info>The file: \"$path\" is a share. Please also run the script for the owner of the share</info>"); return true; } diff --git a/apps/encryption/lib/Crypto/Encryption.php b/apps/encryption/lib/Crypto/Encryption.php index f5b6a40aecc..caf88cb2fac 100644 --- a/apps/encryption/lib/Crypto/Encryption.php +++ b/apps/encryption/lib/Crypto/Encryption.php @@ -378,7 +378,7 @@ class Encryption implements IEncryptionModule { public function shouldEncrypt($path) { if ($this->util->shouldEncryptHomeStorage() === false) { $storage = $this->util->getStorage($path); - if ($storage && $storage->instanceOfStorage('\OCP\Files\IHomeStorage')) { + if ($storage && $storage->instanceOfStorage(\OCP\Files\IHomeStorage::class)) { return false; } } diff --git a/apps/encryption/tests/Command/FixEncryptedVersionTest.php b/apps/encryption/tests/Command/FixEncryptedVersionTest.php index fd6e27e030b..38e86779593 100644 --- a/apps/encryption/tests/Command/FixEncryptedVersionTest.php +++ b/apps/encryption/tests/Command/FixEncryptedVersionTest.php @@ -52,7 +52,7 @@ class FixEncryptedVersionTest extends TestCase { $this->createUser($this->userId, 'foo12345678'); $tmpFolder = \OC::$server->getTempManager()->getTemporaryFolder(); - $this->registerMount($this->userId, '\OC\Files\Storage\Local', '/' . $this->userId, ['datadir' => $tmpFolder]); + $this->registerMount($this->userId, \OC\Files\Storage\Local::class, '/' . $this->userId, ['datadir' => $tmpFolder]); $this->setupForUser($this->userId, 'foo12345678'); $this->loginWithEncryption($this->userId); diff --git a/apps/encryption/tests/Crypto/EncryptionTest.php b/apps/encryption/tests/Crypto/EncryptionTest.php index b07bd0a6b25..d9b0052a5b8 100644 --- a/apps/encryption/tests/Crypto/EncryptionTest.php +++ b/apps/encryption/tests/Crypto/EncryptionTest.php @@ -375,7 +375,7 @@ class EncryptionTest extends TestCase { if ($shouldEncryptHomeStorage === false) { $this->storageMock->expects($this->once())->method('instanceOfStorage') - ->with('\OCP\Files\IHomeStorage')->willReturn($isHomeStorage); + ->with(\OCP\Files\IHomeStorage::class)->willReturn($isHomeStorage); $this->utilMock->expects($this->once())->method('getStorage')->with($path) ->willReturn($this->storageMock); } diff --git a/apps/federatedfilesharing/lib/Notifications.php b/apps/federatedfilesharing/lib/Notifications.php index e107065d0c1..f9ecb98a0b9 100644 --- a/apps/federatedfilesharing/lib/Notifications.php +++ b/apps/federatedfilesharing/lib/Notifications.php @@ -249,7 +249,7 @@ class Notifications { return true; } elseif ($try === 0) { // only add new job on first try - $this->jobList->add('OCA\FederatedFileSharing\BackgroundJob\RetryJob', + $this->jobList->add(\OCA\FederatedFileSharing\BackgroundJob\RetryJob::class, [ 'remote' => $remote, 'remoteId' => $remoteId, diff --git a/apps/federatedfilesharing/tests/Controller/MountPublicLinkControllerTest.php b/apps/federatedfilesharing/tests/Controller/MountPublicLinkControllerTest.php index 6eb7ce30274..f365055c428 100644 --- a/apps/federatedfilesharing/tests/Controller/MountPublicLinkControllerTest.php +++ b/apps/federatedfilesharing/tests/Controller/MountPublicLinkControllerTest.php @@ -76,18 +76,18 @@ class MountPublicLinkControllerTest extends \Test\TestCase { parent::setUp(); $this->request = $this->getMockBuilder(IRequest::class)->disableOriginalConstructor()->getMock(); - $this->federatedShareProvider = $this->getMockBuilder('OCA\FederatedFileSharing\FederatedShareProvider') + $this->federatedShareProvider = $this->getMockBuilder(\OCA\FederatedFileSharing\FederatedShareProvider::class) ->disableOriginalConstructor()->getMock(); $this->shareManager = $this->getMockBuilder(IManager::class)->disableOriginalConstructor()->getMock(); - $this->addressHandler = $this->getMockBuilder('OCA\FederatedFileSharing\AddressHandler') + $this->addressHandler = $this->getMockBuilder(\OCA\FederatedFileSharing\AddressHandler::class) ->disableOriginalConstructor()->getMock(); - $this->rootFolder = $this->getMockBuilder('OCP\Files\IRootFolder')->disableOriginalConstructor()->getMock(); + $this->rootFolder = $this->getMockBuilder(\OCP\Files\IRootFolder::class)->disableOriginalConstructor()->getMock(); $this->userManager = $this->getMockBuilder(IUserManager::class)->disableOriginalConstructor()->getMock(); $this->share = new \OC\Share20\Share($this->rootFolder, $this->userManager); $this->session = $this->getMockBuilder(ISession::class)->disableOriginalConstructor()->getMock(); $this->l10n = $this->getMockBuilder(IL10N::class)->disableOriginalConstructor()->getMock(); $this->userSession = $this->getMockBuilder(IUserSession::class)->disableOriginalConstructor()->getMock(); - $this->clientService = $this->getMockBuilder('OCP\Http\Client\IClientService')->disableOriginalConstructor()->getMock(); + $this->clientService = $this->getMockBuilder(\OCP\Http\Client\IClientService::class)->disableOriginalConstructor()->getMock(); $this->contactsManager = $this->createMock(IContactsManager::class); $this->cloudIdManager = new CloudIdManager( $this->contactsManager, diff --git a/apps/federatedfilesharing/tests/Controller/RequestHandlerControllerTest.php b/apps/federatedfilesharing/tests/Controller/RequestHandlerControllerTest.php index cce1ee8830a..51350fddfa0 100644 --- a/apps/federatedfilesharing/tests/Controller/RequestHandlerControllerTest.php +++ b/apps/federatedfilesharing/tests/Controller/RequestHandlerControllerTest.php @@ -86,7 +86,7 @@ class RequestHandlerControllerTest extends \Test\TestCase { protected function setUp(): void { $this->share = $this->getMockBuilder(IShare::class)->getMock(); - $this->federatedShareProvider = $this->getMockBuilder('OCA\FederatedFileSharing\FederatedShareProvider') + $this->federatedShareProvider = $this->getMockBuilder(\OCA\FederatedFileSharing\FederatedShareProvider::class) ->disableOriginalConstructor()->getMock(); $this->federatedShareProvider->expects($this->any()) ->method('isOutgoingServer2serverShareEnabled')->willReturn(true); @@ -95,9 +95,9 @@ class RequestHandlerControllerTest extends \Test\TestCase { $this->federatedShareProvider->expects($this->any())->method('getShareById') ->willReturn($this->share); - $this->notifications = $this->getMockBuilder('OCA\FederatedFileSharing\Notifications') + $this->notifications = $this->getMockBuilder(\OCA\FederatedFileSharing\Notifications::class) ->disableOriginalConstructor()->getMock(); - $this->addressHandler = $this->getMockBuilder('OCA\FederatedFileSharing\AddressHandler') + $this->addressHandler = $this->getMockBuilder(\OCA\FederatedFileSharing\AddressHandler::class) ->disableOriginalConstructor()->getMock(); $this->userManager = $this->getMockBuilder(IUserManager::class)->getMock(); $this->cloudIdManager = $this->createMock(ICloudIdManager::class); diff --git a/apps/federatedfilesharing/tests/FederatedShareProviderTest.php b/apps/federatedfilesharing/tests/FederatedShareProviderTest.php index 5255a84b461..a687c5738e1 100644 --- a/apps/federatedfilesharing/tests/FederatedShareProviderTest.php +++ b/apps/federatedfilesharing/tests/FederatedShareProviderTest.php @@ -1,989 +1,989 @@ -<?php - -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-only - */ -namespace OCA\FederatedFileSharing\Tests; - -use OC\Federation\CloudIdManager; -use OCA\FederatedFileSharing\AddressHandler; -use OCA\FederatedFileSharing\FederatedShareProvider; -use OCA\FederatedFileSharing\Notifications; -use OCA\FederatedFileSharing\TokenHandler; -use OCP\Contacts\IManager as IContactsManager; -use OCP\EventDispatcher\IEventDispatcher; -use OCP\Federation\ICloudFederationProviderManager; -use OCP\Federation\ICloudIdManager; -use OCP\Files\File; -use OCP\Files\IRootFolder; -use OCP\ICacheFactory; -use OCP\IConfig; -use OCP\IDBConnection; -use OCP\IL10N; -use OCP\IURLGenerator; -use OCP\IUserManager; -use OCP\Share\IManager; -use OCP\Share\IShare; -use PHPUnit\Framework\MockObject\MockObject; -use Psr\Log\LoggerInterface; - -/** - * Class FederatedShareProviderTest - * - * @package OCA\FederatedFileSharing\Tests - * @group DB - */ -class FederatedShareProviderTest extends \Test\TestCase { - /** @var IDBConnection */ - protected $connection; - /** @var AddressHandler|MockObject */ - protected $addressHandler; - /** @var Notifications|MockObject */ - protected $notifications; - /** @var TokenHandler|MockObject */ - protected $tokenHandler; - /** @var IL10N */ - protected $l; - /** @var LoggerInterface */ - protected $logger; - /** @var IRootFolder|MockObject */ - protected $rootFolder; - /** @var IConfig|MockObject */ - protected $config; - /** @var IUserManager|MockObject */ - protected $userManager; - /** @var \OCP\GlobalScale\IConfig|MockObject */ - protected $gsConfig; - - /** @var IManager */ - protected $shareManager; - /** @var FederatedShareProvider */ - protected $provider; - /** @var IContactsManager|MockObject */ - protected $contactsManager; - - /** @var ICloudIdManager */ - private $cloudIdManager; - - /** @var MockObject|ICloudFederationProviderManager */ - private $cloudFederationProviderManager; - - protected function setUp(): void { - parent::setUp(); - - $this->connection = \OC::$server->getDatabaseConnection(); - $this->notifications = $this->getMockBuilder('OCA\FederatedFileSharing\Notifications') - ->disableOriginalConstructor() - ->getMock(); - $this->tokenHandler = $this->getMockBuilder('OCA\FederatedFileSharing\TokenHandler') - ->disableOriginalConstructor() - ->getMock(); - $this->l = $this->getMockBuilder(IL10N::class)->getMock(); - $this->l->method('t') - ->willReturnCallback(function ($text, $parameters = []) { - return vsprintf($text, $parameters); - }); - $this->logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); - $this->rootFolder = $this->getMockBuilder('OCP\Files\IRootFolder')->getMock(); - $this->config = $this->getMockBuilder(IConfig::class)->getMock(); - $this->userManager = $this->getMockBuilder(IUserManager::class)->getMock(); - //$this->addressHandler = new AddressHandler(\OC::$server->getURLGenerator(), $this->l); - $this->addressHandler = $this->getMockBuilder('OCA\FederatedFileSharing\AddressHandler')->disableOriginalConstructor()->getMock(); - $this->contactsManager = $this->createMock(IContactsManager::class); - $this->cloudIdManager = new CloudIdManager( - $this->contactsManager, - $this->createMock(IURLGenerator::class), - $this->userManager, - $this->createMock(ICacheFactory::class), - $this->createMock(IEventDispatcher::class) - ); - $this->gsConfig = $this->createMock(\OCP\GlobalScale\IConfig::class); - - $this->userManager->expects($this->any())->method('userExists')->willReturn(true); - - $this->cloudFederationProviderManager = $this->createMock(ICloudFederationProviderManager::class); - - $this->provider = new FederatedShareProvider( - $this->connection, - $this->addressHandler, - $this->notifications, - $this->tokenHandler, - $this->l, - $this->rootFolder, - $this->config, - $this->userManager, - $this->cloudIdManager, - $this->gsConfig, - $this->cloudFederationProviderManager, - $this->logger, - ); - - $this->shareManager = \OC::$server->getShareManager(); - } - - protected function tearDown(): void { - $this->connection->getQueryBuilder()->delete('share')->execute(); - - parent::tearDown(); - } - - public function dataTestCreate() { - return [ - [null, null], - [new \DateTime('2020-03-01T01:02:03'), '2020-03-01 01:02:03'], - ]; - } - - /** - * @dataProvider dataTestCreate - */ - public function testCreate($expirationDate, $expectedDataDate): void { - $share = $this->shareManager->newShare(); - - /** @var File|MockObject $node */ - $node = $this->getMockBuilder(File::class)->getMock(); - $node->method('getId')->willReturn(42); - $node->method('getName')->willReturn('myFile'); - - $share->setSharedWith('user@server.com') - ->setSharedBy('sharedBy') - ->setShareOwner('shareOwner') - ->setPermissions(19) - ->setShareType(IShare::TYPE_REMOTE) - ->setExpirationDate($expirationDate) - ->setNode($node); - - $this->tokenHandler->method('generateToken')->willReturn('token'); - - $this->addressHandler->expects($this->any())->method('generateRemoteURL') - ->willReturn('http://localhost/'); - $this->addressHandler->expects($this->any())->method('splitUserRemote') - ->willReturn(['user', 'server.com']); - - $this->notifications->expects($this->once()) - ->method('sendRemoteShare') - ->with( - $this->equalTo('token'), - $this->equalTo('user@server.com'), - $this->equalTo('myFile'), - $this->anything(), - 'shareOwner', - 'shareOwner@http://localhost', - 'sharedBy', - 'sharedBy@http://localhost' - ) - ->willReturn(true); - - $this->rootFolder->expects($this->never())->method($this->anything()); - - $this->contactsManager->expects($this->any()) - ->method('search') - ->willReturn([]); - - $share = $this->provider->create($share); - - $qb = $this->connection->getQueryBuilder(); - $stmt = $qb->select('*') - ->from('share') - ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) - ->execute(); - - $data = $stmt->fetch(); - $stmt->closeCursor(); - - $expected = [ - 'share_type' => IShare::TYPE_REMOTE, - 'share_with' => 'user@server.com', - 'uid_owner' => 'shareOwner', - 'uid_initiator' => 'sharedBy', - 'item_type' => 'file', - 'item_source' => 42, - 'file_source' => 42, - 'permissions' => 19, - 'accepted' => 0, - 'token' => 'token', - 'expiration' => $expectedDataDate, - ]; - foreach (array_keys($expected) as $key) { - $this->assertEquals($expected[$key], $data[$key], "Assert that value for key '$key' is the same"); - } - - $this->assertEquals($data['id'], $share->getId()); - $this->assertEquals(IShare::TYPE_REMOTE, $share->getShareType()); - $this->assertEquals('user@server.com', $share->getSharedWith()); - $this->assertEquals('sharedBy', $share->getSharedBy()); - $this->assertEquals('shareOwner', $share->getShareOwner()); - $this->assertEquals('file', $share->getNodeType()); - $this->assertEquals(42, $share->getNodeId()); - $this->assertEquals(19, $share->getPermissions()); - $this->assertEquals('token', $share->getToken()); - $this->assertEquals($expirationDate, $share->getExpirationDate()); - } - - public function testCreateCouldNotFindServer(): void { - $share = $this->shareManager->newShare(); - - $node = $this->getMockBuilder(File::class)->getMock(); - $node->method('getId')->willReturn(42); - $node->method('getName')->willReturn('myFile'); - - $share->setSharedWith('user@server.com') - ->setSharedBy('sharedBy') - ->setShareOwner('shareOwner') - ->setPermissions(19) - ->setShareType(IShare::TYPE_REMOTE) - ->setNode($node); - - $this->tokenHandler->method('generateToken')->willReturn('token'); - - $this->addressHandler->expects($this->any())->method('generateRemoteURL') - ->willReturn('http://localhost/'); - $this->addressHandler->expects($this->any())->method('splitUserRemote') - ->willReturn(['user', 'server.com']); - - $this->notifications->expects($this->once()) - ->method('sendRemoteShare') - ->with( - $this->equalTo('token'), - $this->equalTo('user@server.com'), - $this->equalTo('myFile'), - $this->anything(), - 'shareOwner', - 'shareOwner@http://localhost', - 'sharedBy', - 'sharedBy@http://localhost' - )->willReturn(false); - - $this->rootFolder->method('getById') - ->with('42') - ->willReturn([$node]); - - $this->contactsManager->expects($this->any()) - ->method('search') - ->willReturn([]); - - try { - $share = $this->provider->create($share); - $this->fail(); - } catch (\Exception $e) { - $this->assertEquals('Sharing myFile failed, could not find user@server.com, maybe the server is currently unreachable or uses a self-signed certificate.', $e->getMessage()); - } - - $qb = $this->connection->getQueryBuilder(); - $stmt = $qb->select('*') - ->from('share') - ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) - ->execute(); - - $data = $stmt->fetch(); - $stmt->closeCursor(); - - $this->assertFalse($data); - } - - public function testCreateException(): void { - $share = $this->shareManager->newShare(); - - $node = $this->getMockBuilder(File::class)->getMock(); - $node->method('getId')->willReturn(42); - $node->method('getName')->willReturn('myFile'); - - $share->setSharedWith('user@server.com') - ->setSharedBy('sharedBy') - ->setShareOwner('shareOwner') - ->setPermissions(19) - ->setShareType(IShare::TYPE_REMOTE) - ->setNode($node); - - $this->tokenHandler->method('generateToken')->willReturn('token'); - - $this->addressHandler->expects($this->any())->method('generateRemoteURL') - ->willReturn('http://localhost/'); - $this->addressHandler->expects($this->any())->method('splitUserRemote') - ->willReturn(['user', 'server.com']); - - $this->notifications->expects($this->once()) - ->method('sendRemoteShare') - ->with( - $this->equalTo('token'), - $this->equalTo('user@server.com'), - $this->equalTo('myFile'), - $this->anything(), - 'shareOwner', - 'shareOwner@http://localhost', - 'sharedBy', - 'sharedBy@http://localhost' - )->willThrowException(new \Exception('dummy')); - - $this->rootFolder->method('getById') - ->with('42') - ->willReturn([$node]); - - $this->contactsManager->expects($this->any()) - ->method('search') - ->willReturn([]); - - try { - $share = $this->provider->create($share); - $this->fail(); - } catch (\Exception $e) { - $this->assertEquals('Sharing myFile failed, could not find user@server.com, maybe the server is currently unreachable or uses a self-signed certificate.', $e->getMessage()); - } - - $qb = $this->connection->getQueryBuilder(); - $stmt = $qb->select('*') - ->from('share') - ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) - ->execute(); - - $data = $stmt->fetch(); - $stmt->closeCursor(); - - $this->assertFalse($data); - } - - public function testCreateShareWithSelf(): void { - $share = $this->shareManager->newShare(); - - $node = $this->getMockBuilder(File::class)->getMock(); - $node->method('getId')->willReturn(42); - $node->method('getName')->willReturn('myFile'); - - $this->addressHandler->expects($this->any())->method('compareAddresses') - ->willReturn(true); - - $shareWith = 'sharedBy@localhost'; - - $share->setSharedWith($shareWith) - ->setSharedBy('sharedBy') - ->setShareOwner('shareOwner') - ->setPermissions(19) - ->setNode($node); - - $this->contactsManager->expects($this->any()) - ->method('search') - ->willReturn([]); - - $this->rootFolder->expects($this->never())->method($this->anything()); - - try { - $share = $this->provider->create($share); - $this->fail(); - } catch (\Exception $e) { - $this->assertEquals('Not allowed to create a federated share to the same account', $e->getMessage()); - } - - $qb = $this->connection->getQueryBuilder(); - $stmt = $qb->select('*') - ->from('share') - ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) - ->execute(); - - $data = $stmt->fetch(); - $stmt->closeCursor(); - - $this->assertFalse($data); - } - - public function testCreateAlreadyShared(): void { - $share = $this->shareManager->newShare(); - - $node = $this->getMockBuilder(File::class)->getMock(); - $node->method('getId')->willReturn(42); - $node->method('getName')->willReturn('myFile'); - - - $this->addressHandler->expects($this->any())->method('splitUserRemote') - ->willReturn(['user', 'server.com']); - - $share->setSharedWith('user@server.com') - ->setSharedBy('sharedBy') - ->setShareOwner('shareOwner') - ->setPermissions(19) - ->setShareType(IShare::TYPE_REMOTE) - ->setNode($node); - - $this->tokenHandler->method('generateToken')->willReturn('token'); - - $this->addressHandler->expects($this->any())->method('generateRemoteURL') - ->willReturn('http://localhost/'); - - $this->notifications->expects($this->once()) - ->method('sendRemoteShare') - ->with( - $this->equalTo('token'), - $this->equalTo('user@server.com'), - $this->equalTo('myFile'), - $this->anything(), - 'shareOwner', - 'shareOwner@http://localhost', - 'sharedBy', - 'sharedBy@http://localhost' - )->willReturn(true); - - $this->rootFolder->expects($this->never())->method($this->anything()); - - $this->contactsManager->expects($this->any()) - ->method('search') - ->willReturn([]); - - $this->provider->create($share); - - try { - $this->provider->create($share); - } catch (\Exception $e) { - $this->assertEquals('Sharing myFile failed, because this item is already shared with the account user@server.com', $e->getMessage()); - } - } - - /** - * @dataProvider dataTestUpdate - */ - public function testUpdate($owner, $sharedBy, $expirationDate): void { - $this->provider = $this->getMockBuilder('OCA\FederatedFileSharing\FederatedShareProvider') - ->setConstructorArgs( - [ - $this->connection, - $this->addressHandler, - $this->notifications, - $this->tokenHandler, - $this->l, - $this->rootFolder, - $this->config, - $this->userManager, - $this->cloudIdManager, - $this->gsConfig, - $this->cloudFederationProviderManager, - $this->logger, - ] - )->setMethods(['sendPermissionUpdate'])->getMock(); - - $share = $this->shareManager->newShare(); - - $node = $this->getMockBuilder(File::class)->getMock(); - $node->method('getId')->willReturn(42); - $node->method('getName')->willReturn('myFile'); - - $this->addressHandler->expects($this->any())->method('splitUserRemote') - ->willReturn(['user', 'server.com']); - - $share->setSharedWith('user@server.com') - ->setSharedBy($sharedBy) - ->setShareOwner($owner) - ->setPermissions(19) - ->setShareType(IShare::TYPE_REMOTE) - ->setExpirationDate(new \DateTime('2019-02-01T01:02:03')) - ->setNode($node); - - $this->tokenHandler->method('generateToken')->willReturn('token'); - $this->addressHandler->expects($this->any())->method('generateRemoteURL') - ->willReturn('http://localhost/'); - - $this->notifications->expects($this->once()) - ->method('sendRemoteShare') - ->with( - $this->equalTo('token'), - $this->equalTo('user@server.com'), - $this->equalTo('myFile'), - $this->anything(), - $owner, - $owner . '@http://localhost', - $sharedBy, - $sharedBy . '@http://localhost' - )->willReturn(true); - - if ($owner === $sharedBy) { - $this->provider->expects($this->never())->method('sendPermissionUpdate'); - } else { - $this->provider->expects($this->once())->method('sendPermissionUpdate'); - } - - $this->rootFolder->expects($this->never())->method($this->anything()); - - $this->contactsManager->expects($this->any()) - ->method('search') - ->willReturn([]); - - $share = $this->provider->create($share); - - $share->setPermissions(1); - $share->setExpirationDate($expirationDate); - $this->provider->update($share); - - $share = $this->provider->getShareById($share->getId()); - - $this->assertEquals(1, $share->getPermissions()); - $this->assertEquals($expirationDate, $share->getExpirationDate()); - } - - public function dataTestUpdate() { - return [ - ['sharedBy', 'shareOwner', new \DateTime('2020-03-01T01:02:03')], - ['shareOwner', 'shareOwner', null], - ]; - } - - public function testGetSharedBy(): void { - $node = $this->getMockBuilder(File::class)->getMock(); - $node->method('getId')->willReturn(42); - $node->method('getName')->willReturn('myFile'); - - $this->addressHandler->expects($this->never())->method('splitUserRemote'); - - $this->addressHandler->method('generateRemoteURL') - ->willReturn('remoteurl.com'); - - $this->tokenHandler->method('generateToken')->willReturn('token'); - $this->notifications - ->method('sendRemoteShare') - ->willReturn(true); - - $this->rootFolder->expects($this->never())->method($this->anything()); - - $this->contactsManager->expects($this->any()) - ->method('search') - ->willReturn([]); - - $share = $this->shareManager->newShare(); - $share->setSharedWith('user@server.com') - ->setSharedBy('sharedBy') - ->setShareOwner('shareOwner') - ->setPermissions(19) - ->setShareType(IShare::TYPE_REMOTE) - ->setNode($node); - $this->provider->create($share); - - $share2 = $this->shareManager->newShare(); - $share2->setSharedWith('user2@server.com') - ->setSharedBy('sharedBy2') - ->setShareOwner('shareOwner') - ->setPermissions(19) - ->setShareType(IShare::TYPE_REMOTE) - ->setNode($node); - $this->provider->create($share2); - - $shares = $this->provider->getSharesBy('sharedBy', IShare::TYPE_REMOTE, null, false, -1, 0); - - $this->assertCount(1, $shares); - $this->assertEquals('user@server.com', $shares[0]->getSharedWith()); - $this->assertEquals('sharedBy', $shares[0]->getSharedBy()); - } - - public function testGetSharedByWithNode(): void { - $node = $this->getMockBuilder(File::class)->getMock(); - $node->method('getId')->willReturn(42); - $node->method('getName')->willReturn('myFile'); - - $this->tokenHandler->method('generateToken')->willReturn('token'); - $this->notifications - ->method('sendRemoteShare') - ->willReturn(true); - - $this->rootFolder->expects($this->never())->method($this->anything()); - - $this->addressHandler->method('generateRemoteURL') - ->willReturn('remoteurl.com'); - - $this->contactsManager->expects($this->any()) - ->method('search') - ->willReturn([]); - - $share = $this->shareManager->newShare(); - $share->setSharedWith('user@server.com') - ->setSharedBy('sharedBy') - ->setShareOwner('shareOwner') - ->setPermissions(19) - ->setShareType(IShare::TYPE_REMOTE) - ->setNode($node); - $this->provider->create($share); - - $node2 = $this->getMockBuilder(File::class)->getMock(); - $node2->method('getId')->willReturn(43); - $node2->method('getName')->willReturn('myOtherFile'); - - $share2 = $this->shareManager->newShare(); - $share2->setSharedWith('user@server.com') - ->setSharedBy('sharedBy') - ->setShareOwner('shareOwner') - ->setPermissions(19) - ->setShareType(IShare::TYPE_REMOTE) - ->setNode($node2); - $this->provider->create($share2); - - $shares = $this->provider->getSharesBy('sharedBy', IShare::TYPE_REMOTE, $node2, false, -1, 0); - - $this->assertCount(1, $shares); - $this->assertEquals(43, $shares[0]->getNodeId()); - } - - public function testGetSharedByWithReshares(): void { - $node = $this->getMockBuilder(File::class)->getMock(); - $node->method('getId')->willReturn(42); - $node->method('getName')->willReturn('myFile'); - - $this->tokenHandler->method('generateToken')->willReturn('token'); - $this->notifications - ->method('sendRemoteShare') - ->willReturn(true); - - $this->rootFolder->expects($this->never())->method($this->anything()); - - $this->addressHandler->method('generateRemoteURL') - ->willReturn('remoteurl.com'); - - $this->contactsManager->expects($this->any()) - ->method('search') - ->willReturn([]); - - $share = $this->shareManager->newShare(); - $share->setSharedWith('user@server.com') - ->setSharedBy('shareOwner') - ->setShareOwner('shareOwner') - ->setPermissions(19) - ->setShareType(IShare::TYPE_REMOTE) - ->setNode($node); - $this->provider->create($share); - - $share2 = $this->shareManager->newShare(); - $share2->setSharedWith('user2@server.com') - ->setSharedBy('sharedBy') - ->setShareOwner('shareOwner') - ->setPermissions(19) - ->setShareType(IShare::TYPE_REMOTE) - ->setNode($node); - $this->provider->create($share2); - - $shares = $this->provider->getSharesBy('shareOwner', IShare::TYPE_REMOTE, null, true, -1, 0); - - $this->assertCount(2, $shares); - } - - public function testGetSharedByWithLimit(): void { - $node = $this->getMockBuilder(File::class)->getMock(); - $node->method('getId')->willReturn(42); - $node->method('getName')->willReturn('myFile'); - - $this->addressHandler->expects($this->any())->method('splitUserRemote') - ->willReturnCallback(function ($uid) { - if ($uid === 'user@server.com') { - return ['user', 'server.com']; - } - return ['user2', 'server.com']; - }); - - $this->tokenHandler->method('generateToken')->willReturn('token'); - $this->notifications - ->method('sendRemoteShare') - ->willReturn(true); - - $this->rootFolder->expects($this->never())->method($this->anything()); - - $this->addressHandler->method('generateRemoteURL') - ->willReturn('remoteurl.com'); - - $this->contactsManager->expects($this->any()) - ->method('search') - ->willReturn([]); - - $share = $this->shareManager->newShare(); - $share->setSharedWith('user@server.com') - ->setSharedBy('sharedBy') - ->setShareOwner('shareOwner') - ->setPermissions(19) - ->setShareType(IShare::TYPE_REMOTE) - ->setNode($node); - $this->provider->create($share); - - $share2 = $this->shareManager->newShare(); - $share2->setSharedWith('user2@server.com') - ->setSharedBy('sharedBy') - ->setShareOwner('shareOwner') - ->setPermissions(19) - ->setShareType(IShare::TYPE_REMOTE) - ->setNode($node); - $this->provider->create($share2); - - $shares = $this->provider->getSharesBy('shareOwner', IShare::TYPE_REMOTE, null, true, 1, 1); - - $this->assertCount(1, $shares); - $this->assertEquals('user2@server.com', $shares[0]->getSharedWith()); - } - - public function dataDeleteUser() { - return [ - ['a', 'b', 'c', 'a', true], - ['a', 'b', 'c', 'b', false], - // The recipient is non local. - ['a', 'b', 'c', 'c', false], - ['a', 'b', 'c', 'd', false], - ]; - } - - /** - * @dataProvider dataDeleteUser - * - * @param string $owner The owner of the share (uid) - * @param string $initiator The initiator of the share (uid) - * @param string $recipient The recipient of the share (uid/gid/pass) - * @param string $deletedUser The user that is deleted - * @param bool $rowDeleted Is the row deleted in this setup - */ - public function testDeleteUser($owner, $initiator, $recipient, $deletedUser, $rowDeleted): void { - $qb = $this->connection->getQueryBuilder(); - $qb->insert('share') - ->setValue('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE)) - ->setValue('uid_owner', $qb->createNamedParameter($owner)) - ->setValue('uid_initiator', $qb->createNamedParameter($initiator)) - ->setValue('share_with', $qb->createNamedParameter($recipient)) - ->setValue('item_type', $qb->createNamedParameter('file')) - ->setValue('item_source', $qb->createNamedParameter(42)) - ->setValue('file_source', $qb->createNamedParameter(42)) - ->execute(); - - $id = $qb->getLastInsertId(); - - $this->provider->userDeleted($deletedUser, IShare::TYPE_REMOTE); - - $qb = $this->connection->getQueryBuilder(); - $qb->select('*') - ->from('share') - ->where( - $qb->expr()->eq('id', $qb->createNamedParameter($id)) - ); - $cursor = $qb->execute(); - $data = $cursor->fetchAll(); - $cursor->closeCursor(); - - $this->assertCount($rowDeleted ? 0 : 1, $data); - } - - /** - * @dataProvider dataTestIsOutgoingServer2serverShareEnabled - * - * @param string $isEnabled - * @param bool $expected - */ - public function testIsOutgoingServer2serverShareEnabled($internalOnly, $isEnabled, $expected): void { - $this->gsConfig->expects($this->once())->method('onlyInternalFederation') - ->willReturn($internalOnly); - $this->config->expects($this->any())->method('getAppValue') - ->with('files_sharing', 'outgoing_server2server_share_enabled', 'yes') - ->willReturn($isEnabled); - - $this->assertSame($expected, - $this->provider->isOutgoingServer2serverShareEnabled() - ); - } - - public function dataTestIsOutgoingServer2serverShareEnabled() { - return [ - [false, 'yes', true], - [false, 'no', false], - [true, 'yes', false], - [true, 'no', false], - ]; - } - - /** - * @dataProvider dataTestIsIncomingServer2serverShareEnabled - * - * @param string $isEnabled - * @param bool $expected - */ - public function testIsIncomingServer2serverShareEnabled($onlyInternal, $isEnabled, $expected): void { - $this->gsConfig->expects($this->once())->method('onlyInternalFederation') - ->willReturn($onlyInternal); - $this->config->expects($this->any())->method('getAppValue') - ->with('files_sharing', 'incoming_server2server_share_enabled', 'yes') - ->willReturn($isEnabled); - - $this->assertSame($expected, - $this->provider->isIncomingServer2serverShareEnabled() - ); - } - - public function dataTestIsIncomingServer2serverShareEnabled() { - return [ - [false, 'yes', true], - [false, 'no', false], - [true, 'yes', false], - [true, 'no', false], - ]; - } - - /** - * @dataProvider dataTestIsLookupServerQueriesEnabled - * - * @param string $isEnabled - * @param bool $expected - */ - public function testIsLookupServerQueriesEnabled($gsEnabled, $isEnabled, $expected): void { - $this->gsConfig->expects($this->once())->method('isGlobalScaleEnabled') - ->willReturn($gsEnabled); - $this->config->expects($this->any())->method('getAppValue') - ->with('files_sharing', 'lookupServerEnabled', 'yes') - ->willReturn($isEnabled); - - $this->assertSame($expected, - $this->provider->isLookupServerQueriesEnabled() - ); - } - - - public function dataTestIsLookupServerQueriesEnabled() { - return [ - [false, 'yes', true], - [false, 'no', false], - [true, 'yes', true], - [true, 'no', true], - ]; - } - - /** - * @dataProvider dataTestIsLookupServerUploadEnabled - * - * @param string $isEnabled - * @param bool $expected - */ - public function testIsLookupServerUploadEnabled($gsEnabled, $isEnabled, $expected): void { - $this->gsConfig->expects($this->once())->method('isGlobalScaleEnabled') - ->willReturn($gsEnabled); - $this->config->expects($this->any())->method('getAppValue') - ->with('files_sharing', 'lookupServerUploadEnabled', 'yes') - ->willReturn($isEnabled); - - $this->assertSame($expected, - $this->provider->isLookupServerUploadEnabled() - ); - } - - public function dataTestIsLookupServerUploadEnabled() { - return [ - [false, 'yes', true], - [false, 'no', false], - [true, 'yes', false], - [true, 'no', false], - ]; - } - - public function testGetSharesInFolder(): void { - $userManager = \OC::$server->getUserManager(); - $rootFolder = \OC::$server->getRootFolder(); - - $u1 = $userManager->createUser('testFed', md5(time())); - $u2 = $userManager->createUser('testFed2', md5(time())); - - $folder1 = $rootFolder->getUserFolder($u1->getUID())->newFolder('foo'); - $file1 = $folder1->newFile('bar1'); - $file2 = $folder1->newFile('bar2'); - - $this->tokenHandler->method('generateToken')->willReturn('token'); - $this->notifications - ->method('sendRemoteShare') - ->willReturn(true); - - $this->addressHandler->method('generateRemoteURL') - ->willReturn('remoteurl.com'); - - $this->contactsManager->expects($this->any()) - ->method('search') - ->willReturn([]); - - $share1 = $this->shareManager->newShare(); - $share1->setSharedWith('user@server.com') - ->setSharedBy($u1->getUID()) - ->setShareOwner($u1->getUID()) - ->setPermissions(\OCP\Constants::PERMISSION_READ) - ->setShareType(IShare::TYPE_REMOTE) - ->setNode($file1); - $this->provider->create($share1); - - $share2 = $this->shareManager->newShare(); - $share2->setSharedWith('user@server.com') - ->setSharedBy($u2->getUID()) - ->setShareOwner($u1->getUID()) - ->setPermissions(\OCP\Constants::PERMISSION_READ) - ->setShareType(IShare::TYPE_REMOTE) - ->setNode($file2); - $this->provider->create($share2); - - $result = $this->provider->getSharesInFolder($u1->getUID(), $folder1, false); - $this->assertCount(1, $result); - $this->assertCount(1, $result[$file1->getId()]); - - $result = $this->provider->getSharesInFolder($u1->getUID(), $folder1, true); - $this->assertCount(2, $result); - $this->assertCount(1, $result[$file1->getId()]); - $this->assertCount(1, $result[$file2->getId()]); - - $u1->delete(); - $u2->delete(); - } - - public function testGetAccessList(): void { - $userManager = \OC::$server->getUserManager(); - $rootFolder = \OC::$server->getRootFolder(); - - $u1 = $userManager->createUser('testFed', md5(time())); - - $folder1 = $rootFolder->getUserFolder($u1->getUID())->newFolder('foo'); - $file1 = $folder1->newFile('bar1'); - - $this->tokenHandler->expects($this->exactly(2)) - ->method('generateToken') - ->willReturnOnConsecutiveCalls('token1', 'token2'); - $this->notifications->expects($this->atLeastOnce()) - ->method('sendRemoteShare') - ->willReturn(true); - - $this->contactsManager->expects($this->any()) - ->method('search') - ->willReturn([]); - - $result = $this->provider->getAccessList([$file1], true); - $this->assertEquals(['remote' => []], $result); - - $result = $this->provider->getAccessList([$file1], false); - $this->assertEquals(['remote' => false], $result); - - $this->addressHandler->method('generateRemoteURL') - ->willReturn('remoteurl.com'); - - $share1 = $this->shareManager->newShare(); - $share1->setSharedWith('user@server.com') - ->setSharedBy($u1->getUID()) - ->setShareOwner($u1->getUID()) - ->setPermissions(\OCP\Constants::PERMISSION_READ) - ->setShareType(IShare::TYPE_REMOTE) - ->setNode($file1); - $this->provider->create($share1); - - $share2 = $this->shareManager->newShare(); - $share2->setSharedWith('foobar@localhost') - ->setSharedBy($u1->getUID()) - ->setShareOwner($u1->getUID()) - ->setPermissions(\OCP\Constants::PERMISSION_READ) - ->setShareType(IShare::TYPE_REMOTE) - ->setNode($file1); - $this->provider->create($share2); - - $result = $this->provider->getAccessList([$file1], true); - $this->assertEquals(['remote' => [ - 'user@server.com' => [ - 'token' => 'token1', - 'node_id' => $file1->getId(), - ], - 'foobar@localhost' => [ - 'token' => 'token2', - 'node_id' => $file1->getId(), - ], - ]], $result); - - $result = $this->provider->getAccessList([$file1], false); - $this->assertEquals(['remote' => true], $result); - - $u1->delete(); - } -} +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\FederatedFileSharing\Tests; + +use OC\Federation\CloudIdManager; +use OCA\FederatedFileSharing\AddressHandler; +use OCA\FederatedFileSharing\FederatedShareProvider; +use OCA\FederatedFileSharing\Notifications; +use OCA\FederatedFileSharing\TokenHandler; +use OCP\Contacts\IManager as IContactsManager; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Federation\ICloudFederationProviderManager; +use OCP\Federation\ICloudIdManager; +use OCP\Files\File; +use OCP\Files\IRootFolder; +use OCP\ICacheFactory; +use OCP\IConfig; +use OCP\IDBConnection; +use OCP\IL10N; +use OCP\IURLGenerator; +use OCP\IUserManager; +use OCP\Share\IManager; +use OCP\Share\IShare; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; + +/** + * Class FederatedShareProviderTest + * + * @package OCA\FederatedFileSharing\Tests + * @group DB + */ +class FederatedShareProviderTest extends \Test\TestCase { + /** @var IDBConnection */ + protected $connection; + /** @var AddressHandler|MockObject */ + protected $addressHandler; + /** @var Notifications|MockObject */ + protected $notifications; + /** @var TokenHandler|MockObject */ + protected $tokenHandler; + /** @var IL10N */ + protected $l; + /** @var LoggerInterface */ + protected $logger; + /** @var IRootFolder|MockObject */ + protected $rootFolder; + /** @var IConfig|MockObject */ + protected $config; + /** @var IUserManager|MockObject */ + protected $userManager; + /** @var \OCP\GlobalScale\IConfig|MockObject */ + protected $gsConfig; + + /** @var IManager */ + protected $shareManager; + /** @var FederatedShareProvider */ + protected $provider; + /** @var IContactsManager|MockObject */ + protected $contactsManager; + + /** @var ICloudIdManager */ + private $cloudIdManager; + + /** @var MockObject|ICloudFederationProviderManager */ + private $cloudFederationProviderManager; + + protected function setUp(): void { + parent::setUp(); + + $this->connection = \OC::$server->getDatabaseConnection(); + $this->notifications = $this->getMockBuilder(\OCA\FederatedFileSharing\Notifications::class) + ->disableOriginalConstructor() + ->getMock(); + $this->tokenHandler = $this->getMockBuilder(\OCA\FederatedFileSharing\TokenHandler::class) + ->disableOriginalConstructor() + ->getMock(); + $this->l = $this->getMockBuilder(IL10N::class)->getMock(); + $this->l->method('t') + ->willReturnCallback(function ($text, $parameters = []) { + return vsprintf($text, $parameters); + }); + $this->logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); + $this->rootFolder = $this->getMockBuilder(\OCP\Files\IRootFolder::class)->getMock(); + $this->config = $this->getMockBuilder(IConfig::class)->getMock(); + $this->userManager = $this->getMockBuilder(IUserManager::class)->getMock(); + //$this->addressHandler = new AddressHandler(\OC::$server->getURLGenerator(), $this->l); + $this->addressHandler = $this->getMockBuilder(\OCA\FederatedFileSharing\AddressHandler::class)->disableOriginalConstructor()->getMock(); + $this->contactsManager = $this->createMock(IContactsManager::class); + $this->cloudIdManager = new CloudIdManager( + $this->contactsManager, + $this->createMock(IURLGenerator::class), + $this->userManager, + $this->createMock(ICacheFactory::class), + $this->createMock(IEventDispatcher::class) + ); + $this->gsConfig = $this->createMock(\OCP\GlobalScale\IConfig::class); + + $this->userManager->expects($this->any())->method('userExists')->willReturn(true); + + $this->cloudFederationProviderManager = $this->createMock(ICloudFederationProviderManager::class); + + $this->provider = new FederatedShareProvider( + $this->connection, + $this->addressHandler, + $this->notifications, + $this->tokenHandler, + $this->l, + $this->rootFolder, + $this->config, + $this->userManager, + $this->cloudIdManager, + $this->gsConfig, + $this->cloudFederationProviderManager, + $this->logger, + ); + + $this->shareManager = \OC::$server->getShareManager(); + } + + protected function tearDown(): void { + $this->connection->getQueryBuilder()->delete('share')->execute(); + + parent::tearDown(); + } + + public function dataTestCreate() { + return [ + [null, null], + [new \DateTime('2020-03-01T01:02:03'), '2020-03-01 01:02:03'], + ]; + } + + /** + * @dataProvider dataTestCreate + */ + public function testCreate($expirationDate, $expectedDataDate): void { + $share = $this->shareManager->newShare(); + + /** @var File|MockObject $node */ + $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(42); + $node->method('getName')->willReturn('myFile'); + + $share->setSharedWith('user@server.com') + ->setSharedBy('sharedBy') + ->setShareOwner('shareOwner') + ->setPermissions(19) + ->setShareType(IShare::TYPE_REMOTE) + ->setExpirationDate($expirationDate) + ->setNode($node); + + $this->tokenHandler->method('generateToken')->willReturn('token'); + + $this->addressHandler->expects($this->any())->method('generateRemoteURL') + ->willReturn('http://localhost/'); + $this->addressHandler->expects($this->any())->method('splitUserRemote') + ->willReturn(['user', 'server.com']); + + $this->notifications->expects($this->once()) + ->method('sendRemoteShare') + ->with( + $this->equalTo('token'), + $this->equalTo('user@server.com'), + $this->equalTo('myFile'), + $this->anything(), + 'shareOwner', + 'shareOwner@http://localhost', + 'sharedBy', + 'sharedBy@http://localhost' + ) + ->willReturn(true); + + $this->rootFolder->expects($this->never())->method($this->anything()); + + $this->contactsManager->expects($this->any()) + ->method('search') + ->willReturn([]); + + $share = $this->provider->create($share); + + $qb = $this->connection->getQueryBuilder(); + $stmt = $qb->select('*') + ->from('share') + ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) + ->execute(); + + $data = $stmt->fetch(); + $stmt->closeCursor(); + + $expected = [ + 'share_type' => IShare::TYPE_REMOTE, + 'share_with' => 'user@server.com', + 'uid_owner' => 'shareOwner', + 'uid_initiator' => 'sharedBy', + 'item_type' => 'file', + 'item_source' => 42, + 'file_source' => 42, + 'permissions' => 19, + 'accepted' => 0, + 'token' => 'token', + 'expiration' => $expectedDataDate, + ]; + foreach (array_keys($expected) as $key) { + $this->assertEquals($expected[$key], $data[$key], "Assert that value for key '$key' is the same"); + } + + $this->assertEquals($data['id'], $share->getId()); + $this->assertEquals(IShare::TYPE_REMOTE, $share->getShareType()); + $this->assertEquals('user@server.com', $share->getSharedWith()); + $this->assertEquals('sharedBy', $share->getSharedBy()); + $this->assertEquals('shareOwner', $share->getShareOwner()); + $this->assertEquals('file', $share->getNodeType()); + $this->assertEquals(42, $share->getNodeId()); + $this->assertEquals(19, $share->getPermissions()); + $this->assertEquals('token', $share->getToken()); + $this->assertEquals($expirationDate, $share->getExpirationDate()); + } + + public function testCreateCouldNotFindServer(): void { + $share = $this->shareManager->newShare(); + + $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(42); + $node->method('getName')->willReturn('myFile'); + + $share->setSharedWith('user@server.com') + ->setSharedBy('sharedBy') + ->setShareOwner('shareOwner') + ->setPermissions(19) + ->setShareType(IShare::TYPE_REMOTE) + ->setNode($node); + + $this->tokenHandler->method('generateToken')->willReturn('token'); + + $this->addressHandler->expects($this->any())->method('generateRemoteURL') + ->willReturn('http://localhost/'); + $this->addressHandler->expects($this->any())->method('splitUserRemote') + ->willReturn(['user', 'server.com']); + + $this->notifications->expects($this->once()) + ->method('sendRemoteShare') + ->with( + $this->equalTo('token'), + $this->equalTo('user@server.com'), + $this->equalTo('myFile'), + $this->anything(), + 'shareOwner', + 'shareOwner@http://localhost', + 'sharedBy', + 'sharedBy@http://localhost' + )->willReturn(false); + + $this->rootFolder->method('getById') + ->with('42') + ->willReturn([$node]); + + $this->contactsManager->expects($this->any()) + ->method('search') + ->willReturn([]); + + try { + $share = $this->provider->create($share); + $this->fail(); + } catch (\Exception $e) { + $this->assertEquals('Sharing myFile failed, could not find user@server.com, maybe the server is currently unreachable or uses a self-signed certificate.', $e->getMessage()); + } + + $qb = $this->connection->getQueryBuilder(); + $stmt = $qb->select('*') + ->from('share') + ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) + ->execute(); + + $data = $stmt->fetch(); + $stmt->closeCursor(); + + $this->assertFalse($data); + } + + public function testCreateException(): void { + $share = $this->shareManager->newShare(); + + $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(42); + $node->method('getName')->willReturn('myFile'); + + $share->setSharedWith('user@server.com') + ->setSharedBy('sharedBy') + ->setShareOwner('shareOwner') + ->setPermissions(19) + ->setShareType(IShare::TYPE_REMOTE) + ->setNode($node); + + $this->tokenHandler->method('generateToken')->willReturn('token'); + + $this->addressHandler->expects($this->any())->method('generateRemoteURL') + ->willReturn('http://localhost/'); + $this->addressHandler->expects($this->any())->method('splitUserRemote') + ->willReturn(['user', 'server.com']); + + $this->notifications->expects($this->once()) + ->method('sendRemoteShare') + ->with( + $this->equalTo('token'), + $this->equalTo('user@server.com'), + $this->equalTo('myFile'), + $this->anything(), + 'shareOwner', + 'shareOwner@http://localhost', + 'sharedBy', + 'sharedBy@http://localhost' + )->willThrowException(new \Exception('dummy')); + + $this->rootFolder->method('getById') + ->with('42') + ->willReturn([$node]); + + $this->contactsManager->expects($this->any()) + ->method('search') + ->willReturn([]); + + try { + $share = $this->provider->create($share); + $this->fail(); + } catch (\Exception $e) { + $this->assertEquals('Sharing myFile failed, could not find user@server.com, maybe the server is currently unreachable or uses a self-signed certificate.', $e->getMessage()); + } + + $qb = $this->connection->getQueryBuilder(); + $stmt = $qb->select('*') + ->from('share') + ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) + ->execute(); + + $data = $stmt->fetch(); + $stmt->closeCursor(); + + $this->assertFalse($data); + } + + public function testCreateShareWithSelf(): void { + $share = $this->shareManager->newShare(); + + $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(42); + $node->method('getName')->willReturn('myFile'); + + $this->addressHandler->expects($this->any())->method('compareAddresses') + ->willReturn(true); + + $shareWith = 'sharedBy@localhost'; + + $share->setSharedWith($shareWith) + ->setSharedBy('sharedBy') + ->setShareOwner('shareOwner') + ->setPermissions(19) + ->setNode($node); + + $this->contactsManager->expects($this->any()) + ->method('search') + ->willReturn([]); + + $this->rootFolder->expects($this->never())->method($this->anything()); + + try { + $share = $this->provider->create($share); + $this->fail(); + } catch (\Exception $e) { + $this->assertEquals('Not allowed to create a federated share to the same account', $e->getMessage()); + } + + $qb = $this->connection->getQueryBuilder(); + $stmt = $qb->select('*') + ->from('share') + ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) + ->execute(); + + $data = $stmt->fetch(); + $stmt->closeCursor(); + + $this->assertFalse($data); + } + + public function testCreateAlreadyShared(): void { + $share = $this->shareManager->newShare(); + + $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(42); + $node->method('getName')->willReturn('myFile'); + + + $this->addressHandler->expects($this->any())->method('splitUserRemote') + ->willReturn(['user', 'server.com']); + + $share->setSharedWith('user@server.com') + ->setSharedBy('sharedBy') + ->setShareOwner('shareOwner') + ->setPermissions(19) + ->setShareType(IShare::TYPE_REMOTE) + ->setNode($node); + + $this->tokenHandler->method('generateToken')->willReturn('token'); + + $this->addressHandler->expects($this->any())->method('generateRemoteURL') + ->willReturn('http://localhost/'); + + $this->notifications->expects($this->once()) + ->method('sendRemoteShare') + ->with( + $this->equalTo('token'), + $this->equalTo('user@server.com'), + $this->equalTo('myFile'), + $this->anything(), + 'shareOwner', + 'shareOwner@http://localhost', + 'sharedBy', + 'sharedBy@http://localhost' + )->willReturn(true); + + $this->rootFolder->expects($this->never())->method($this->anything()); + + $this->contactsManager->expects($this->any()) + ->method('search') + ->willReturn([]); + + $this->provider->create($share); + + try { + $this->provider->create($share); + } catch (\Exception $e) { + $this->assertEquals('Sharing myFile failed, because this item is already shared with the account user@server.com', $e->getMessage()); + } + } + + /** + * @dataProvider dataTestUpdate + */ + public function testUpdate($owner, $sharedBy, $expirationDate): void { + $this->provider = $this->getMockBuilder(\OCA\FederatedFileSharing\FederatedShareProvider::class) + ->setConstructorArgs( + [ + $this->connection, + $this->addressHandler, + $this->notifications, + $this->tokenHandler, + $this->l, + $this->rootFolder, + $this->config, + $this->userManager, + $this->cloudIdManager, + $this->gsConfig, + $this->cloudFederationProviderManager, + $this->logger, + ] + )->setMethods(['sendPermissionUpdate'])->getMock(); + + $share = $this->shareManager->newShare(); + + $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(42); + $node->method('getName')->willReturn('myFile'); + + $this->addressHandler->expects($this->any())->method('splitUserRemote') + ->willReturn(['user', 'server.com']); + + $share->setSharedWith('user@server.com') + ->setSharedBy($sharedBy) + ->setShareOwner($owner) + ->setPermissions(19) + ->setShareType(IShare::TYPE_REMOTE) + ->setExpirationDate(new \DateTime('2019-02-01T01:02:03')) + ->setNode($node); + + $this->tokenHandler->method('generateToken')->willReturn('token'); + $this->addressHandler->expects($this->any())->method('generateRemoteURL') + ->willReturn('http://localhost/'); + + $this->notifications->expects($this->once()) + ->method('sendRemoteShare') + ->with( + $this->equalTo('token'), + $this->equalTo('user@server.com'), + $this->equalTo('myFile'), + $this->anything(), + $owner, + $owner . '@http://localhost', + $sharedBy, + $sharedBy . '@http://localhost' + )->willReturn(true); + + if ($owner === $sharedBy) { + $this->provider->expects($this->never())->method('sendPermissionUpdate'); + } else { + $this->provider->expects($this->once())->method('sendPermissionUpdate'); + } + + $this->rootFolder->expects($this->never())->method($this->anything()); + + $this->contactsManager->expects($this->any()) + ->method('search') + ->willReturn([]); + + $share = $this->provider->create($share); + + $share->setPermissions(1); + $share->setExpirationDate($expirationDate); + $this->provider->update($share); + + $share = $this->provider->getShareById($share->getId()); + + $this->assertEquals(1, $share->getPermissions()); + $this->assertEquals($expirationDate, $share->getExpirationDate()); + } + + public function dataTestUpdate() { + return [ + ['sharedBy', 'shareOwner', new \DateTime('2020-03-01T01:02:03')], + ['shareOwner', 'shareOwner', null], + ]; + } + + public function testGetSharedBy(): void { + $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(42); + $node->method('getName')->willReturn('myFile'); + + $this->addressHandler->expects($this->never())->method('splitUserRemote'); + + $this->addressHandler->method('generateRemoteURL') + ->willReturn('remoteurl.com'); + + $this->tokenHandler->method('generateToken')->willReturn('token'); + $this->notifications + ->method('sendRemoteShare') + ->willReturn(true); + + $this->rootFolder->expects($this->never())->method($this->anything()); + + $this->contactsManager->expects($this->any()) + ->method('search') + ->willReturn([]); + + $share = $this->shareManager->newShare(); + $share->setSharedWith('user@server.com') + ->setSharedBy('sharedBy') + ->setShareOwner('shareOwner') + ->setPermissions(19) + ->setShareType(IShare::TYPE_REMOTE) + ->setNode($node); + $this->provider->create($share); + + $share2 = $this->shareManager->newShare(); + $share2->setSharedWith('user2@server.com') + ->setSharedBy('sharedBy2') + ->setShareOwner('shareOwner') + ->setPermissions(19) + ->setShareType(IShare::TYPE_REMOTE) + ->setNode($node); + $this->provider->create($share2); + + $shares = $this->provider->getSharesBy('sharedBy', IShare::TYPE_REMOTE, null, false, -1, 0); + + $this->assertCount(1, $shares); + $this->assertEquals('user@server.com', $shares[0]->getSharedWith()); + $this->assertEquals('sharedBy', $shares[0]->getSharedBy()); + } + + public function testGetSharedByWithNode(): void { + $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(42); + $node->method('getName')->willReturn('myFile'); + + $this->tokenHandler->method('generateToken')->willReturn('token'); + $this->notifications + ->method('sendRemoteShare') + ->willReturn(true); + + $this->rootFolder->expects($this->never())->method($this->anything()); + + $this->addressHandler->method('generateRemoteURL') + ->willReturn('remoteurl.com'); + + $this->contactsManager->expects($this->any()) + ->method('search') + ->willReturn([]); + + $share = $this->shareManager->newShare(); + $share->setSharedWith('user@server.com') + ->setSharedBy('sharedBy') + ->setShareOwner('shareOwner') + ->setPermissions(19) + ->setShareType(IShare::TYPE_REMOTE) + ->setNode($node); + $this->provider->create($share); + + $node2 = $this->getMockBuilder(File::class)->getMock(); + $node2->method('getId')->willReturn(43); + $node2->method('getName')->willReturn('myOtherFile'); + + $share2 = $this->shareManager->newShare(); + $share2->setSharedWith('user@server.com') + ->setSharedBy('sharedBy') + ->setShareOwner('shareOwner') + ->setPermissions(19) + ->setShareType(IShare::TYPE_REMOTE) + ->setNode($node2); + $this->provider->create($share2); + + $shares = $this->provider->getSharesBy('sharedBy', IShare::TYPE_REMOTE, $node2, false, -1, 0); + + $this->assertCount(1, $shares); + $this->assertEquals(43, $shares[0]->getNodeId()); + } + + public function testGetSharedByWithReshares(): void { + $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(42); + $node->method('getName')->willReturn('myFile'); + + $this->tokenHandler->method('generateToken')->willReturn('token'); + $this->notifications + ->method('sendRemoteShare') + ->willReturn(true); + + $this->rootFolder->expects($this->never())->method($this->anything()); + + $this->addressHandler->method('generateRemoteURL') + ->willReturn('remoteurl.com'); + + $this->contactsManager->expects($this->any()) + ->method('search') + ->willReturn([]); + + $share = $this->shareManager->newShare(); + $share->setSharedWith('user@server.com') + ->setSharedBy('shareOwner') + ->setShareOwner('shareOwner') + ->setPermissions(19) + ->setShareType(IShare::TYPE_REMOTE) + ->setNode($node); + $this->provider->create($share); + + $share2 = $this->shareManager->newShare(); + $share2->setSharedWith('user2@server.com') + ->setSharedBy('sharedBy') + ->setShareOwner('shareOwner') + ->setPermissions(19) + ->setShareType(IShare::TYPE_REMOTE) + ->setNode($node); + $this->provider->create($share2); + + $shares = $this->provider->getSharesBy('shareOwner', IShare::TYPE_REMOTE, null, true, -1, 0); + + $this->assertCount(2, $shares); + } + + public function testGetSharedByWithLimit(): void { + $node = $this->getMockBuilder(File::class)->getMock(); + $node->method('getId')->willReturn(42); + $node->method('getName')->willReturn('myFile'); + + $this->addressHandler->expects($this->any())->method('splitUserRemote') + ->willReturnCallback(function ($uid) { + if ($uid === 'user@server.com') { + return ['user', 'server.com']; + } + return ['user2', 'server.com']; + }); + + $this->tokenHandler->method('generateToken')->willReturn('token'); + $this->notifications + ->method('sendRemoteShare') + ->willReturn(true); + + $this->rootFolder->expects($this->never())->method($this->anything()); + + $this->addressHandler->method('generateRemoteURL') + ->willReturn('remoteurl.com'); + + $this->contactsManager->expects($this->any()) + ->method('search') + ->willReturn([]); + + $share = $this->shareManager->newShare(); + $share->setSharedWith('user@server.com') + ->setSharedBy('sharedBy') + ->setShareOwner('shareOwner') + ->setPermissions(19) + ->setShareType(IShare::TYPE_REMOTE) + ->setNode($node); + $this->provider->create($share); + + $share2 = $this->shareManager->newShare(); + $share2->setSharedWith('user2@server.com') + ->setSharedBy('sharedBy') + ->setShareOwner('shareOwner') + ->setPermissions(19) + ->setShareType(IShare::TYPE_REMOTE) + ->setNode($node); + $this->provider->create($share2); + + $shares = $this->provider->getSharesBy('shareOwner', IShare::TYPE_REMOTE, null, true, 1, 1); + + $this->assertCount(1, $shares); + $this->assertEquals('user2@server.com', $shares[0]->getSharedWith()); + } + + public function dataDeleteUser() { + return [ + ['a', 'b', 'c', 'a', true], + ['a', 'b', 'c', 'b', false], + // The recipient is non local. + ['a', 'b', 'c', 'c', false], + ['a', 'b', 'c', 'd', false], + ]; + } + + /** + * @dataProvider dataDeleteUser + * + * @param string $owner The owner of the share (uid) + * @param string $initiator The initiator of the share (uid) + * @param string $recipient The recipient of the share (uid/gid/pass) + * @param string $deletedUser The user that is deleted + * @param bool $rowDeleted Is the row deleted in this setup + */ + public function testDeleteUser($owner, $initiator, $recipient, $deletedUser, $rowDeleted): void { + $qb = $this->connection->getQueryBuilder(); + $qb->insert('share') + ->setValue('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE)) + ->setValue('uid_owner', $qb->createNamedParameter($owner)) + ->setValue('uid_initiator', $qb->createNamedParameter($initiator)) + ->setValue('share_with', $qb->createNamedParameter($recipient)) + ->setValue('item_type', $qb->createNamedParameter('file')) + ->setValue('item_source', $qb->createNamedParameter(42)) + ->setValue('file_source', $qb->createNamedParameter(42)) + ->execute(); + + $id = $qb->getLastInsertId(); + + $this->provider->userDeleted($deletedUser, IShare::TYPE_REMOTE); + + $qb = $this->connection->getQueryBuilder(); + $qb->select('*') + ->from('share') + ->where( + $qb->expr()->eq('id', $qb->createNamedParameter($id)) + ); + $cursor = $qb->execute(); + $data = $cursor->fetchAll(); + $cursor->closeCursor(); + + $this->assertCount($rowDeleted ? 0 : 1, $data); + } + + /** + * @dataProvider dataTestIsOutgoingServer2serverShareEnabled + * + * @param string $isEnabled + * @param bool $expected + */ + public function testIsOutgoingServer2serverShareEnabled($internalOnly, $isEnabled, $expected): void { + $this->gsConfig->expects($this->once())->method('onlyInternalFederation') + ->willReturn($internalOnly); + $this->config->expects($this->any())->method('getAppValue') + ->with('files_sharing', 'outgoing_server2server_share_enabled', 'yes') + ->willReturn($isEnabled); + + $this->assertSame($expected, + $this->provider->isOutgoingServer2serverShareEnabled() + ); + } + + public function dataTestIsOutgoingServer2serverShareEnabled() { + return [ + [false, 'yes', true], + [false, 'no', false], + [true, 'yes', false], + [true, 'no', false], + ]; + } + + /** + * @dataProvider dataTestIsIncomingServer2serverShareEnabled + * + * @param string $isEnabled + * @param bool $expected + */ + public function testIsIncomingServer2serverShareEnabled($onlyInternal, $isEnabled, $expected): void { + $this->gsConfig->expects($this->once())->method('onlyInternalFederation') + ->willReturn($onlyInternal); + $this->config->expects($this->any())->method('getAppValue') + ->with('files_sharing', 'incoming_server2server_share_enabled', 'yes') + ->willReturn($isEnabled); + + $this->assertSame($expected, + $this->provider->isIncomingServer2serverShareEnabled() + ); + } + + public function dataTestIsIncomingServer2serverShareEnabled() { + return [ + [false, 'yes', true], + [false, 'no', false], + [true, 'yes', false], + [true, 'no', false], + ]; + } + + /** + * @dataProvider dataTestIsLookupServerQueriesEnabled + * + * @param string $isEnabled + * @param bool $expected + */ + public function testIsLookupServerQueriesEnabled($gsEnabled, $isEnabled, $expected): void { + $this->gsConfig->expects($this->once())->method('isGlobalScaleEnabled') + ->willReturn($gsEnabled); + $this->config->expects($this->any())->method('getAppValue') + ->with('files_sharing', 'lookupServerEnabled', 'yes') + ->willReturn($isEnabled); + + $this->assertSame($expected, + $this->provider->isLookupServerQueriesEnabled() + ); + } + + + public function dataTestIsLookupServerQueriesEnabled() { + return [ + [false, 'yes', true], + [false, 'no', false], + [true, 'yes', true], + [true, 'no', true], + ]; + } + + /** + * @dataProvider dataTestIsLookupServerUploadEnabled + * + * @param string $isEnabled + * @param bool $expected + */ + public function testIsLookupServerUploadEnabled($gsEnabled, $isEnabled, $expected): void { + $this->gsConfig->expects($this->once())->method('isGlobalScaleEnabled') + ->willReturn($gsEnabled); + $this->config->expects($this->any())->method('getAppValue') + ->with('files_sharing', 'lookupServerUploadEnabled', 'yes') + ->willReturn($isEnabled); + + $this->assertSame($expected, + $this->provider->isLookupServerUploadEnabled() + ); + } + + public function dataTestIsLookupServerUploadEnabled() { + return [ + [false, 'yes', true], + [false, 'no', false], + [true, 'yes', false], + [true, 'no', false], + ]; + } + + public function testGetSharesInFolder(): void { + $userManager = \OC::$server->getUserManager(); + $rootFolder = \OC::$server->getRootFolder(); + + $u1 = $userManager->createUser('testFed', md5(time())); + $u2 = $userManager->createUser('testFed2', md5(time())); + + $folder1 = $rootFolder->getUserFolder($u1->getUID())->newFolder('foo'); + $file1 = $folder1->newFile('bar1'); + $file2 = $folder1->newFile('bar2'); + + $this->tokenHandler->method('generateToken')->willReturn('token'); + $this->notifications + ->method('sendRemoteShare') + ->willReturn(true); + + $this->addressHandler->method('generateRemoteURL') + ->willReturn('remoteurl.com'); + + $this->contactsManager->expects($this->any()) + ->method('search') + ->willReturn([]); + + $share1 = $this->shareManager->newShare(); + $share1->setSharedWith('user@server.com') + ->setSharedBy($u1->getUID()) + ->setShareOwner($u1->getUID()) + ->setPermissions(\OCP\Constants::PERMISSION_READ) + ->setShareType(IShare::TYPE_REMOTE) + ->setNode($file1); + $this->provider->create($share1); + + $share2 = $this->shareManager->newShare(); + $share2->setSharedWith('user@server.com') + ->setSharedBy($u2->getUID()) + ->setShareOwner($u1->getUID()) + ->setPermissions(\OCP\Constants::PERMISSION_READ) + ->setShareType(IShare::TYPE_REMOTE) + ->setNode($file2); + $this->provider->create($share2); + + $result = $this->provider->getSharesInFolder($u1->getUID(), $folder1, false); + $this->assertCount(1, $result); + $this->assertCount(1, $result[$file1->getId()]); + + $result = $this->provider->getSharesInFolder($u1->getUID(), $folder1, true); + $this->assertCount(2, $result); + $this->assertCount(1, $result[$file1->getId()]); + $this->assertCount(1, $result[$file2->getId()]); + + $u1->delete(); + $u2->delete(); + } + + public function testGetAccessList(): void { + $userManager = \OC::$server->getUserManager(); + $rootFolder = \OC::$server->getRootFolder(); + + $u1 = $userManager->createUser('testFed', md5(time())); + + $folder1 = $rootFolder->getUserFolder($u1->getUID())->newFolder('foo'); + $file1 = $folder1->newFile('bar1'); + + $this->tokenHandler->expects($this->exactly(2)) + ->method('generateToken') + ->willReturnOnConsecutiveCalls('token1', 'token2'); + $this->notifications->expects($this->atLeastOnce()) + ->method('sendRemoteShare') + ->willReturn(true); + + $this->contactsManager->expects($this->any()) + ->method('search') + ->willReturn([]); + + $result = $this->provider->getAccessList([$file1], true); + $this->assertEquals(['remote' => []], $result); + + $result = $this->provider->getAccessList([$file1], false); + $this->assertEquals(['remote' => false], $result); + + $this->addressHandler->method('generateRemoteURL') + ->willReturn('remoteurl.com'); + + $share1 = $this->shareManager->newShare(); + $share1->setSharedWith('user@server.com') + ->setSharedBy($u1->getUID()) + ->setShareOwner($u1->getUID()) + ->setPermissions(\OCP\Constants::PERMISSION_READ) + ->setShareType(IShare::TYPE_REMOTE) + ->setNode($file1); + $this->provider->create($share1); + + $share2 = $this->shareManager->newShare(); + $share2->setSharedWith('foobar@localhost') + ->setSharedBy($u1->getUID()) + ->setShareOwner($u1->getUID()) + ->setPermissions(\OCP\Constants::PERMISSION_READ) + ->setShareType(IShare::TYPE_REMOTE) + ->setNode($file1); + $this->provider->create($share2); + + $result = $this->provider->getAccessList([$file1], true); + $this->assertEquals(['remote' => [ + 'user@server.com' => [ + 'token' => 'token1', + 'node_id' => $file1->getId(), + ], + 'foobar@localhost' => [ + 'token' => 'token2', + 'node_id' => $file1->getId(), + ], + ]], $result); + + $result = $this->provider->getAccessList([$file1], false); + $this->assertEquals(['remote' => true], $result); + + $u1->delete(); + } +} diff --git a/apps/federatedfilesharing/tests/NotificationsTest.php b/apps/federatedfilesharing/tests/NotificationsTest.php index 868591cb4dd..24fec06bf72 100644 --- a/apps/federatedfilesharing/tests/NotificationsTest.php +++ b/apps/federatedfilesharing/tests/NotificationsTest.php @@ -46,10 +46,10 @@ class NotificationsTest extends \Test\TestCase { protected function setUp(): void { parent::setUp(); - $this->jobList = $this->getMockBuilder('OCP\BackgroundJob\IJobList')->getMock(); + $this->jobList = $this->getMockBuilder(\OCP\BackgroundJob\IJobList::class)->getMock(); $this->discoveryService = $this->getMockBuilder(IDiscoveryService::class)->getMock(); - $this->httpClientService = $this->getMockBuilder('OCP\Http\Client\IClientService')->getMock(); - $this->addressHandler = $this->getMockBuilder('OCA\FederatedFileSharing\AddressHandler') + $this->httpClientService = $this->getMockBuilder(\OCP\Http\Client\IClientService::class)->getMock(); + $this->addressHandler = $this->getMockBuilder(\OCA\FederatedFileSharing\AddressHandler::class) ->disableOriginalConstructor()->getMock(); $this->logger = $this->createMock(LoggerInterface::class); $this->cloudFederationProviderManager = $this->createMock(ICloudFederationProviderManager::class); @@ -76,7 +76,7 @@ class NotificationsTest extends \Test\TestCase { $this->logger, ); } else { - $instance = $this->getMockBuilder('OCA\FederatedFileSharing\Notifications') + $instance = $this->getMockBuilder(\OCA\FederatedFileSharing\Notifications::class) ->setConstructorArgs( [ $this->addressHandler, @@ -120,7 +120,7 @@ class NotificationsTest extends \Test\TestCase { if ($try === 0 && $expected === false) { $this->jobList->expects($this->once())->method('add') ->with( - 'OCA\FederatedFileSharing\BackgroundJob\RetryJob', + \OCA\FederatedFileSharing\BackgroundJob\RetryJob::class, [ 'remote' => $remote, 'remoteId' => $id, diff --git a/apps/federation/lib/Controller/OCSAuthAPIController.php b/apps/federation/lib/Controller/OCSAuthAPIController.php index 8412868da42..31e87ff66d9 100644 --- a/apps/federation/lib/Controller/OCSAuthAPIController.php +++ b/apps/federation/lib/Controller/OCSAuthAPIController.php @@ -130,7 +130,7 @@ class OCSAuthAPIController extends OCSController { } $this->jobList->add( - 'OCA\Federation\BackgroundJob\GetSharedSecret', + \OCA\Federation\BackgroundJob\GetSharedSecret::class, [ 'url' => $url, 'token' => $token, diff --git a/apps/federation/tests/BackgroundJob/RequestSharedSecretTest.php b/apps/federation/tests/BackgroundJob/RequestSharedSecretTest.php index 63b8324ad2e..64c7ae3cdd4 100644 --- a/apps/federation/tests/BackgroundJob/RequestSharedSecretTest.php +++ b/apps/federation/tests/BackgroundJob/RequestSharedSecretTest.php @@ -89,7 +89,7 @@ class RequestSharedSecretTest extends TestCase { */ public function testStart($isTrustedServer, $retainBackgroundJob): void { /** @var RequestSharedSecret |MockObject $requestSharedSecret */ - $requestSharedSecret = $this->getMockBuilder('OCA\Federation\BackgroundJob\RequestSharedSecret') + $requestSharedSecret = $this->getMockBuilder(\OCA\Federation\BackgroundJob\RequestSharedSecret::class) ->setConstructorArgs( [ $this->httpClientService, diff --git a/apps/federation/tests/Controller/OCSAuthAPIControllerTest.php b/apps/federation/tests/Controller/OCSAuthAPIControllerTest.php index 9f2d41a1072..1f1fd58b088 100644 --- a/apps/federation/tests/Controller/OCSAuthAPIControllerTest.php +++ b/apps/federation/tests/Controller/OCSAuthAPIControllerTest.php @@ -91,7 +91,7 @@ class OCSAuthAPIControllerTest extends TestCase { if ($ok) { $this->jobList->expects($this->once())->method('add') - ->with('OCA\Federation\BackgroundJob\GetSharedSecret', ['url' => $url, 'token' => $token, 'created' => $this->currentTime]); + ->with(\OCA\Federation\BackgroundJob\GetSharedSecret::class, ['url' => $url, 'token' => $token, 'created' => $this->currentTime]); } else { $this->jobList->expects($this->never())->method('add'); $this->jobList->expects($this->never())->method('remove'); @@ -127,7 +127,7 @@ class OCSAuthAPIControllerTest extends TestCase { $token = 'token'; /** @var OCSAuthAPIController | \PHPUnit\Framework\MockObject\MockObject $ocsAuthApi */ - $ocsAuthApi = $this->getMockBuilder('OCA\Federation\Controller\OCSAuthAPIController') + $ocsAuthApi = $this->getMockBuilder(\OCA\Federation\Controller\OCSAuthAPIController::class) ->setConstructorArgs( [ 'federation', diff --git a/apps/federation/tests/DAV/FedAuthTest.php b/apps/federation/tests/DAV/FedAuthTest.php index d059fff0481..aa92b0112d0 100644 --- a/apps/federation/tests/DAV/FedAuthTest.php +++ b/apps/federation/tests/DAV/FedAuthTest.php @@ -22,7 +22,7 @@ class FedAuthTest extends TestCase { */ public function testFedAuth($expected, $user, $password): void { /** @var DbHandler | \PHPUnit\Framework\MockObject\MockObject $db */ - $db = $this->getMockBuilder('OCA\Federation\DbHandler')->disableOriginalConstructor()->getMock(); + $db = $this->getMockBuilder(\OCA\Federation\DbHandler::class)->disableOriginalConstructor()->getMock(); $db->method('auth')->willReturn(true); $auth = new FedAuth($db); $result = $this->invokePrivate($auth, 'validateUserPass', [$user, $password]); diff --git a/apps/federation/tests/Settings/AdminTest.php b/apps/federation/tests/Settings/AdminTest.php index 3d58fae2d7b..86baa6d6472 100644 --- a/apps/federation/tests/Settings/AdminTest.php +++ b/apps/federation/tests/Settings/AdminTest.php @@ -19,7 +19,7 @@ class AdminTest extends TestCase { protected function setUp(): void { parent::setUp(); - $this->trustedServers = $this->getMockBuilder('\OCA\Federation\TrustedServers')->disableOriginalConstructor()->getMock(); + $this->trustedServers = $this->getMockBuilder(\OCA\Federation\TrustedServers::class)->disableOriginalConstructor()->getMock(); $this->admin = new Admin( $this->trustedServers, $this->createMock(IL10N::class) diff --git a/apps/federation/tests/SyncFederationAddressbooksTest.php b/apps/federation/tests/SyncFederationAddressbooksTest.php index 6d826741292..73a89fea5eb 100644 --- a/apps/federation/tests/SyncFederationAddressbooksTest.php +++ b/apps/federation/tests/SyncFederationAddressbooksTest.php @@ -35,7 +35,7 @@ class SyncFederationAddressbooksTest extends \Test\TestCase { public function testSync(): void { /** @var DbHandler | MockObject $dbHandler */ - $dbHandler = $this->getMockBuilder('OCA\Federation\DbHandler') + $dbHandler = $this->getMockBuilder(\OCA\Federation\DbHandler::class) ->disableOriginalConstructor() ->getMock(); $dbHandler->method('getAllServer') @@ -49,7 +49,7 @@ class SyncFederationAddressbooksTest extends \Test\TestCase { ]); $dbHandler->expects($this->once())->method('setServerStatus')-> with('https://cloud.drop.box', 1, '1'); - $syncService = $this->getMockBuilder('OCA\DAV\CardDAV\SyncService') + $syncService = $this->getMockBuilder(\OCA\DAV\CardDAV\SyncService::class) ->disableOriginalConstructor() ->getMock(); $syncService->expects($this->once())->method('syncRemoteAddressBook') @@ -65,7 +65,7 @@ class SyncFederationAddressbooksTest extends \Test\TestCase { public function testException(): void { /** @var DbHandler | MockObject $dbHandler */ - $dbHandler = $this->getMockBuilder('OCA\Federation\DbHandler')-> + $dbHandler = $this->getMockBuilder(\OCA\Federation\DbHandler::class)-> disableOriginalConstructor()-> getMock(); $dbHandler->method('getAllServer')-> @@ -77,7 +77,7 @@ class SyncFederationAddressbooksTest extends \Test\TestCase { 'sync_token' => '0' ] ]); - $syncService = $this->getMockBuilder('OCA\DAV\CardDAV\SyncService') + $syncService = $this->getMockBuilder(\OCA\DAV\CardDAV\SyncService::class) ->disableOriginalConstructor() ->getMock(); $syncService->expects($this->once())->method('syncRemoteAddressBook') @@ -93,7 +93,7 @@ class SyncFederationAddressbooksTest extends \Test\TestCase { public function testSuccessfulSyncWithoutChangesAfterFailure(): void { /** @var DbHandler | MockObject $dbHandler */ - $dbHandler = $this->getMockBuilder('OCA\Federation\DbHandler') + $dbHandler = $this->getMockBuilder(\OCA\Federation\DbHandler::class) ->disableOriginalConstructor() ->getMock(); $dbHandler->method('getAllServer') @@ -108,7 +108,7 @@ class SyncFederationAddressbooksTest extends \Test\TestCase { $dbHandler->method('getServerStatus')->willReturn(\OCA\Federation\TrustedServers::STATUS_FAILURE); $dbHandler->expects($this->once())->method('setServerStatus')-> with('https://cloud.drop.box', 1); - $syncService = $this->getMockBuilder('OCA\DAV\CardDAV\SyncService') + $syncService = $this->getMockBuilder(\OCA\DAV\CardDAV\SyncService::class) ->disableOriginalConstructor() ->getMock(); $syncService->expects($this->once())->method('syncRemoteAddressBook') diff --git a/apps/federation/tests/TrustedServersTest.php b/apps/federation/tests/TrustedServersTest.php index 67b59c87bdb..21f6102317a 100644 --- a/apps/federation/tests/TrustedServersTest.php +++ b/apps/federation/tests/TrustedServersTest.php @@ -84,7 +84,7 @@ class TrustedServersTest extends TestCase { public function testAddServer(): void { /** @var \PHPUnit\Framework\MockObject\MockObject|TrustedServers $trustedServers */ - $trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers') + $trustedServers = $this->getMockBuilder(\OCA\Federation\TrustedServers::class) ->setConstructorArgs( [ $this->dbHandler, @@ -110,7 +110,7 @@ class TrustedServersTest extends TestCase { ->willReturn('token'); $this->dbHandler->expects($this->once())->method('addToken')->with('https://url', 'token'); $this->jobList->expects($this->once())->method('add') - ->with('OCA\Federation\BackgroundJob\RequestSharedSecret', + ->with(\OCA\Federation\BackgroundJob\RequestSharedSecret::class, ['url' => 'https://url', 'token' => 'token', 'created' => 1234567]); $this->assertSame( @@ -195,7 +195,7 @@ class TrustedServersTest extends TestCase { $server = 'server1'; /** @var \PHPUnit\Framework\MockObject\MockObject | TrustedServers $trustedServers */ - $trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers') + $trustedServers = $this->getMockBuilder(\OCA\Federation\TrustedServers::class) ->setConstructorArgs( [ $this->dbHandler, diff --git a/apps/files/lib/AppInfo/Application.php b/apps/files/lib/AppInfo/Application.php index 3d2d0527072..2a9c3f2bce3 100644 --- a/apps/files/lib/AppInfo/Application.php +++ b/apps/files/lib/AppInfo/Application.php @@ -147,6 +147,6 @@ class Application extends App implements IBootstrap { } private function registerHooks(): void { - Util::connectHook('\OCP\Config', 'js', '\OCA\Files\App', 'extendJsConfig'); + Util::connectHook('\OCP\Config', 'js', \OCA\Files\App::class, 'extendJsConfig'); } } diff --git a/apps/files/lib/Command/Scan.php b/apps/files/lib/Command/Scan.php index 68c80f6559a..22852706804 100644 --- a/apps/files/lib/Command/Scan.php +++ b/apps/files/lib/Command/Scan.php @@ -106,7 +106,7 @@ class Scan extends Base { ); # check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception - $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function (string $path) use ($output, $scanMetadata) { + $scanner->listen(\OC\Files\Utils\Scanner::class, 'scanFile', function (string $path) use ($output, $scanMetadata) { $output->writeln("\tFile\t<info>$path</info>", OutputInterface::VERBOSITY_VERBOSE); ++$this->filesCounter; $this->abortIfInterrupted(); @@ -120,18 +120,18 @@ class Scan extends Base { } }); - $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) { + $scanner->listen(\OC\Files\Utils\Scanner::class, 'scanFolder', function ($path) use ($output) { $output->writeln("\tFolder\t<info>$path</info>", OutputInterface::VERBOSITY_VERBOSE); ++$this->foldersCounter; $this->abortIfInterrupted(); }); - $scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) { + $scanner->listen(\OC\Files\Utils\Scanner::class, 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) { $output->writeln('Error while scanning, storage not available (' . $e->getMessage() . ')', OutputInterface::VERBOSITY_VERBOSE); ++$this->errorsCounter; }); - $scanner->listen('\OC\Files\Utils\Scanner', 'normalizedNameMismatch', function ($fullPath) use ($output) { + $scanner->listen(\OC\Files\Utils\Scanner::class, 'normalizedNameMismatch', function ($fullPath) use ($output) { $output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>'); ++$this->errorsCounter; }); diff --git a/apps/files/lib/Command/ScanAppData.php b/apps/files/lib/Command/ScanAppData.php index 5360d38bdb6..97f35cfc374 100644 --- a/apps/files/lib/Command/ScanAppData.php +++ b/apps/files/lib/Command/ScanAppData.php @@ -73,23 +73,23 @@ class ScanAppData extends Base { ); # check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception - $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) { + $scanner->listen(\OC\Files\Utils\Scanner::class, 'scanFile', function ($path) use ($output) { $output->writeln("\tFile <info>$path</info>", OutputInterface::VERBOSITY_VERBOSE); ++$this->filesCounter; $this->abortIfInterrupted(); }); - $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) { + $scanner->listen(\OC\Files\Utils\Scanner::class, 'scanFolder', function ($path) use ($output) { $output->writeln("\tFolder <info>$path</info>", OutputInterface::VERBOSITY_VERBOSE); ++$this->foldersCounter; $this->abortIfInterrupted(); }); - $scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) { + $scanner->listen(\OC\Files\Utils\Scanner::class, 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) { $output->writeln('Error while scanning, storage not available (' . $e->getMessage() . ')', OutputInterface::VERBOSITY_VERBOSE); }); - $scanner->listen('\OC\Files\Utils\Scanner', 'normalizedNameMismatch', function ($fullPath) use ($output) { + $scanner->listen(\OC\Files\Utils\Scanner::class, 'normalizedNameMismatch', function ($fullPath) use ($output) { $output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>'); }); diff --git a/apps/files/tests/BackgroundJob/ScanFilesTest.php b/apps/files/tests/BackgroundJob/ScanFilesTest.php index 0fb5163143f..6e7b6c7cd54 100644 --- a/apps/files/tests/BackgroundJob/ScanFilesTest.php +++ b/apps/files/tests/BackgroundJob/ScanFilesTest.php @@ -43,7 +43,7 @@ class ScanFilesTest extends TestCase { $connection = \OC::$server->getDatabaseConnection(); $this->mountCache = \OC::$server->getUserMountCache(); - $this->scanFiles = $this->getMockBuilder('\OCA\Files\BackgroundJob\ScanFiles') + $this->scanFiles = $this->getMockBuilder(\OCA\Files\BackgroundJob\ScanFiles::class) ->setConstructorArgs([ $config, $dispatcher, diff --git a/apps/files/tests/Controller/ViewControllerTest.php b/apps/files/tests/Controller/ViewControllerTest.php index a6eba1f9eaf..d9d5910f4c4 100644 --- a/apps/files/tests/Controller/ViewControllerTest.php +++ b/apps/files/tests/Controller/ViewControllerTest.php @@ -58,7 +58,7 @@ class ViewControllerTest extends TestCase { $this->config = $this->getMockBuilder(IConfig::class)->getMock(); $this->eventDispatcher = $this->createMock(IEventDispatcher::class); $this->userSession = $this->getMockBuilder(IUserSession::class)->getMock(); - $this->appManager = $this->getMockBuilder('\OCP\App\IAppManager')->getMock(); + $this->appManager = $this->getMockBuilder(\OCP\App\IAppManager::class)->getMock(); $this->user = $this->getMockBuilder(IUser::class)->getMock(); $this->user->expects($this->any()) ->method('getUID') @@ -66,7 +66,7 @@ class ViewControllerTest extends TestCase { $this->userSession->expects($this->any()) ->method('getUser') ->willReturn($this->user); - $this->rootFolder = $this->getMockBuilder('\OCP\Files\IRootFolder')->getMock(); + $this->rootFolder = $this->getMockBuilder(\OCP\Files\IRootFolder::class)->getMock(); $this->initialState = $this->createMock(IInitialState::class); $this->templateManager = $this->createMock(ITemplateManager::class); $this->userConfig = $this->createMock(UserConfig::class); diff --git a/apps/files_external/3rdparty/composer/InstalledVersions.php b/apps/files_external/3rdparty/composer/InstalledVersions.php index 51e734a774b..7d297a8d4b2 100644 --- a/apps/files_external/3rdparty/composer/InstalledVersions.php +++ b/apps/files_external/3rdparty/composer/InstalledVersions.php @@ -318,7 +318,7 @@ class InstalledVersions private static function getInstalled() { if (null === self::$canGetVendors) { - self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + self::$canGetVendors = method_exists(\Composer\Autoload\ClassLoader::class, 'getRegisteredLoaders'); } $installed = array(); diff --git a/apps/files_external/lib/Command/Scan.php b/apps/files_external/lib/Command/Scan.php index 575ee5989f5..b0f417d1f45 100644 --- a/apps/files_external/lib/Command/Scan.php +++ b/apps/files_external/lib/Command/Scan.php @@ -70,13 +70,13 @@ class Scan extends StorageAuthBase { /** @var Scanner $scanner */ $scanner = $storage->getScanner(); - $scanner->listen('\OC\Files\Cache\Scanner', 'scanFile', function (string $path) use ($output) { + $scanner->listen(\OC\Files\Cache\Scanner::class, 'scanFile', function (string $path) use ($output) { $output->writeln("\tFile\t<info>$path</info>", OutputInterface::VERBOSITY_VERBOSE); ++$this->filesCounter; $this->abortIfInterrupted(); }); - $scanner->listen('\OC\Files\Cache\Scanner', 'scanFolder', function (string $path) use ($output) { + $scanner->listen(\OC\Files\Cache\Scanner::class, 'scanFolder', function (string $path) use ($output) { $output->writeln("\tFolder\t<info>$path</info>", OutputInterface::VERBOSITY_VERBOSE); ++$this->foldersCounter; $this->abortIfInterrupted(); diff --git a/apps/files_external/lib/Config/ConfigAdapter.php b/apps/files_external/lib/Config/ConfigAdapter.php index 97bc4f78142..972ca5d80c5 100644 --- a/apps/files_external/lib/Config/ConfigAdapter.php +++ b/apps/files_external/lib/Config/ConfigAdapter.php @@ -46,7 +46,7 @@ class ConfigAdapter implements IMountProvider { $objectStore = $storage->getBackendOption('objectstore'); if ($objectStore) { $objectClass = $objectStore['class']; - if (!is_subclass_of($objectClass, '\OCP\Files\ObjectStore\IObjectStore')) { + if (!is_subclass_of($objectClass, \OCP\Files\ObjectStore\IObjectStore::class)) { throw new \InvalidArgumentException('Invalid object store'); } $storage->setBackendOption('objectstore', new $objectClass($objectStore)); diff --git a/apps/files_external/lib/Lib/Backend/AmazonS3.php b/apps/files_external/lib/Lib/Backend/AmazonS3.php index e345ed53f70..a4f1b18f58c 100644 --- a/apps/files_external/lib/Lib/Backend/AmazonS3.php +++ b/apps/files_external/lib/Lib/Backend/AmazonS3.php @@ -19,7 +19,7 @@ class AmazonS3 extends Backend { $this ->setIdentifier('amazons3') ->addIdentifierAlias('\OC\Files\Storage\AmazonS3') // legacy compat - ->setStorageClass('\OCA\Files_External\Lib\Storage\AmazonS3') + ->setStorageClass(\OCA\Files_External\Lib\Storage\AmazonS3::class) ->setText($l->t('Amazon S3')) ->addParameters([ new DefinitionParameter('bucket', $l->t('Bucket')), diff --git a/apps/files_external/lib/Lib/Backend/DAV.php b/apps/files_external/lib/Lib/Backend/DAV.php index 9eb206f0272..34c79f198e5 100644 --- a/apps/files_external/lib/Lib/Backend/DAV.php +++ b/apps/files_external/lib/Lib/Backend/DAV.php @@ -18,8 +18,8 @@ class DAV extends Backend { public function __construct(IL10N $l, Password $legacyAuth) { $this ->setIdentifier('dav') - ->addIdentifierAlias('\OC\Files\Storage\DAV') // legacy compat - ->setStorageClass('\OC\Files\Storage\DAV') + ->addIdentifierAlias(\OC\Files\Storage\DAV::class) // legacy compat + ->setStorageClass(\OC\Files\Storage\DAV::class) ->setText($l->t('WebDAV')) ->addParameters([ new DefinitionParameter('host', $l->t('URL')), diff --git a/apps/files_external/lib/Lib/Backend/FTP.php b/apps/files_external/lib/Lib/Backend/FTP.php index cdf7d187b4d..f942340f1e0 100644 --- a/apps/files_external/lib/Lib/Backend/FTP.php +++ b/apps/files_external/lib/Lib/Backend/FTP.php @@ -19,7 +19,7 @@ class FTP extends Backend { $this ->setIdentifier('ftp') ->addIdentifierAlias('\OC\Files\Storage\FTP') // legacy compat - ->setStorageClass('\OCA\Files_External\Lib\Storage\FTP') + ->setStorageClass(\OCA\Files_External\Lib\Storage\FTP::class) ->setText($l->t('FTP')) ->addParameters([ new DefinitionParameter('host', $l->t('Host')), diff --git a/apps/files_external/lib/Lib/Backend/InvalidBackend.php b/apps/files_external/lib/Lib/Backend/InvalidBackend.php index 22d0287244a..a61fb0af8e5 100644 --- a/apps/files_external/lib/Lib/Backend/InvalidBackend.php +++ b/apps/files_external/lib/Lib/Backend/InvalidBackend.php @@ -29,7 +29,7 @@ class InvalidBackend extends Backend { $this->invalidId = $invalidId; $this ->setIdentifier($invalidId) - ->setStorageClass('\OC\Files\Storage\FailedStorage') + ->setStorageClass(\OC\Files\Storage\FailedStorage::class) ->setText('Unknown storage backend ' . $invalidId); } diff --git a/apps/files_external/lib/Lib/Backend/Local.php b/apps/files_external/lib/Lib/Backend/Local.php index 2902ba770c6..505a3893b2d 100644 --- a/apps/files_external/lib/Lib/Backend/Local.php +++ b/apps/files_external/lib/Lib/Backend/Local.php @@ -18,8 +18,8 @@ class Local extends Backend { public function __construct(IL10N $l, NullMechanism $legacyAuth) { $this ->setIdentifier('local') - ->addIdentifierAlias('\OC\Files\Storage\Local') // legacy compat - ->setStorageClass('\OC\Files\Storage\Local') + ->addIdentifierAlias(\OC\Files\Storage\Local::class) // legacy compat + ->setStorageClass(\OC\Files\Storage\Local::class) ->setText($l->t('Local')) ->addParameters([ new DefinitionParameter('datadir', $l->t('Location')), diff --git a/apps/files_external/lib/Lib/Backend/OwnCloud.php b/apps/files_external/lib/Lib/Backend/OwnCloud.php index c0bd6891864..1c08bbe3a53 100644 --- a/apps/files_external/lib/Lib/Backend/OwnCloud.php +++ b/apps/files_external/lib/Lib/Backend/OwnCloud.php @@ -16,7 +16,7 @@ class OwnCloud extends Backend { $this ->setIdentifier('owncloud') ->addIdentifierAlias('\OC\Files\Storage\OwnCloud') // legacy compat - ->setStorageClass('\OCA\Files_External\Lib\Storage\OwnCloud') + ->setStorageClass(\OCA\Files_External\Lib\Storage\OwnCloud::class) ->setText($l->t('Nextcloud')) ->addParameters([ new DefinitionParameter('host', $l->t('URL')), diff --git a/apps/files_external/lib/Lib/Backend/SFTP.php b/apps/files_external/lib/Lib/Backend/SFTP.php index 93a5d87a5ff..348e0370608 100644 --- a/apps/files_external/lib/Lib/Backend/SFTP.php +++ b/apps/files_external/lib/Lib/Backend/SFTP.php @@ -16,7 +16,7 @@ class SFTP extends Backend { $this ->setIdentifier('sftp') ->addIdentifierAlias('\OC\Files\Storage\SFTP') // legacy compat - ->setStorageClass('\OCA\Files_External\Lib\Storage\SFTP') + ->setStorageClass(\OCA\Files_External\Lib\Storage\SFTP::class) ->setText($l->t('SFTP')) ->addParameters([ new DefinitionParameter('host', $l->t('Host')), diff --git a/apps/files_external/lib/Lib/Backend/SFTP_Key.php b/apps/files_external/lib/Lib/Backend/SFTP_Key.php index a657dce66e5..63c272d2432 100644 --- a/apps/files_external/lib/Lib/Backend/SFTP_Key.php +++ b/apps/files_external/lib/Lib/Backend/SFTP_Key.php @@ -15,7 +15,7 @@ class SFTP_Key extends Backend { public function __construct(IL10N $l, RSA $legacyAuth, SFTP $sftpBackend) { $this ->setIdentifier('\OC\Files\Storage\SFTP_Key') - ->setStorageClass('\OCA\Files_External\Lib\Storage\SFTP') + ->setStorageClass(\OCA\Files_External\Lib\Storage\SFTP::class) ->setText($l->t('SFTP with secret key login')) ->addParameters([ new DefinitionParameter('host', $l->t('Host')), diff --git a/apps/files_external/lib/Lib/Backend/SMB.php b/apps/files_external/lib/Lib/Backend/SMB.php index c4a68fea6e1..8e24b0c146d 100644 --- a/apps/files_external/lib/Lib/Backend/SMB.php +++ b/apps/files_external/lib/Lib/Backend/SMB.php @@ -27,7 +27,7 @@ class SMB extends Backend { $this ->setIdentifier('smb') ->addIdentifierAlias('\OC\Files\Storage\SMB')// legacy compat - ->setStorageClass('\OCA\Files_External\Lib\Storage\SMB') + ->setStorageClass(\OCA\Files_External\Lib\Storage\SMB::class) ->setText($l->t('SMB/CIFS')) ->addParameters([ new DefinitionParameter('host', $l->t('Host')), diff --git a/apps/files_external/lib/Lib/Backend/SMB_OC.php b/apps/files_external/lib/Lib/Backend/SMB_OC.php index 55edec8a464..bf7f855d180 100644 --- a/apps/files_external/lib/Lib/Backend/SMB_OC.php +++ b/apps/files_external/lib/Lib/Backend/SMB_OC.php @@ -24,7 +24,7 @@ class SMB_OC extends Backend { public function __construct(IL10N $l, SessionCredentials $legacyAuth, SMB $smbBackend) { $this ->setIdentifier('\OC\Files\Storage\SMB_OC') - ->setStorageClass('\OCA\Files_External\Lib\Storage\SMB') + ->setStorageClass(\OCA\Files_External\Lib\Storage\SMB::class) ->setText($l->t('SMB/CIFS using OC login')) ->addParameters([ new DefinitionParameter('host', $l->t('Host')), diff --git a/apps/files_external/lib/Lib/Backend/Swift.php b/apps/files_external/lib/Lib/Backend/Swift.php index 386604e6e1d..778e141a123 100644 --- a/apps/files_external/lib/Lib/Backend/Swift.php +++ b/apps/files_external/lib/Lib/Backend/Swift.php @@ -20,7 +20,7 @@ class Swift extends Backend { $this ->setIdentifier('swift') ->addIdentifierAlias('\OC\Files\Storage\Swift') // legacy compat - ->setStorageClass('\OCA\Files_External\Lib\Storage\Swift') + ->setStorageClass(\OCA\Files_External\Lib\Storage\Swift::class) ->setText($l->t('OpenStack Object Storage')) ->addParameters([ (new DefinitionParameter('service_name', $l->t('Service name'))) diff --git a/apps/files_external/tests/Backend/LegacyBackendTest.php b/apps/files_external/tests/Backend/LegacyBackendTest.php index 303700c6611..cc3a32d65b0 100644 --- a/apps/files_external/tests/Backend/LegacyBackendTest.php +++ b/apps/files_external/tests/Backend/LegacyBackendTest.php @@ -1,97 +1,97 @@ -<?php -/** - * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-only - */ -namespace OCA\Files_External\Tests\Backend; - -use OCA\Files_External\Lib\Backend\LegacyBackend; -use OCA\Files_External\Lib\DefinitionParameter; -use OCA\Files_External\Lib\MissingDependency; - -class LegacyBackendTest extends \Test\TestCase { - - /** - * @return MissingDependency[] - */ - public static function checkDependencies() { - return [ - (new MissingDependency('abc'))->setMessage('foobar') - ]; - } - - public function testConstructor(): void { - $auth = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\Builtin') - ->disableOriginalConstructor() - ->getMock(); - - $class = '\OCA\Files_External\Tests\Backend\LegacyBackendTest'; - $definition = [ - 'configuration' => [ - 'textfield' => 'Text field', - 'passwordfield' => '*Password field', - 'checkbox' => '!Checkbox', - 'hiddenfield' => '#Hidden field', - 'optionaltext' => '&Optional text field', - 'optionalpassword' => '&*Optional password field', - ], - 'backend' => 'Backend text', - 'priority' => 123, - 'custom' => 'foo/bar.js', - 'has_dependencies' => true, - ]; - - $backend = new LegacyBackend($class, $definition, $auth); - - $this->assertEquals('\OCA\Files_External\Tests\Backend\LegacyBackendTest', $backend->getStorageClass()); - $this->assertEquals('Backend text', $backend->getText()); - $this->assertEquals(123, $backend->getPriority()); - $this->assertContains('foo/bar.js', $backend->getCustomJs()); - $this->assertArrayHasKey('builtin', $backend->getAuthSchemes()); - $this->assertEquals($auth, $backend->getLegacyAuthMechanism()); - - $dependencies = $backend->checkDependencies(); - $this->assertCount(1, $dependencies); - $this->assertEquals('abc', $dependencies[0]->getDependency()); - $this->assertEquals('foobar', $dependencies[0]->getMessage()); - - $parameters = $backend->getParameters(); - $this->assertEquals('Text field', $parameters['textfield']->getText()); - $this->assertEquals(DefinitionParameter::VALUE_TEXT, $parameters['textfield']->getType()); - $this->assertEquals(DefinitionParameter::FLAG_NONE, $parameters['textfield']->getFlags()); - $this->assertEquals('Password field', $parameters['passwordfield']->getText()); - $this->assertEquals(DefinitionParameter::VALUE_PASSWORD, $parameters['passwordfield']->getType()); - $this->assertEquals(DefinitionParameter::FLAG_NONE, $parameters['passwordfield']->getFlags()); - $this->assertEquals('Checkbox', $parameters['checkbox']->getText()); - $this->assertEquals(DefinitionParameter::VALUE_BOOLEAN, $parameters['checkbox']->getType()); - $this->assertEquals(DefinitionParameter::FLAG_NONE, $parameters['checkbox']->getFlags()); - $this->assertEquals('Hidden field', $parameters['hiddenfield']->getText()); - $this->assertEquals(DefinitionParameter::VALUE_HIDDEN, $parameters['hiddenfield']->getType()); - $this->assertEquals(DefinitionParameter::FLAG_NONE, $parameters['hiddenfield']->getFlags()); - $this->assertEquals('Optional text field', $parameters['optionaltext']->getText()); - $this->assertEquals(DefinitionParameter::VALUE_TEXT, $parameters['optionaltext']->getType()); - $this->assertEquals(DefinitionParameter::FLAG_OPTIONAL, $parameters['optionaltext']->getFlags()); - $this->assertEquals('Optional password field', $parameters['optionalpassword']->getText()); - $this->assertEquals(DefinitionParameter::VALUE_PASSWORD, $parameters['optionalpassword']->getType()); - $this->assertEquals(DefinitionParameter::FLAG_OPTIONAL, $parameters['optionalpassword']->getFlags()); - } - - public function testNoDependencies(): void { - $auth = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\Builtin') - ->disableOriginalConstructor() - ->getMock(); - - $class = '\OCA\Files_External\Tests\Backend\LegacyBackendTest'; - $definition = [ - 'configuration' => [ - ], - 'backend' => 'Backend text', - ]; - - $backend = new LegacyBackend($class, $definition, $auth); - - $dependencies = $backend->checkDependencies(); - $this->assertCount(0, $dependencies); - } -} +<?php +/** + * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_External\Tests\Backend; + +use OCA\Files_External\Lib\Backend\LegacyBackend; +use OCA\Files_External\Lib\DefinitionParameter; +use OCA\Files_External\Lib\MissingDependency; + +class LegacyBackendTest extends \Test\TestCase { + + /** + * @return MissingDependency[] + */ + public static function checkDependencies() { + return [ + (new MissingDependency('abc'))->setMessage('foobar') + ]; + } + + public function testConstructor(): void { + $auth = $this->getMockBuilder(\OCA\Files_External\Lib\Auth\Builtin::class) + ->disableOriginalConstructor() + ->getMock(); + + $class = \OCA\Files_External\Tests\Backend\LegacyBackendTest::class; + $definition = [ + 'configuration' => [ + 'textfield' => 'Text field', + 'passwordfield' => '*Password field', + 'checkbox' => '!Checkbox', + 'hiddenfield' => '#Hidden field', + 'optionaltext' => '&Optional text field', + 'optionalpassword' => '&*Optional password field', + ], + 'backend' => 'Backend text', + 'priority' => 123, + 'custom' => 'foo/bar.js', + 'has_dependencies' => true, + ]; + + $backend = new LegacyBackend($class, $definition, $auth); + + $this->assertEquals(\OCA\Files_External\Tests\Backend\LegacyBackendTest::class, $backend->getStorageClass()); + $this->assertEquals('Backend text', $backend->getText()); + $this->assertEquals(123, $backend->getPriority()); + $this->assertContains('foo/bar.js', $backend->getCustomJs()); + $this->assertArrayHasKey('builtin', $backend->getAuthSchemes()); + $this->assertEquals($auth, $backend->getLegacyAuthMechanism()); + + $dependencies = $backend->checkDependencies(); + $this->assertCount(1, $dependencies); + $this->assertEquals('abc', $dependencies[0]->getDependency()); + $this->assertEquals('foobar', $dependencies[0]->getMessage()); + + $parameters = $backend->getParameters(); + $this->assertEquals('Text field', $parameters['textfield']->getText()); + $this->assertEquals(DefinitionParameter::VALUE_TEXT, $parameters['textfield']->getType()); + $this->assertEquals(DefinitionParameter::FLAG_NONE, $parameters['textfield']->getFlags()); + $this->assertEquals('Password field', $parameters['passwordfield']->getText()); + $this->assertEquals(DefinitionParameter::VALUE_PASSWORD, $parameters['passwordfield']->getType()); + $this->assertEquals(DefinitionParameter::FLAG_NONE, $parameters['passwordfield']->getFlags()); + $this->assertEquals('Checkbox', $parameters['checkbox']->getText()); + $this->assertEquals(DefinitionParameter::VALUE_BOOLEAN, $parameters['checkbox']->getType()); + $this->assertEquals(DefinitionParameter::FLAG_NONE, $parameters['checkbox']->getFlags()); + $this->assertEquals('Hidden field', $parameters['hiddenfield']->getText()); + $this->assertEquals(DefinitionParameter::VALUE_HIDDEN, $parameters['hiddenfield']->getType()); + $this->assertEquals(DefinitionParameter::FLAG_NONE, $parameters['hiddenfield']->getFlags()); + $this->assertEquals('Optional text field', $parameters['optionaltext']->getText()); + $this->assertEquals(DefinitionParameter::VALUE_TEXT, $parameters['optionaltext']->getType()); + $this->assertEquals(DefinitionParameter::FLAG_OPTIONAL, $parameters['optionaltext']->getFlags()); + $this->assertEquals('Optional password field', $parameters['optionalpassword']->getText()); + $this->assertEquals(DefinitionParameter::VALUE_PASSWORD, $parameters['optionalpassword']->getType()); + $this->assertEquals(DefinitionParameter::FLAG_OPTIONAL, $parameters['optionalpassword']->getFlags()); + } + + public function testNoDependencies(): void { + $auth = $this->getMockBuilder(\OCA\Files_External\Lib\Auth\Builtin::class) + ->disableOriginalConstructor() + ->getMock(); + + $class = \OCA\Files_External\Tests\Backend\LegacyBackendTest::class; + $definition = [ + 'configuration' => [ + ], + 'backend' => 'Backend text', + ]; + + $backend = new LegacyBackend($class, $definition, $auth); + + $dependencies = $backend->checkDependencies(); + $this->assertCount(0, $dependencies); + } +} diff --git a/apps/files_external/tests/Command/CommandTest.php b/apps/files_external/tests/Command/CommandTest.php index eb47fe08ac4..8d26f92afe1 100644 --- a/apps/files_external/tests/Command/CommandTest.php +++ b/apps/files_external/tests/Command/CommandTest.php @@ -20,7 +20,7 @@ abstract class CommandTest extends TestCase { * @return \OCA\Files_External\Service\GlobalStoragesService|\PHPUnit\Framework\MockObject\MockObject */ protected function getGlobalStorageService(array $mounts = []) { - $mock = $this->getMockBuilder('OCA\Files_External\Service\GlobalStoragesService') + $mock = $this->getMockBuilder(\OCA\Files_External\Service\GlobalStoragesService::class) ->disableOriginalConstructor() ->getMock(); diff --git a/apps/files_external/tests/Controller/AjaxControllerTest.php b/apps/files_external/tests/Controller/AjaxControllerTest.php index dc9661732cc..100c9770058 100644 --- a/apps/files_external/tests/Controller/AjaxControllerTest.php +++ b/apps/files_external/tests/Controller/AjaxControllerTest.php @@ -31,10 +31,10 @@ class AjaxControllerTest extends TestCase { protected function setUp(): void { $this->request = $this->createMock(IRequest::class); - $this->rsa = $this->getMockBuilder('\\OCA\\Files_External\\Lib\\Auth\\PublicKey\\RSA') + $this->rsa = $this->getMockBuilder(\OCA\Files_External\Lib\Auth\PublicKey\RSA::class) ->disableOriginalConstructor() ->getMock(); - $this->globalAuth = $this->getMockBuilder('\\OCA\\Files_External\\Lib\\Auth\\Password\GlobalAuth') + $this->globalAuth = $this->getMockBuilder(\OCA\Files_External\Lib\Auth\Password\GlobalAuth::class) ->disableOriginalConstructor() ->getMock(); $this->userSession = $this->createMock(IUserSession::class); diff --git a/apps/files_external/tests/Controller/GlobalStoragesControllerTest.php b/apps/files_external/tests/Controller/GlobalStoragesControllerTest.php index 4c318951d1b..cf2ef83a9c6 100644 --- a/apps/files_external/tests/Controller/GlobalStoragesControllerTest.php +++ b/apps/files_external/tests/Controller/GlobalStoragesControllerTest.php @@ -21,7 +21,7 @@ class GlobalStoragesControllerTest extends StoragesControllerTest { protected function setUp(): void { parent::setUp(); - $this->service = $this->getMockBuilder('\OCA\Files_External\Service\GlobalStoragesService') + $this->service = $this->getMockBuilder(\OCA\Files_External\Service\GlobalStoragesService::class) ->disableOriginalConstructor() ->getMock(); diff --git a/apps/files_external/tests/Controller/StoragesControllerTest.php b/apps/files_external/tests/Controller/StoragesControllerTest.php index 9e9595152ad..d8c00b7bcc2 100644 --- a/apps/files_external/tests/Controller/StoragesControllerTest.php +++ b/apps/files_external/tests/Controller/StoragesControllerTest.php @@ -40,7 +40,7 @@ abstract class StoragesControllerTest extends \Test\TestCase { /** * @return \OCA\Files_External\Lib\Backend\Backend|MockObject */ - protected function getBackendMock($class = '\OCA\Files_External\Lib\Backend\SMB', $storageClass = '\OCA\Files_External\Lib\Storage\SMB') { + protected function getBackendMock($class = \OCA\Files_External\Lib\Backend\SMB::class, $storageClass = \OCA\Files_External\Lib\Storage\SMB::class) { $backend = $this->getMockBuilder(Backend::class) ->disableOriginalConstructor() ->getMock(); @@ -56,7 +56,7 @@ abstract class StoragesControllerTest extends \Test\TestCase { /** * @return \OCA\Files_External\Lib\Auth\AuthMechanism|MockObject */ - protected function getAuthMechMock($scheme = 'null', $class = '\OCA\Files_External\Lib\Auth\NullMechanism') { + protected function getAuthMechMock($scheme = 'null', $class = \OCA\Files_External\Lib\Auth\NullMechanism::class) { $authMech = $this->getMockBuilder(AuthMechanism::class) ->disableOriginalConstructor() ->getMock(); @@ -97,8 +97,8 @@ abstract class StoragesControllerTest extends \Test\TestCase { $response = $this->controller->create( 'mount', - '\OCA\Files_External\Lib\Storage\SMB', - '\OCA\Files_External\Lib\Auth\NullMechanism', + \OCA\Files_External\Lib\Storage\SMB::class, + \OCA\Files_External\Lib\Auth\NullMechanism::class, [], [], [], @@ -129,7 +129,7 @@ abstract class StoragesControllerTest extends \Test\TestCase { $response = $this->controller->create( 'mount', 'local', - '\OCA\Files_External\Lib\Auth\NullMechanism', + \OCA\Files_External\Lib\Auth\NullMechanism::class, [], [], [], @@ -169,8 +169,8 @@ abstract class StoragesControllerTest extends \Test\TestCase { $response = $this->controller->update( 1, 'mount', - '\OCA\Files_External\Lib\Storage\SMB', - '\OCA\Files_External\Lib\Auth\NullMechanism', + \OCA\Files_External\Lib\Storage\SMB::class, + \OCA\Files_External\Lib\Auth\NullMechanism::class, [], [], [], @@ -211,8 +211,8 @@ abstract class StoragesControllerTest extends \Test\TestCase { $response = $this->controller->create( $mountPoint, - '\OCA\Files_External\Lib\Storage\SMB', - '\OCA\Files_External\Lib\Auth\NullMechanism', + \OCA\Files_External\Lib\Storage\SMB::class, + \OCA\Files_External\Lib\Auth\NullMechanism::class, [], [], [], @@ -225,8 +225,8 @@ abstract class StoragesControllerTest extends \Test\TestCase { $response = $this->controller->update( 1, $mountPoint, - '\OCA\Files_External\Lib\Storage\SMB', - '\OCA\Files_External\Lib\Auth\NullMechanism', + \OCA\Files_External\Lib\Storage\SMB::class, + \OCA\Files_External\Lib\Auth\NullMechanism::class, [], [], [], @@ -249,7 +249,7 @@ abstract class StoragesControllerTest extends \Test\TestCase { $response = $this->controller->create( 'mount', '\OC\Files\Storage\InvalidStorage', - '\OCA\Files_External\Lib\Auth\NullMechanism', + \OCA\Files_External\Lib\Auth\NullMechanism::class, [], [], [], @@ -263,7 +263,7 @@ abstract class StoragesControllerTest extends \Test\TestCase { 1, 'mount', '\OC\Files\Storage\InvalidStorage', - '\OCA\Files_External\Lib\Auth\NullMechanism', + \OCA\Files_External\Lib\Auth\NullMechanism::class, [], [], [], @@ -302,8 +302,8 @@ abstract class StoragesControllerTest extends \Test\TestCase { $response = $this->controller->update( 255, 'mount', - '\OCA\Files_External\Lib\Storage\SMB', - '\OCA\Files_External\Lib\Auth\NullMechanism', + \OCA\Files_External\Lib\Storage\SMB::class, + \OCA\Files_External\Lib\Auth\NullMechanism::class, [], [], [], @@ -400,8 +400,8 @@ abstract class StoragesControllerTest extends \Test\TestCase { $response = $this->controller->create( 'mount', - '\OCA\Files_External\Lib\Storage\SMB', - '\OCA\Files_External\Lib\Auth\NullMechanism', + \OCA\Files_External\Lib\Storage\SMB::class, + \OCA\Files_External\Lib\Auth\NullMechanism::class, [], [], [], diff --git a/apps/files_external/tests/Controller/UserStoragesControllerTest.php b/apps/files_external/tests/Controller/UserStoragesControllerTest.php index c15ded48ea7..4a0d3d8850f 100644 --- a/apps/files_external/tests/Controller/UserStoragesControllerTest.php +++ b/apps/files_external/tests/Controller/UserStoragesControllerTest.php @@ -28,7 +28,7 @@ class UserStoragesControllerTest extends StoragesControllerTest { protected function setUp(): void { parent::setUp(); - $this->service = $this->getMockBuilder('\OCA\Files_External\Service\UserStoragesService') + $this->service = $this->getMockBuilder(\OCA\Files_External\Service\UserStoragesService::class) ->disableOriginalConstructor() ->getMock(); @@ -88,7 +88,7 @@ class UserStoragesControllerTest extends StoragesControllerTest { $response = $this->controller->create( 'mount', - '\OCA\Files_External\Lib\Storage\SMB', + \OCA\Files_External\Lib\Storage\SMB::class, '\Auth\Mechanism', [], [], @@ -102,7 +102,7 @@ class UserStoragesControllerTest extends StoragesControllerTest { $response = $this->controller->update( 1, 'mount', - '\OCA\Files_External\Lib\Storage\SMB', + \OCA\Files_External\Lib\Storage\SMB::class, '\Auth\Mechanism', [], [], diff --git a/apps/files_external/tests/FrontendDefinitionTraitTest.php b/apps/files_external/tests/FrontendDefinitionTraitTest.php index bc5d88ff3f0..e33a175d28b 100644 --- a/apps/files_external/tests/FrontendDefinitionTraitTest.php +++ b/apps/files_external/tests/FrontendDefinitionTraitTest.php @@ -16,7 +16,7 @@ class FrontendDefinitionTraitTest extends \Test\TestCase { ->getMock(); $param->method('getName')->willReturn('foo'); - $trait = $this->getMockForTrait('\OCA\Files_External\Lib\FrontendDefinitionTrait'); + $trait = $this->getMockForTrait(\OCA\Files_External\Lib\FrontendDefinitionTrait::class); $trait->setText('test'); $trait->addParameters([$param]); $trait->addCustomJs('foo/bar.js'); @@ -67,7 +67,7 @@ class FrontendDefinitionTraitTest extends \Test\TestCase { $storageConfig->expects($this->any()) ->method('setBackendOption'); - $trait = $this->getMockForTrait('\OCA\Files_External\Lib\FrontendDefinitionTrait'); + $trait = $this->getMockForTrait(\OCA\Files_External\Lib\FrontendDefinitionTrait::class); $trait->setText('test'); $trait->addParameters($backendParams); @@ -98,7 +98,7 @@ class FrontendDefinitionTraitTest extends \Test\TestCase { ->method('setBackendOption') ->with('param', 'foobar'); - $trait = $this->getMockForTrait('\OCA\Files_External\Lib\FrontendDefinitionTrait'); + $trait = $this->getMockForTrait(\OCA\Files_External\Lib\FrontendDefinitionTrait::class); $trait->setText('test'); $trait->addParameter($param); diff --git a/apps/files_external/tests/LegacyDependencyCheckPolyfillTest.php b/apps/files_external/tests/LegacyDependencyCheckPolyfillTest.php index 5fcfe1dd1e6..db12ed3c1b4 100644 --- a/apps/files_external/tests/LegacyDependencyCheckPolyfillTest.php +++ b/apps/files_external/tests/LegacyDependencyCheckPolyfillTest.php @@ -1,36 +1,36 @@ -<?php -/** - * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-only - */ -namespace OCA\Files_External\Tests; - -use OCA\Files_External\Lib\MissingDependency; - -class LegacyDependencyCheckPolyfillTest extends \Test\TestCase { - - /** - * @return MissingDependency[] - */ - public static function checkDependencies() { - return [ - (new MissingDependency('dependency'))->setMessage('missing dependency'), - (new MissingDependency('program'))->setMessage('cannot find program'), - ]; - } - - public function testCheckDependencies(): void { - $trait = $this->getMockForTrait('\OCA\Files_External\Lib\LegacyDependencyCheckPolyfill'); - $trait->expects($this->once()) - ->method('getStorageClass') - ->willReturn('\OCA\Files_External\Tests\LegacyDependencyCheckPolyfillTest'); - - $dependencies = $trait->checkDependencies(); - $this->assertCount(2, $dependencies); - $this->assertEquals('dependency', $dependencies[0]->getDependency()); - $this->assertEquals('missing dependency', $dependencies[0]->getMessage()); - $this->assertEquals('program', $dependencies[1]->getDependency()); - $this->assertEquals('cannot find program', $dependencies[1]->getMessage()); - } -} +<?php +/** + * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCA\Files_External\Tests; + +use OCA\Files_External\Lib\MissingDependency; + +class LegacyDependencyCheckPolyfillTest extends \Test\TestCase { + + /** + * @return MissingDependency[] + */ + public static function checkDependencies() { + return [ + (new MissingDependency('dependency'))->setMessage('missing dependency'), + (new MissingDependency('program'))->setMessage('cannot find program'), + ]; + } + + public function testCheckDependencies(): void { + $trait = $this->getMockForTrait(\OCA\Files_External\Lib\LegacyDependencyCheckPolyfill::class); + $trait->expects($this->once()) + ->method('getStorageClass') + ->willReturn(\OCA\Files_External\Tests\LegacyDependencyCheckPolyfillTest::class); + + $dependencies = $trait->checkDependencies(); + $this->assertCount(2, $dependencies); + $this->assertEquals('dependency', $dependencies[0]->getDependency()); + $this->assertEquals('missing dependency', $dependencies[0]->getMessage()); + $this->assertEquals('program', $dependencies[1]->getDependency()); + $this->assertEquals('cannot find program', $dependencies[1]->getMessage()); + } +} diff --git a/apps/files_external/tests/PersonalMountTest.php b/apps/files_external/tests/PersonalMountTest.php index 2d8f41c3e50..9deb5c41435 100644 --- a/apps/files_external/tests/PersonalMountTest.php +++ b/apps/files_external/tests/PersonalMountTest.php @@ -16,11 +16,11 @@ class PersonalMountTest extends TestCase { public function testFindByStorageId(): void { $storageConfig = $this->createMock(StorageConfig::class); /** @var \OCA\Files_External\Service\UserStoragesService $storageService */ - $storageService = $this->getMockBuilder('\OCA\Files_External\Service\UserStoragesService') + $storageService = $this->getMockBuilder(\OCA\Files_External\Service\UserStoragesService::class) ->disableOriginalConstructor() ->getMock(); - $storage = $this->getMockBuilder('\OC\Files\Storage\Storage') + $storage = $this->getMockBuilder(\OC\Files\Storage\Storage::class) ->disableOriginalConstructor() ->getMock(); diff --git a/apps/files_external/tests/Service/BackendServiceTest.php b/apps/files_external/tests/Service/BackendServiceTest.php index 6d9754a5335..9d4007f852d 100644 --- a/apps/files_external/tests/Service/BackendServiceTest.php +++ b/apps/files_external/tests/Service/BackendServiceTest.php @@ -187,7 +187,7 @@ class BackendServiceTest extends \Test\TestCase { $backendNotAvailable->expects($this->once()) ->method('checkDependencies') ->willReturn([ - $this->getMockBuilder('\OCA\Files_External\Lib\MissingDependency') + $this->getMockBuilder(\OCA\Files_External\Lib\MissingDependency::class) ->disableOriginalConstructor() ->getMock() ]); diff --git a/apps/files_external/tests/Service/StoragesServiceTest.php b/apps/files_external/tests/Service/StoragesServiceTest.php index 40cba73a74f..c9df7b6c13b 100644 --- a/apps/files_external/tests/Service/StoragesServiceTest.php +++ b/apps/files_external/tests/Service/StoragesServiceTest.php @@ -98,7 +98,7 @@ abstract class StoragesServiceTest extends \Test\TestCase { // prepare BackendService mock $this->backendService = - $this->getMockBuilder('\OCA\Files_External\Service\BackendService') + $this->getMockBuilder(\OCA\Files_External\Service\BackendService::class) ->disableOriginalConstructor() ->getMock(); @@ -123,10 +123,10 @@ abstract class StoragesServiceTest extends \Test\TestCase { $this->backendService->method('getAuthMechanisms') ->willReturn($authMechanisms); - $sftpBackend = $this->getBackendMock('\OCA\Files_External\Lib\Backend\SFTP', '\OCA\Files_External\Lib\Storage\SFTP'); + $sftpBackend = $this->getBackendMock(\OCA\Files_External\Lib\Backend\SFTP::class, \OCA\Files_External\Lib\Storage\SFTP::class); $backends = [ - 'identifier:\OCA\Files_External\Lib\Backend\DAV' => $this->getBackendMock('\OCA\Files_External\Lib\Backend\DAV', '\OC\Files\Storage\DAV'), - 'identifier:\OCA\Files_External\Lib\Backend\SMB' => $this->getBackendMock('\OCA\Files_External\Lib\Backend\SMB', '\OCA\Files_External\Lib\Storage\SMB'), + 'identifier:\OCA\Files_External\Lib\Backend\DAV' => $this->getBackendMock(\OCA\Files_External\Lib\Backend\DAV::class, \OC\Files\Storage\DAV::class), + 'identifier:\OCA\Files_External\Lib\Backend\SMB' => $this->getBackendMock(\OCA\Files_External\Lib\Backend\SMB::class, \OCA\Files_External\Lib\Storage\SMB::class), 'identifier:\OCA\Files_External\Lib\Backend\SFTP' => $sftpBackend, 'identifier:sftp_alias' => $sftpBackend, ]; @@ -155,7 +155,7 @@ abstract class StoragesServiceTest extends \Test\TestCase { $containerMock = $this->createMock(IAppContainer::class); $containerMock->method('query') ->willReturnCallback(function ($name) { - if ($name === 'OCA\Files_External\Service\BackendService') { + if ($name === \OCA\Files_External\Service\BackendService::class) { return $this->backendService; } }); @@ -169,7 +169,7 @@ abstract class StoragesServiceTest extends \Test\TestCase { } } - protected function getBackendMock($class = '\OCA\Files_External\Lib\Backend\SMB', $storageClass = '\OCA\Files_External\Lib\Storage\SMB') { + protected function getBackendMock($class = \OCA\Files_External\Lib\Backend\SMB::class, $storageClass = \OCA\Files_External\Lib\Storage\SMB::class) { $backend = $this->getMockBuilder(Backend::class) ->disableOriginalConstructor() ->getMock(); @@ -180,7 +180,7 @@ abstract class StoragesServiceTest extends \Test\TestCase { return $backend; } - protected function getAuthMechMock($scheme = 'null', $class = '\OCA\Files_External\Lib\Auth\NullMechanism') { + protected function getAuthMechMock($scheme = 'null', $class = \OCA\Files_External\Lib\Auth\NullMechanism::class) { $authMech = $this->getMockBuilder(AuthMechanism::class) ->disableOriginalConstructor() ->getMock(); diff --git a/apps/files_external/tests/Service/UserStoragesServiceTest.php b/apps/files_external/tests/Service/UserStoragesServiceTest.php index cb7abfaf725..4ddc7177ebd 100644 --- a/apps/files_external/tests/Service/UserStoragesServiceTest.php +++ b/apps/files_external/tests/Service/UserStoragesServiceTest.php @@ -185,7 +185,7 @@ class UserStoragesServiceTest extends StoragesServiceTest { $newStorage = $this->globalStoragesService->addStorage($storage); - $this->assertInstanceOf('\OCA\Files_External\Lib\StorageConfig', $this->globalStoragesService->getStorage($newStorage->getId())); + $this->assertInstanceOf(\OCA\Files_External\Lib\StorageConfig::class, $this->globalStoragesService->getStorage($newStorage->getId())); $this->service->getStorage($newStorage->getId()); } diff --git a/apps/files_sharing/lib/Helper.php b/apps/files_sharing/lib/Helper.php index f2f92679e2f..4b3714ff10f 100644 --- a/apps/files_sharing/lib/Helper.php +++ b/apps/files_sharing/lib/Helper.php @@ -12,10 +12,10 @@ use OCA\Files_Sharing\AppInfo\Application; class Helper { public static function registerHooks() { - \OCP\Util::connectHook('OC_Filesystem', 'post_rename', '\OCA\Files_Sharing\Updater', 'renameHook'); - \OCP\Util::connectHook('OC_Filesystem', 'post_delete', '\OCA\Files_Sharing\Hooks', 'unshareChildren'); + \OCP\Util::connectHook('OC_Filesystem', 'post_rename', \OCA\Files_Sharing\Updater::class, 'renameHook'); + \OCP\Util::connectHook('OC_Filesystem', 'post_delete', \OCA\Files_Sharing\Hooks::class, 'unshareChildren'); - \OCP\Util::connectHook('OC_User', 'post_deleteUser', '\OCA\Files_Sharing\Hooks', 'deleteUser'); + \OCP\Util::connectHook('OC_User', 'post_deleteUser', \OCA\Files_Sharing\Hooks::class, 'deleteUser'); } /** diff --git a/apps/files_sharing/lib/Listener/LoadAdditionalListener.php b/apps/files_sharing/lib/Listener/LoadAdditionalListener.php index fc6516a83e2..ccd60ec6dfc 100644 --- a/apps/files_sharing/lib/Listener/LoadAdditionalListener.php +++ b/apps/files_sharing/lib/Listener/LoadAdditionalListener.php @@ -27,7 +27,7 @@ class LoadAdditionalListener implements IEventListener { Util::addStyle(Application::APP_ID, 'icons'); $shareManager = \OC::$server->get(IManager::class); - if ($shareManager->shareApiEnabled() && class_exists('\OCA\Files\App')) { + if ($shareManager->shareApiEnabled() && class_exists(\OCA\Files\App::class)) { Util::addInitScript(Application::APP_ID, 'init'); } } diff --git a/apps/files_sharing/lib/MountProvider.php b/apps/files_sharing/lib/MountProvider.php index 64847bf5a5f..3d38e99c1cd 100644 --- a/apps/files_sharing/lib/MountProvider.php +++ b/apps/files_sharing/lib/MountProvider.php @@ -80,7 +80,7 @@ class MountProvider implements IMountProvider { $ownerViews[$owner] = new View('/' . $parentShare->getShareOwner() . '/files'); } $mount = new SharedMount( - '\OCA\Files_Sharing\SharedStorage', + \OCA\Files_Sharing\SharedStorage::class, $mounts, [ 'user' => $user->getUID(), diff --git a/apps/files_sharing/lib/Scanner.php b/apps/files_sharing/lib/Scanner.php index 1ff1046bce7..43fd5f0babf 100644 --- a/apps/files_sharing/lib/Scanner.php +++ b/apps/files_sharing/lib/Scanner.php @@ -42,7 +42,7 @@ class Scanner extends \OC\Files\Cache\Scanner { if ($this->sourceScanner) { return $this->sourceScanner; } - if ($this->storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) { + if ($this->storage->instanceOfStorage(\OCA\Files_Sharing\SharedStorage::class)) { /** @var \OC\Files\Storage\Storage $storage */ [$storage] = $this->storage->resolvePath(''); $this->sourceScanner = $storage->getScanner(); diff --git a/apps/files_sharing/lib/SharedStorage.php b/apps/files_sharing/lib/SharedStorage.php index 00f757d4734..26f50aa2e02 100644 --- a/apps/files_sharing/lib/SharedStorage.php +++ b/apps/files_sharing/lib/SharedStorage.php @@ -202,13 +202,13 @@ class SharedStorage extends \OC\Files\Storage\Wrapper\Jail implements LegacyISha * @inheritdoc */ public function instanceOfStorage($class): bool { - if ($class === '\OC\Files\Storage\Common' || $class == Common::class) { + if ($class === \OC\Files\Storage\Common::class || $class == Common::class) { return true; } if (in_array($class, [ - '\OC\Files\Storage\Home', - '\OC\Files\ObjectStore\HomeObjectStoreStorage', - '\OCP\Files\IHomeStorage', + \OC\Files\Storage\Home::class, + \OC\Files\ObjectStore\HomeObjectStoreStorage::class, + \OCP\Files\IHomeStorage::class, Home::class, HomeObjectStoreStorage::class, IHomeStorage::class diff --git a/apps/files_sharing/tests/ApiTest.php b/apps/files_sharing/tests/ApiTest.php index fe0739cfcde..3806a8c1ea2 100644 --- a/apps/files_sharing/tests/ApiTest.php +++ b/apps/files_sharing/tests/ApiTest.php @@ -1264,7 +1264,7 @@ class ApiTest extends TestCase { $this->shareManager->deleteShare($share); \OC_Hook::clear('OC_Filesystem', 'post_initMountPoints'); - \OC_Hook::clear('\OCA\Files_Sharing\Tests\ApiTest', 'initTestMountPointsHook'); + \OC_Hook::clear(\OCA\Files_Sharing\Tests\ApiTest::class, 'initTestMountPointsHook'); } public function datesProvider() { diff --git a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php index f28302b4ccd..8c894f87559 100644 --- a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php +++ b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php @@ -521,7 +521,7 @@ class ShareAPIControllerTest extends TestCase { public function dataGetShare() { $data = []; - $cache = $this->getMockBuilder('OC\Files\Cache\Cache') + $cache = $this->getMockBuilder(\OC\Files\Cache\Cache::class) ->disableOriginalConstructor() ->getMock(); $cache->method('getNumericStorageId')->willReturn(101); @@ -535,7 +535,7 @@ class ShareAPIControllerTest extends TestCase { $parentFolder = $this->getMockBuilder(Folder::class)->getMock(); $parentFolder->method('getId')->willReturn(3); - $file = $this->getMockBuilder('OCP\Files\File')->getMock(); + $file = $this->getMockBuilder(\OCP\Files\File::class)->getMock(); $file->method('getId')->willReturn(1); $file->method('getPath')->willReturn('file'); $file->method('getStorage')->willReturn($storage); @@ -1926,8 +1926,8 @@ class ShareAPIControllerTest extends TestCase { $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') ->willReturnMap([ - ['OCA\Files_Sharing\External\Storage', false], - ['OCA\Files_Sharing\SharedStorage', false], + [\OCA\Files_Sharing\External\Storage::class, false], + [\OCA\Files_Sharing\SharedStorage::class, false], ]); $path->method('getStorage')->willReturn($storage); $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); @@ -1950,8 +1950,8 @@ class ShareAPIControllerTest extends TestCase { $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') ->willReturnMap([ - ['OCA\Files_Sharing\External\Storage', false], - ['OCA\Files_Sharing\SharedStorage', false], + [\OCA\Files_Sharing\External\Storage::class, false], + [\OCA\Files_Sharing\SharedStorage::class, false], ]); $path->method('getStorage')->willReturn($storage); $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); @@ -1975,8 +1975,8 @@ class ShareAPIControllerTest extends TestCase { $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') ->willReturnMap([ - ['OCA\Files_Sharing\External\Storage', false], - ['OCA\Files_Sharing\SharedStorage', false], + [\OCA\Files_Sharing\External\Storage::class, false], + [\OCA\Files_Sharing\SharedStorage::class, false], ]); $path->method('getStorage')->willReturn($storage); $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); @@ -1999,8 +1999,8 @@ class ShareAPIControllerTest extends TestCase { $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') ->willReturnMap([ - ['OCA\Files_Sharing\External\Storage', false], - ['OCA\Files_Sharing\SharedStorage', false], + [\OCA\Files_Sharing\External\Storage::class, false], + [\OCA\Files_Sharing\SharedStorage::class, false], ]); $path->method('getStorage')->willReturn($storage); $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); @@ -2038,8 +2038,8 @@ class ShareAPIControllerTest extends TestCase { $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') ->willReturnMap([ - ['OCA\Files_Sharing\External\Storage', false], - ['OCA\Files_Sharing\SharedStorage', false], + [\OCA\Files_Sharing\External\Storage::class, false], + [\OCA\Files_Sharing\SharedStorage::class, false], ]); $path->method('getStorage')->willReturn($storage); $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); @@ -2077,8 +2077,8 @@ class ShareAPIControllerTest extends TestCase { $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') ->willReturnMap([ - ['OCA\Files_Sharing\External\Storage', false], - ['OCA\Files_Sharing\SharedStorage', false], + [\OCA\Files_Sharing\External\Storage::class, false], + [\OCA\Files_Sharing\SharedStorage::class, false], ]); $path->method('getStorage')->willReturn($storage); $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); @@ -2123,8 +2123,8 @@ class ShareAPIControllerTest extends TestCase { $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') ->willReturnMap([ - ['OCA\Files_Sharing\External\Storage', false], - ['OCA\Files_Sharing\SharedStorage', false], + [\OCA\Files_Sharing\External\Storage::class, false], + [\OCA\Files_Sharing\SharedStorage::class, false], ]); $path->method('getStorage')->willReturn($storage); $path->method('getPath')->willReturn('valid-path'); @@ -2162,8 +2162,8 @@ class ShareAPIControllerTest extends TestCase { $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') ->willReturnMap([ - ['OCA\Files_Sharing\External\Storage', false], - ['OCA\Files_Sharing\SharedStorage', false], + [\OCA\Files_Sharing\External\Storage::class, false], + [\OCA\Files_Sharing\SharedStorage::class, false], ]); $path->method('getStorage')->willReturn($storage); $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); @@ -2208,8 +2208,8 @@ class ShareAPIControllerTest extends TestCase { $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') ->willReturnMap([ - ['OCA\Files_Sharing\External\Storage', false], - ['OCA\Files_Sharing\SharedStorage', false], + [\OCA\Files_Sharing\External\Storage::class, false], + [\OCA\Files_Sharing\SharedStorage::class, false], ]); $path->method('getStorage')->willReturn($storage); $this->rootFolder->method('getUserFolder')->with($this->currentUser)->willReturnSelf(); @@ -2577,8 +2577,8 @@ class ShareAPIControllerTest extends TestCase { $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') ->willReturnMap([ - ['OCA\Files_Sharing\External\Storage', true], - ['OCA\Files_Sharing\SharedStorage', false], + [\OCA\Files_Sharing\External\Storage::class, true], + [\OCA\Files_Sharing\SharedStorage::class, false], ]); $userFolder->method('getStorage')->willReturn($storage); $path->method('getStorage')->willReturn($storage); @@ -3760,7 +3760,7 @@ class ShareAPIControllerTest extends TestCase { $folder->method('getMTime')->willReturn(1234567890); $fileWithPreview->method('getMTime')->willReturn(1234567890); - $cache = $this->getMockBuilder('OCP\Files\Cache\ICache')->getMock(); + $cache = $this->getMockBuilder(\OCP\Files\Cache\ICache::class)->getMock(); $cache->method('getNumericStorageId')->willReturn(100); $storage = $this->createMock(Storage::class); $storage->method('getId')->willReturn('storageId'); @@ -4757,7 +4757,7 @@ class ShareAPIControllerTest extends TestCase { $mountPoint->method('getMountType')->willReturn(''); $file->method('getMountPoint')->willReturn($mountPoint); - $cache = $this->getMockBuilder('OCP\Files\Cache\ICache')->getMock(); + $cache = $this->getMockBuilder(\OCP\Files\Cache\ICache::class)->getMock(); $cache->method('getNumericStorageId')->willReturn(100); $storage = $this->createMock(Storage::class); $storage->method('getId')->willReturn('storageId'); @@ -4926,8 +4926,8 @@ class ShareAPIControllerTest extends TestCase { $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') ->willReturnMap([ - ['OCA\Files_Sharing\External\Storage', false], - ['OCA\Files_Sharing\SharedStorage', false], + [\OCA\Files_Sharing\External\Storage::class, false], + [\OCA\Files_Sharing\SharedStorage::class, false], ]); $userFolder->method('getStorage')->willReturn($storage); $node->method('getStorage')->willReturn($storage); @@ -4941,8 +4941,8 @@ class ShareAPIControllerTest extends TestCase { $storage = $this->createMock(Storage::class); $storage->method('instanceOfStorage') ->willReturnMap([ - ['OCA\Files_Sharing\External\Storage', false], - ['OCA\Files_Sharing\SharedStorage', false], + [\OCA\Files_Sharing\External\Storage::class, false], + [\OCA\Files_Sharing\SharedStorage::class, false], ]); $userFolder->method('getStorage')->willReturn($storage); $node->method('getStorage')->willReturn($storage); diff --git a/apps/files_sharing/tests/Controller/ShareControllerTest.php b/apps/files_sharing/tests/Controller/ShareControllerTest.php index cfe9d935f7f..6d974deb0ff 100644 --- a/apps/files_sharing/tests/Controller/ShareControllerTest.php +++ b/apps/files_sharing/tests/Controller/ShareControllerTest.php @@ -624,7 +624,7 @@ class ShareControllerTest extends \Test\TestCase { $owner->method('getDisplayName')->willReturn('ownerDisplay'); $owner->method('getUID')->willReturn('ownerUID'); - $file = $this->getMockBuilder('OCP\Files\File')->getMock(); + $file = $this->getMockBuilder(\OCP\Files\File::class)->getMock(); $file->method('getName')->willReturn($filename); $file->method('getMimetype')->willReturn('text/plain'); $file->method('getSize')->willReturn(33); diff --git a/apps/files_sharing/tests/Controller/ShareesAPIControllerTest.php b/apps/files_sharing/tests/Controller/ShareesAPIControllerTest.php index bf02e8114df..525a243e875 100644 --- a/apps/files_sharing/tests/Controller/ShareesAPIControllerTest.php +++ b/apps/files_sharing/tests/Controller/ShareesAPIControllerTest.php @@ -350,7 +350,7 @@ class ShareesAPIControllerTest extends TestCase { $urlGenerator = $this->createMock(IURLGenerator::class); /** @var MockObject|ShareesAPIController $sharees */ - $sharees = $this->getMockBuilder('\OCA\Files_Sharing\Controller\ShareesAPIController') + $sharees = $this->getMockBuilder(\OCA\Files_Sharing\Controller\ShareesAPIController::class) ->setConstructorArgs([ 'files_sharing', $request, diff --git a/apps/files_sharing/tests/EncryptedSizePropagationTest.php b/apps/files_sharing/tests/EncryptedSizePropagationTest.php index af2cf379358..657cf9f4b42 100644 --- a/apps/files_sharing/tests/EncryptedSizePropagationTest.php +++ b/apps/files_sharing/tests/EncryptedSizePropagationTest.php @@ -18,7 +18,7 @@ class EncryptedSizePropagationTest extends SizePropagationTest { protected function setupUser($name, $password = '') { $this->createUser($name, $password); $tmpFolder = \OC::$server->getTempManager()->getTemporaryFolder(); - $this->registerMount($name, '\OC\Files\Storage\Local', '/' . $name, ['datadir' => $tmpFolder]); + $this->registerMount($name, \OC\Files\Storage\Local::class, '/' . $name, ['datadir' => $tmpFolder]); $this->config->setAppValue('encryption', 'useMasterKey', '0'); $this->setupForUser($name, $password); $this->loginWithEncryption($name); diff --git a/apps/files_sharing/tests/EtagPropagationTest.php b/apps/files_sharing/tests/EtagPropagationTest.php index 5a65b1b5389..031f0f02e87 100644 --- a/apps/files_sharing/tests/EtagPropagationTest.php +++ b/apps/files_sharing/tests/EtagPropagationTest.php @@ -45,9 +45,9 @@ class EtagPropagationTest extends PropagationTestCase { $view1->file_put_contents('/sub1/sub2/folder/file.txt', 'foobar'); $view1->file_put_contents('/sub1/sub2/folder/inside/file.txt', 'foobar'); $folderInfo = $view1->getFileInfo('/sub1/sub2/folder'); - $this->assertInstanceOf('\OC\Files\FileInfo', $folderInfo); + $this->assertInstanceOf(\OC\Files\FileInfo::class, $folderInfo); $fileInfo = $view1->getFileInfo('/foo.txt'); - $this->assertInstanceOf('\OC\Files\FileInfo', $fileInfo); + $this->assertInstanceOf(\OC\Files\FileInfo::class, $fileInfo); $node = $rootFolder->getUserFolder(self::TEST_FILES_SHARING_API_USER1) ->get('/foo.txt'); @@ -81,7 +81,7 @@ class EtagPropagationTest extends PropagationTestCase { $this->shareManager->acceptShare($share, self::TEST_FILES_SHARING_API_USER3); $folderInfo = $view1->getFileInfo('/directReshare'); - $this->assertInstanceOf('\OC\Files\FileInfo', $folderInfo); + $this->assertInstanceOf(\OC\Files\FileInfo::class, $folderInfo); $node = $rootFolder->getUserFolder(self::TEST_FILES_SHARING_API_USER1) ->get('/directReshare'); @@ -108,7 +108,7 @@ class EtagPropagationTest extends PropagationTestCase { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER2); $insideInfo = $view2->getFileInfo('/sub1/sub2/folder/inside'); - $this->assertInstanceOf('\OC\Files\FileInfo', $insideInfo); + $this->assertInstanceOf(\OC\Files\FileInfo::class, $insideInfo); $node = $rootFolder->getUserFolder(self::TEST_FILES_SHARING_API_USER2) ->get('/sub1/sub2/folder/inside'); @@ -122,7 +122,7 @@ class EtagPropagationTest extends PropagationTestCase { $this->shareManager->acceptShare($share, self::TEST_FILES_SHARING_API_USER4); $folderInfo = $view2->getFileInfo('/directReshare'); - $this->assertInstanceOf('\OC\Files\FileInfo', $folderInfo); + $this->assertInstanceOf(\OC\Files\FileInfo::class, $folderInfo); $node = $rootFolder->getUserFolder(self::TEST_FILES_SHARING_API_USER2) ->get('/directReshare'); @@ -260,7 +260,7 @@ class EtagPropagationTest extends PropagationTestCase { public function testOwnerUnshares(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); $folderInfo = $this->rootView->getFileInfo('/' . self::TEST_FILES_SHARING_API_USER1 . '/files/sub1/sub2/folder'); - $this->assertInstanceOf('\OC\Files\FileInfo', $folderInfo); + $this->assertInstanceOf(\OC\Files\FileInfo::class, $folderInfo); $node = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1)->get('/sub1/sub2/folder'); $shareManager = \OC::$server->getShareManager(); @@ -283,7 +283,7 @@ class EtagPropagationTest extends PropagationTestCase { public function testOwnerUnsharesFlatReshares(): void { $this->loginAsUser(self::TEST_FILES_SHARING_API_USER1); $folderInfo = $this->rootView->getFileInfo('/' . self::TEST_FILES_SHARING_API_USER1 . '/files/sub1/sub2/folder/inside'); - $this->assertInstanceOf('\OC\Files\FileInfo', $folderInfo); + $this->assertInstanceOf(\OC\Files\FileInfo::class, $folderInfo); $node = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1)->get('/sub1/sub2/folder/inside'); $shareManager = \OC::$server->getShareManager(); diff --git a/apps/files_sharing/tests/External/CacheTest.php b/apps/files_sharing/tests/External/CacheTest.php index 2fb99e15715..8ba2427868e 100644 --- a/apps/files_sharing/tests/External/CacheTest.php +++ b/apps/files_sharing/tests/External/CacheTest.php @@ -58,7 +58,7 @@ class CacheTest extends TestCase { ); $this->remoteUser = $this->getUniqueID('remoteuser'); - $this->storage = $this->getMockBuilder('\OCA\Files_Sharing\External\Storage') + $this->storage = $this->getMockBuilder(\OCA\Files_Sharing\External\Storage::class) ->disableOriginalConstructor() ->getMock(); $this->storage diff --git a/apps/files_sharing/tests/External/ManagerTest.php b/apps/files_sharing/tests/External/ManagerTest.php index 7302fd307f2..9993f4c6d8f 100644 --- a/apps/files_sharing/tests/External/ManagerTest.php +++ b/apps/files_sharing/tests/External/ManagerTest.php @@ -252,7 +252,7 @@ class ManagerTest extends TestCase { $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1'); if (!$isGroup) { - $client = $this->getMockBuilder('OCP\Http\Client\IClient') + $client = $this->getMockBuilder(\OCP\Http\Client\IClient::class) ->disableOriginalConstructor()->getMock(); $this->clientService->expects($this->at(0)) ->method('newClient') @@ -308,7 +308,7 @@ class ManagerTest extends TestCase { $this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1'); if (!$isGroup) { - $client = $this->getMockBuilder('OCP\Http\Client\IClient') + $client = $this->getMockBuilder(\OCP\Http\Client\IClient::class) ->disableOriginalConstructor()->getMock(); $this->clientService->expects($this->at(0)) ->method('newClient') @@ -364,9 +364,9 @@ class ManagerTest extends TestCase { // no http requests here $this->manager->removeGroupShares('group1'); } else { - $client1 = $this->getMockBuilder('OCP\Http\Client\IClient') + $client1 = $this->getMockBuilder(\OCP\Http\Client\IClient::class) ->disableOriginalConstructor()->getMock(); - $client2 = $this->getMockBuilder('OCP\Http\Client\IClient') + $client2 = $this->getMockBuilder(\OCP\Http\Client\IClient::class) ->disableOriginalConstructor()->getMock(); $this->clientService->expects($this->exactly(2)) ->method('newClient') @@ -728,18 +728,18 @@ class ManagerTest extends TestCase { private function assertMount($mountPoint) { $mountPoint = rtrim($mountPoint, '/'); $mount = $this->mountManager->find($this->getFullPath($mountPoint)); - $this->assertInstanceOf('\OCA\Files_Sharing\External\Mount', $mount); - $this->assertInstanceOf('\OCP\Files\Mount\IMountPoint', $mount); + $this->assertInstanceOf(\OCA\Files_Sharing\External\Mount::class, $mount); + $this->assertInstanceOf(\OCP\Files\Mount\IMountPoint::class, $mount); $this->assertEquals($this->getFullPath($mountPoint), rtrim($mount->getMountPoint(), '/')); $storage = $mount->getStorage(); - $this->assertInstanceOf('\OCA\Files_Sharing\External\Storage', $storage); + $this->assertInstanceOf(\OCA\Files_Sharing\External\Storage::class, $storage); } private function assertNotMount($mountPoint) { $mountPoint = rtrim($mountPoint, '/'); try { $mount = $this->mountManager->find($this->getFullPath($mountPoint)); - $this->assertInstanceOf('\OCP\Files\Mount\IMountPoint', $mount); + $this->assertInstanceOf(\OCP\Files\Mount\IMountPoint::class, $mount); $this->assertNotEquals($this->getFullPath($mountPoint), rtrim($mount->getMountPoint(), '/')); } catch (NotFoundException $e) { diff --git a/apps/files_sharing/tests/External/ScannerTest.php b/apps/files_sharing/tests/External/ScannerTest.php index 7daa5f229d2..1a0077cf04b 100644 --- a/apps/files_sharing/tests/External/ScannerTest.php +++ b/apps/files_sharing/tests/External/ScannerTest.php @@ -22,10 +22,10 @@ class ScannerTest extends TestCase { protected function setUp(): void { parent::setUp(); - $this->storage = $this->getMockBuilder('\OCA\Files_Sharing\External\Storage') + $this->storage = $this->getMockBuilder(\OCA\Files_Sharing\External\Storage::class) ->disableOriginalConstructor() ->getMock(); - $this->cache = $this->getMockBuilder('\OC\Files\Cache\Cache') + $this->cache = $this->getMockBuilder(\OC\Files\Cache\Cache::class) ->disableOriginalConstructor() ->getMock(); $this->storage->expects($this->any()) diff --git a/apps/files_sharing/tests/Middleware/OCSShareAPIMiddlewareTest.php b/apps/files_sharing/tests/Middleware/OCSShareAPIMiddlewareTest.php index 30bae45f520..127d982fb2f 100644 --- a/apps/files_sharing/tests/Middleware/OCSShareAPIMiddlewareTest.php +++ b/apps/files_sharing/tests/Middleware/OCSShareAPIMiddlewareTest.php @@ -114,7 +114,7 @@ class OCSShareAPIMiddlewareTest extends \Test\TestCase { $controller->expects($this->once())->method('cleanup'); } - $response = $this->getMockBuilder('OCP\AppFramework\Http\Response') + $response = $this->getMockBuilder(\OCP\AppFramework\Http\Response::class) ->disableOriginalConstructor() ->getMock(); $this->middleware->afterController($controller, 'foo', $response); diff --git a/apps/files_sharing/tests/MountProviderTest.php b/apps/files_sharing/tests/MountProviderTest.php index 2dc5365ae2b..014153f5660 100644 --- a/apps/files_sharing/tests/MountProviderTest.php +++ b/apps/files_sharing/tests/MountProviderTest.php @@ -47,7 +47,7 @@ class MountProviderTest extends \Test\TestCase { $this->config = $this->getMockBuilder(IConfig::class)->getMock(); $this->user = $this->getMockBuilder(IUser::class)->getMock(); - $this->loader = $this->getMockBuilder('OCP\Files\Storage\IStorageFactory')->getMock(); + $this->loader = $this->getMockBuilder(\OCP\Files\Storage\IStorageFactory::class)->getMock(); $this->shareManager = $this->getMockBuilder(IManager::class)->getMock(); $this->logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); $eventDispatcher = $this->createMock(IEventDispatcher::class); @@ -169,10 +169,10 @@ class MountProviderTest extends \Test\TestCase { }); $mounts = $this->provider->getMountsForUser($this->user, $this->loader); $this->assertCount(4, $mounts); - $this->assertInstanceOf('OCA\Files_Sharing\SharedMount', $mounts[0]); - $this->assertInstanceOf('OCA\Files_Sharing\SharedMount', $mounts[1]); - $this->assertInstanceOf('OCA\Files_Sharing\SharedMount', $mounts[2]); - $this->assertInstanceOf('OCA\Files_Sharing\SharedMount', $mounts[3]); + $this->assertInstanceOf(\OCA\Files_Sharing\SharedMount::class, $mounts[0]); + $this->assertInstanceOf(\OCA\Files_Sharing\SharedMount::class, $mounts[1]); + $this->assertInstanceOf(\OCA\Files_Sharing\SharedMount::class, $mounts[2]); + $this->assertInstanceOf(\OCA\Files_Sharing\SharedMount::class, $mounts[3]); $mountedShare1 = $mounts[0]->getShare(); $this->assertEquals('2', $mountedShare1->getId()); $this->assertEquals('user2', $mountedShare1->getShareOwner()); @@ -401,7 +401,7 @@ class MountProviderTest extends \Test\TestCase { foreach ($mounts as $index => $mount) { $expectedShare = $expectedShares[$index]; - $this->assertInstanceOf('OCA\Files_Sharing\SharedMount', $mount); + $this->assertInstanceOf(\OCA\Files_Sharing\SharedMount::class, $mount); // supershare $share = $mount->getShare(); diff --git a/apps/files_sharing/tests/PropagationTestCase.php b/apps/files_sharing/tests/PropagationTestCase.php index dee056f0658..fd463ef0c6f 100644 --- a/apps/files_sharing/tests/PropagationTestCase.php +++ b/apps/files_sharing/tests/PropagationTestCase.php @@ -28,7 +28,7 @@ abstract class PropagationTestCase extends TestCase { \OC_Hook::clear('OC_Filesystem', 'post_write'); \OC_Hook::clear('OC_Filesystem', 'post_delete'); \OC_Hook::clear('OC_Filesystem', 'post_rename'); - \OC_Hook::clear('OCP\Share', 'post_update_permissions'); + \OC_Hook::clear(\OCP\Share::class, 'post_update_permissions'); parent::tearDown(); } diff --git a/apps/files_sharing/tests/SharedStorageTest.php b/apps/files_sharing/tests/SharedStorageTest.php index 5f907ad8de3..521872755b5 100644 --- a/apps/files_sharing/tests/SharedStorageTest.php +++ b/apps/files_sharing/tests/SharedStorageTest.php @@ -420,7 +420,7 @@ class SharedStorageTest extends TestCase { * @var \OCP\Files\Storage $sharedStorage */ [$sharedStorage,] = $view->resolvePath($this->folder); - $this->assertTrue($sharedStorage->instanceOfStorage('OCA\Files_Sharing\ISharedStorage')); + $this->assertTrue($sharedStorage->instanceOfStorage(\OCA\Files_Sharing\ISharedStorage::class)); $sourceStorage = new \OC\Files\Storage\Temporary([]); $sourceStorage->file_put_contents('foo.txt', 'asd'); @@ -453,7 +453,7 @@ class SharedStorageTest extends TestCase { * @var \OCP\Files\Storage $sharedStorage */ [$sharedStorage,] = $view->resolvePath($this->folder); - $this->assertTrue($sharedStorage->instanceOfStorage('OCA\Files_Sharing\ISharedStorage')); + $this->assertTrue($sharedStorage->instanceOfStorage(\OCA\Files_Sharing\ISharedStorage::class)); $sourceStorage = new \OC\Files\Storage\Temporary([]); $sourceStorage->file_put_contents('foo.txt', 'asd'); @@ -508,7 +508,7 @@ class SharedStorageTest extends TestCase { $this->assertTrue($view2->file_exists('/foo (2)')); $mount = $view2->getMount('/foo'); - $this->assertInstanceOf('\OCA\Files_Sharing\SharedMount', $mount); + $this->assertInstanceOf(\OCA\Files_Sharing\SharedMount::class, $mount); /** @var \OCA\Files_Sharing\SharedStorage $storage */ $storage = $mount->getStorage(); diff --git a/apps/files_sharing/tests/SizePropagationTest.php b/apps/files_sharing/tests/SizePropagationTest.php index de830c508cd..56057a3722c 100644 --- a/apps/files_sharing/tests/SizePropagationTest.php +++ b/apps/files_sharing/tests/SizePropagationTest.php @@ -23,7 +23,7 @@ class SizePropagationTest extends TestCase { protected function setupUser($name, $password = '') { $this->createUser($name, $password); $tmpFolder = \OC::$server->getTempManager()->getTemporaryFolder(); - $this->registerMount($name, '\OC\Files\Storage\Local', '/' . $name, ['datadir' => $tmpFolder]); + $this->registerMount($name, \OC\Files\Storage\Local::class, '/' . $name, ['datadir' => $tmpFolder]); $this->loginAsUser($name); return new View('/' . $name . '/files'); } diff --git a/apps/files_sharing/tests/TestCase.php b/apps/files_sharing/tests/TestCase.php index 4545e67be32..34332d4bdaa 100644 --- a/apps/files_sharing/tests/TestCase.php +++ b/apps/files_sharing/tests/TestCase.php @@ -65,7 +65,7 @@ abstract class TestCase extends \Test\TestCase { \OC::$server->getGroupManager()->clearBackends(); // clear share hooks - \OC_Hook::clear('OCP\\Share'); + \OC_Hook::clear(\OCP\Share::class); \OC::registerShareHooks(\OC::$server->getSystemConfig()); // create users diff --git a/apps/files_sharing/tests/UnshareChildrenTest.php b/apps/files_sharing/tests/UnshareChildrenTest.php index e95c1c68ecb..dd84061b9d3 100644 --- a/apps/files_sharing/tests/UnshareChildrenTest.php +++ b/apps/files_sharing/tests/UnshareChildrenTest.php @@ -25,7 +25,7 @@ class UnshareChildrenTest extends TestCase { protected function setUp(): void { parent::setUp(); - \OCP\Util::connectHook('OC_Filesystem', 'post_delete', '\OCA\Files_Sharing\Hooks', 'unshareChildren'); + \OCP\Util::connectHook('OC_Filesystem', 'post_delete', \OCA\Files_Sharing\Hooks::class, 'unshareChildren'); $this->folder = self::TEST_FOLDER_NAME; $this->subfolder = '/subfolder_share_api_test'; diff --git a/apps/files_trashbin/lib/AppInfo/Application.php b/apps/files_trashbin/lib/AppInfo/Application.php index e1a8e02afaf..0979910b4a3 100644 --- a/apps/files_trashbin/lib/AppInfo/Application.php +++ b/apps/files_trashbin/lib/AppInfo/Application.php @@ -53,13 +53,13 @@ class Application extends App implements IBootstrap { $context->injectFn([$this, 'registerTrashBackends']); // create storage wrapper on setup - \OCP\Util::connectHook('OC_Filesystem', 'preSetup', 'OCA\Files_Trashbin\Storage', 'setupStorage'); + \OCP\Util::connectHook('OC_Filesystem', 'preSetup', \OCA\Files_Trashbin\Storage::class, 'setupStorage'); //Listen to delete user signal - \OCP\Util::connectHook('OC_User', 'pre_deleteUser', 'OCA\Files_Trashbin\Hooks', 'deleteUser_hook'); + \OCP\Util::connectHook('OC_User', 'pre_deleteUser', \OCA\Files_Trashbin\Hooks::class, 'deleteUser_hook'); //Listen to post write hook - \OCP\Util::connectHook('OC_Filesystem', 'post_write', 'OCA\Files_Trashbin\Hooks', 'post_write_hook'); + \OCP\Util::connectHook('OC_Filesystem', 'post_write', \OCA\Files_Trashbin\Hooks::class, 'post_write_hook'); // pre and post-rename, disable trash logic for the copy+unlink case - \OCP\Util::connectHook('OC_Filesystem', 'delete', 'OCA\Files_Trashbin\Trashbin', 'ensureFileScannedHook'); + \OCP\Util::connectHook('OC_Filesystem', 'delete', \OCA\Files_Trashbin\Trashbin::class, 'ensureFileScannedHook'); } public function registerTrashBackends(ContainerInterface $serverContainer, LoggerInterface $logger, IAppManager $appManager, ITrashManager $trashManager): void { diff --git a/apps/files_trashbin/lib/Trashbin.php b/apps/files_trashbin/lib/Trashbin.php index c9863241045..9eaa4630331 100644 --- a/apps/files_trashbin/lib/Trashbin.php +++ b/apps/files_trashbin/lib/Trashbin.php @@ -328,7 +328,7 @@ class Trashbin { if (!$result) { \OC::$server->get(LoggerInterface::class)->error('trash bin database couldn\'t be updated', ['app' => 'files_trashbin']); } - \OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_moveToTrash', ['filePath' => Filesystem::normalizePath($file_path), + \OCP\Util::emitHook(\OCA\Files_Trashbin\Trashbin::class, 'post_moveToTrash', ['filePath' => Filesystem::normalizePath($file_path), 'trashPath' => Filesystem::normalizePath(static::getTrashFilename($filename, $timestamp))]); self::retainVersions($filename, $owner, $ownerPath, $timestamp); @@ -504,7 +504,7 @@ class Trashbin { $view->chroot('/' . $user . '/files'); $view->touch('/' . $location . '/' . $uniqueFilename, $mtime); $view->chroot($fakeRoot); - \OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', ['filePath' => $targetPath, 'trashPath' => $sourcePath]); + \OCP\Util::emitHook(\OCA\Files_Trashbin\Trashbin::class, 'post_restore', ['filePath' => $targetPath, 'trashPath' => $sourcePath]); $sourceNode = self::getNodeForPath($sourcePath); $targetNode = self::getNodeForPath($targetPath); diff --git a/apps/files_trashbin/tests/Command/CleanUpTest.php b/apps/files_trashbin/tests/Command/CleanUpTest.php index 49ae103ea30..625ca595a11 100644 --- a/apps/files_trashbin/tests/Command/CleanUpTest.php +++ b/apps/files_trashbin/tests/Command/CleanUpTest.php @@ -45,9 +45,9 @@ class CleanUpTest extends TestCase { protected function setUp(): void { parent::setUp(); - $this->rootFolder = $this->getMockBuilder('OCP\Files\IRootFolder') + $this->rootFolder = $this->getMockBuilder(\OCP\Files\IRootFolder::class) ->disableOriginalConstructor()->getMock(); - $this->userManager = $this->getMockBuilder('OC\User\Manager') + $this->userManager = $this->getMockBuilder(\OC\User\Manager::class) ->disableOriginalConstructor()->getMock(); $this->dbConnection = \OC::$server->getDatabaseConnection(); @@ -139,7 +139,7 @@ class CleanUpTest extends TestCase { */ public function testExecuteDeleteListOfUsers(): void { $userIds = ['user1', 'user2', 'user3']; - $instance = $this->getMockBuilder('OCA\Files_Trashbin\Command\CleanUp') + $instance = $this->getMockBuilder(\OCA\Files_Trashbin\Command\CleanUp::class) ->setMethods(['removeDeletedFiles']) ->setConstructorArgs([$this->rootFolder, $this->userManager, $this->dbConnection]) ->getMock(); @@ -171,7 +171,7 @@ class CleanUpTest extends TestCase { public function testExecuteAllUsers(): void { $userIds = []; $backendUsers = ['user1', 'user2']; - $instance = $this->getMockBuilder('OCA\Files_Trashbin\Command\CleanUp') + $instance = $this->getMockBuilder(\OCA\Files_Trashbin\Command\CleanUp::class) ->setMethods(['removeDeletedFiles']) ->setConstructorArgs([$this->rootFolder, $this->userManager, $this->dbConnection]) ->getMock(); diff --git a/apps/files_trashbin/tests/StorageTest.php b/apps/files_trashbin/tests/StorageTest.php index 37dfe84fc60..eaf815f9c89 100644 --- a/apps/files_trashbin/tests/StorageTest.php +++ b/apps/files_trashbin/tests/StorageTest.php @@ -503,7 +503,7 @@ class StorageTest extends \Test\TestCase { /** * @var \OC\Files\Storage\Temporary | \PHPUnit\Framework\MockObject\MockObject $storage */ - $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary') + $storage = $this->getMockBuilder(\OC\Files\Storage\Temporary::class) ->setConstructorArgs([[]]) ->setMethods(['rename', 'unlink', 'moveFromStorage']) ->getMock(); @@ -540,7 +540,7 @@ class StorageTest extends \Test\TestCase { /** * @var \OC\Files\Storage\Temporary | \PHPUnit\Framework\MockObject\MockObject $storage */ - $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary') + $storage = $this->getMockBuilder(\OC\Files\Storage\Temporary::class) ->setConstructorArgs([[]]) ->setMethods(['rename', 'unlink', 'rmdir']) ->getMock(); @@ -574,7 +574,7 @@ class StorageTest extends \Test\TestCase { $fileID = 1; $cache = $this->createMock(ICache::class); $cache->expects($this->any())->method('getId')->willReturn($fileID); - $tmpStorage = $this->getMockBuilder('\OC\Files\Storage\Temporary') + $tmpStorage = $this->getMockBuilder(\OC\Files\Storage\Temporary::class) ->disableOriginalConstructor()->getMock($cache); $tmpStorage->expects($this->any())->method('getCache')->willReturn($cache); $userManager = $this->getMockBuilder(IUserManager::class) diff --git a/apps/files_trashbin/tests/TrashbinTest.php b/apps/files_trashbin/tests/TrashbinTest.php index 11501891c77..df361ee6b76 100644 --- a/apps/files_trashbin/tests/TrashbinTest.php +++ b/apps/files_trashbin/tests/TrashbinTest.php @@ -45,7 +45,7 @@ class TrashbinTest extends \Test\TestCase { \OC_User::useBackend('database'); // clear share hooks - \OC_Hook::clear('OCP\\Share'); + \OC_Hook::clear(\OCP\Share::class); \OC::registerShareHooks(\OC::$server->getSystemConfig()); // init files sharing diff --git a/apps/files_versions/lib/Storage.php b/apps/files_versions/lib/Storage.php index 41f04b5a1d1..532e598115d 100644 --- a/apps/files_versions/lib/Storage.php +++ b/apps/files_versions/lib/Storage.php @@ -414,7 +414,7 @@ class Storage { try { // TODO add a proper way of overwriting a file while maintaining file ids - if ($storage1->instanceOfStorage('\OC\Files\ObjectStore\ObjectStoreStorage') || $storage2->instanceOfStorage('\OC\Files\ObjectStore\ObjectStoreStorage')) { + if ($storage1->instanceOfStorage(\OC\Files\ObjectStore\ObjectStoreStorage::class) || $storage2->instanceOfStorage(\OC\Files\ObjectStore\ObjectStoreStorage::class)) { $source = $storage1->fopen($internalPath1, 'r'); $target = $storage2->fopen($internalPath2, 'w'); [, $result] = \OC_Helper::streamCopy($source, $target); diff --git a/apps/files_versions/tests/Command/CleanupTest.php b/apps/files_versions/tests/Command/CleanupTest.php index 021a47ed08d..efa873edf86 100644 --- a/apps/files_versions/tests/Command/CleanupTest.php +++ b/apps/files_versions/tests/Command/CleanupTest.php @@ -38,11 +38,11 @@ class CleanupTest extends TestCase { protected function setUp(): void { parent::setUp(); - $this->rootFolder = $this->getMockBuilder('OCP\Files\IRootFolder') + $this->rootFolder = $this->getMockBuilder(\OCP\Files\IRootFolder::class) ->disableOriginalConstructor()->getMock(); - $this->userManager = $this->getMockBuilder('OC\User\Manager') + $this->userManager = $this->getMockBuilder(\OC\User\Manager::class) ->disableOriginalConstructor()->getMock(); - $this->versionMapper = $this->getMockBuilder('OCA\Files_Versions\Db\VersionsMapper') + $this->versionMapper = $this->getMockBuilder(\OCA\Files_Versions\Db\VersionsMapper::class) ->disableOriginalConstructor()->getMock(); $this->cleanup = new CleanUp($this->rootFolder, $this->userManager, $this->versionMapper); @@ -105,7 +105,7 @@ class CleanupTest extends TestCase { public function testExecuteDeleteListOfUsers(): void { $userIds = ['user1', 'user2', 'user3']; - $instance = $this->getMockBuilder('OCA\Files_Versions\Command\CleanUp') + $instance = $this->getMockBuilder(\OCA\Files_Versions\Command\CleanUp::class) ->setMethods(['deleteVersions']) ->setConstructorArgs([$this->rootFolder, $this->userManager, $this->versionMapper]) ->getMock(); @@ -137,7 +137,7 @@ class CleanupTest extends TestCase { $userIds = []; $backendUsers = ['user1', 'user2']; - $instance = $this->getMockBuilder('OCA\Files_Versions\Command\CleanUp') + $instance = $this->getMockBuilder(\OCA\Files_Versions\Command\CleanUp::class) ->setMethods(['deleteVersions']) ->setConstructorArgs([$this->rootFolder, $this->userManager, $this->versionMapper]) ->getMock(); diff --git a/apps/provisioning_api/tests/Controller/GroupsControllerTest.php b/apps/provisioning_api/tests/Controller/GroupsControllerTest.php index 8bbc8a29c29..751e92cc285 100644 --- a/apps/provisioning_api/tests/Controller/GroupsControllerTest.php +++ b/apps/provisioning_api/tests/Controller/GroupsControllerTest.php @@ -84,7 +84,7 @@ class GroupsControllerTest extends \Test\TestCase { * @return \OCP\IGroup|\PHPUnit\Framework\MockObject\MockObject */ private function createGroup($gid) { - $group = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); + $group = $this->getMockBuilder(\OCP\IGroup::class)->disableOriginalConstructor()->getMock(); $group ->method('getGID') ->willReturn($gid); diff --git a/apps/provisioning_api/tests/Controller/UsersControllerTest.php b/apps/provisioning_api/tests/Controller/UsersControllerTest.php index 0f82fc53ba6..c64bd4405e9 100644 --- a/apps/provisioning_api/tests/Controller/UsersControllerTest.php +++ b/apps/provisioning_api/tests/Controller/UsersControllerTest.php @@ -170,21 +170,21 @@ class UsersControllerTest extends TestCase { ->expects($this->once()) ->method('isAdmin') ->willReturn(false); - $firstGroup = $this->getMockBuilder('OCP\IGroup') + $firstGroup = $this->getMockBuilder(\OCP\IGroup::class) ->disableOriginalConstructor() ->getMock(); $firstGroup ->expects($this->once()) ->method('getGID') ->willReturn('FirstGroup'); - $secondGroup = $this->getMockBuilder('OCP\IGroup') + $secondGroup = $this->getMockBuilder(\OCP\IGroup::class) ->disableOriginalConstructor() ->getMock(); $secondGroup ->expects($this->once()) ->method('getGID') ->willReturn('SecondGroup'); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $subAdminManager ->expects($this->once()) @@ -649,7 +649,7 @@ class UsersControllerTest extends TestCase { ->method('createUser') ->with('NewUser', 'PasswordOfTheNewUser') ->willReturn($user); - $group = $this->getMockBuilder('OCP\IGroup') + $group = $this->getMockBuilder(\OCP\IGroup::class) ->disableOriginalConstructor() ->getMock(); $group @@ -744,7 +744,7 @@ class UsersControllerTest extends TestCase { ->method('isAdmin') ->with('regularUser') ->willReturn(false); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $this->groupManager ->expects($this->once()) @@ -777,13 +777,13 @@ class UsersControllerTest extends TestCase { ->method('isAdmin') ->with('regularUser') ->willReturn(false); - $existingGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); + $existingGroup = $this->getMockBuilder(\OCP\IGroup::class)->disableOriginalConstructor()->getMock(); $this->groupManager ->expects($this->once()) ->method('get') ->with('ExistingGroup') ->willReturn($existingGroup); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $subAdminManager ->expects($this->once()) @@ -842,10 +842,10 @@ class UsersControllerTest extends TestCase { ->method('createUser') ->with('NewUser', 'PasswordOfTheNewUser') ->willReturn($user); - $existingGroup1 = $this->getMockBuilder('OCP\IGroup') + $existingGroup1 = $this->getMockBuilder(\OCP\IGroup::class) ->disableOriginalConstructor() ->getMock(); - $existingGroup2 = $this->getMockBuilder('OCP\IGroup') + $existingGroup2 = $this->getMockBuilder(\OCP\IGroup::class) ->disableOriginalConstructor() ->getMock(); $existingGroup1 @@ -877,7 +877,7 @@ class UsersControllerTest extends TestCase { ['Added userid NewUser to group ExistingGroup1', ['app' => 'ocs_api']], ['Added userid NewUser to group ExistingGroup2', ['app' => 'ocs_api']] ); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $this->groupManager ->expects($this->once()) @@ -927,7 +927,7 @@ class UsersControllerTest extends TestCase { $loggedInUser = $this->getMockBuilder(IUser::class) ->disableOriginalConstructor() ->getMock(); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor() ->getMock(); $loggedInUser @@ -1105,7 +1105,7 @@ class UsersControllerTest extends TestCase { ->expects($this->any()) ->method('getUserGroups') ->willReturn([]); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor() ->getMock(); $subAdminManager @@ -1242,7 +1242,7 @@ class UsersControllerTest extends TestCase { ->method('isAdmin') ->with('subadmin') ->willReturn(false); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor() ->getMock(); $subAdminManager @@ -1283,7 +1283,7 @@ class UsersControllerTest extends TestCase { ->method('isAdmin') ->with('UID') ->willReturn(false); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor() ->getMock(); $subAdminManager @@ -2070,7 +2070,7 @@ class UsersControllerTest extends TestCase { ->method('isAdmin') ->with('admin') ->willReturn(true); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor() ->getMock(); $this->groupManager @@ -2322,7 +2322,7 @@ class UsersControllerTest extends TestCase { ->method('get') ->with('UserToEdit') ->willReturn($targetUser); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor() ->getMock(); $subAdminManager @@ -2368,7 +2368,7 @@ class UsersControllerTest extends TestCase { ->method('get') ->with('UserToEdit') ->willReturn($targetUser); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor() ->getMock(); $subAdminManager @@ -2534,7 +2534,7 @@ class UsersControllerTest extends TestCase { ->method('isAdmin') ->with('subadmin') ->willReturn(false); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $subAdminManager ->expects($this->once()) @@ -2582,7 +2582,7 @@ class UsersControllerTest extends TestCase { ->method('isAdmin') ->with('subadmin') ->willReturn(false); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $subAdminManager ->expects($this->once()) @@ -2630,7 +2630,7 @@ class UsersControllerTest extends TestCase { ->method('isAdmin') ->with('subadmin') ->willReturn(false); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $subAdminManager ->expects($this->once()) @@ -2747,7 +2747,7 @@ class UsersControllerTest extends TestCase { ->method('isAdmin') ->with('subadmin') ->willReturn(false); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $subAdminManager ->expects($this->once()) @@ -2758,12 +2758,12 @@ class UsersControllerTest extends TestCase { ->expects($this->once()) ->method('getSubAdmin') ->willReturn($subAdminManager); - $group1 = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); + $group1 = $this->getMockBuilder(\OCP\IGroup::class)->disableOriginalConstructor()->getMock(); $group1 ->expects($this->any()) ->method('getGID') ->willReturn('Group1'); - $group2 = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); + $group2 = $this->getMockBuilder(\OCP\IGroup::class)->disableOriginalConstructor()->getMock(); $group2 ->expects($this->any()) ->method('getGID') @@ -2811,7 +2811,7 @@ class UsersControllerTest extends TestCase { ->method('isAdmin') ->with('subadmin') ->willReturn(false); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $subAdminManager ->expects($this->once()) @@ -3053,7 +3053,7 @@ class UsersControllerTest extends TestCase { $this->expectExceptionCode(103); $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock(); - $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); + $targetGroup = $this->getMockBuilder(\OCP\IGroup::class)->disableOriginalConstructor()->getMock(); $this->userSession ->expects($this->once()) ->method('getUser') @@ -3083,7 +3083,7 @@ class UsersControllerTest extends TestCase { ->method('getUID') ->willReturn('unauthorizedUser'); $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock(); - $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); + $targetGroup = $this->getMockBuilder(\OCP\IGroup::class)->disableOriginalConstructor()->getMock(); $this->userSession ->expects($this->once()) ->method('getUser') @@ -3098,7 +3098,7 @@ class UsersControllerTest extends TestCase { ->method('get') ->with('TargetUser') ->willReturn($targetUser); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $this->groupManager ->expects($this->once()) @@ -3129,7 +3129,7 @@ class UsersControllerTest extends TestCase { ->expects($this->once()) ->method('getUID') ->willReturn('admin'); - $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); + $targetGroup = $this->getMockBuilder(\OCP\IGroup::class)->disableOriginalConstructor()->getMock(); $targetGroup ->expects($this->once()) ->method('getGID') @@ -3148,7 +3148,7 @@ class UsersControllerTest extends TestCase { ->method('get') ->with('Admin') ->willReturn($targetUser); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $this->groupManager ->expects($this->once()) @@ -3179,7 +3179,7 @@ class UsersControllerTest extends TestCase { ->expects($this->once()) ->method('getUID') ->willReturn('subadmin'); - $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); + $targetGroup = $this->getMockBuilder(\OCP\IGroup::class)->disableOriginalConstructor()->getMock(); $targetGroup ->expects($this->any()) ->method('getGID') @@ -3198,7 +3198,7 @@ class UsersControllerTest extends TestCase { ->method('get') ->with('SubAdmin') ->willReturn($targetUser); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $subAdminManager ->expects($this->once()) @@ -3230,7 +3230,7 @@ class UsersControllerTest extends TestCase { ->method('getUID') ->willReturn('subadmin'); $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock(); - $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); + $targetGroup = $this->getMockBuilder(\OCP\IGroup::class)->disableOriginalConstructor()->getMock(); $targetGroup ->expects($this->any()) ->method('getGID') @@ -3249,7 +3249,7 @@ class UsersControllerTest extends TestCase { ->method('get') ->with('AnotherUser') ->willReturn($targetUser); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $subAdminManager ->expects($this->once()) @@ -3287,7 +3287,7 @@ class UsersControllerTest extends TestCase { ->method('getUID') ->willReturn('admin'); $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock(); - $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); + $targetGroup = $this->getMockBuilder(\OCP\IGroup::class)->disableOriginalConstructor()->getMock(); $this->userSession ->expects($this->once()) ->method('getUser') @@ -3302,7 +3302,7 @@ class UsersControllerTest extends TestCase { ->method('get') ->with('AnotherUser') ->willReturn($targetUser); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $this->groupManager ->expects($this->once()) @@ -3365,7 +3365,7 @@ class UsersControllerTest extends TestCase { $this->expectExceptionCode(103); $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock(); - $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); + $targetGroup = $this->getMockBuilder(\OCP\IGroup::class)->disableOriginalConstructor()->getMock(); $targetGroup ->expects($this->once()) ->method('getGID') @@ -3386,7 +3386,7 @@ class UsersControllerTest extends TestCase { public function testAddSubAdminTwice(): void { $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock(); - $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); + $targetGroup = $this->getMockBuilder(\OCP\IGroup::class)->disableOriginalConstructor()->getMock(); $this->userManager ->expects($this->once()) ->method('get') @@ -3397,7 +3397,7 @@ class UsersControllerTest extends TestCase { ->method('get') ->with('TargetGroup') ->willReturn($targetGroup); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $subAdminManager ->expects($this->once()) @@ -3414,7 +3414,7 @@ class UsersControllerTest extends TestCase { public function testAddSubAdminSuccessful(): void { $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock(); - $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); + $targetGroup = $this->getMockBuilder(\OCP\IGroup::class)->disableOriginalConstructor()->getMock(); $this->userManager ->expects($this->once()) ->method('get') @@ -3425,7 +3425,7 @@ class UsersControllerTest extends TestCase { ->method('get') ->with('TargetGroup') ->willReturn($targetGroup); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $subAdminManager ->expects($this->once()) @@ -3488,7 +3488,7 @@ class UsersControllerTest extends TestCase { $this->expectExceptionCode(102); $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock(); - $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); + $targetGroup = $this->getMockBuilder(\OCP\IGroup::class)->disableOriginalConstructor()->getMock(); $this->userManager ->expects($this->once()) ->method('get') @@ -3499,7 +3499,7 @@ class UsersControllerTest extends TestCase { ->method('get') ->with('GroupToDeleteFrom') ->willReturn($targetGroup); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $subAdminManager ->expects($this->once()) @@ -3516,7 +3516,7 @@ class UsersControllerTest extends TestCase { public function testRemoveSubAdminSuccessful(): void { $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock(); - $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); + $targetGroup = $this->getMockBuilder(\OCP\IGroup::class)->disableOriginalConstructor()->getMock(); $this->userManager ->expects($this->once()) ->method('get') @@ -3527,7 +3527,7 @@ class UsersControllerTest extends TestCase { ->method('get') ->with('GroupToDeleteFrom') ->willReturn($targetGroup); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $subAdminManager ->expects($this->once()) @@ -3563,7 +3563,7 @@ class UsersControllerTest extends TestCase { public function testGetUserSubAdminGroupsWithGroups(): void { $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock(); - $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); + $targetGroup = $this->getMockBuilder(\OCP\IGroup::class)->disableOriginalConstructor()->getMock(); $targetGroup ->expects($this->once()) ->method('getGID') @@ -3573,7 +3573,7 @@ class UsersControllerTest extends TestCase { ->method('get') ->with('RequestedUser') ->willReturn($targetUser); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor()->getMock(); $subAdminManager ->expects($this->once()) @@ -3834,7 +3834,7 @@ class UsersControllerTest extends TestCase { ->method('isAdmin') ->with('subadmin') ->willReturn(false); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor() ->getMock(); $subAdminManager @@ -3871,7 +3871,7 @@ class UsersControllerTest extends TestCase { ->method('get') ->with('UserToGet') ->willReturn($targetUser); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor() ->getMock(); $subAdminManager @@ -3916,7 +3916,7 @@ class UsersControllerTest extends TestCase { ->method('get') ->with('UserToGet') ->willReturn($targetUser); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor() ->getMock(); $subAdminManager @@ -3962,7 +3962,7 @@ class UsersControllerTest extends TestCase { ->method('get') ->with('UserToGet') ->willReturn($targetUser); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor() ->getMock(); $subAdminManager @@ -4013,7 +4013,7 @@ class UsersControllerTest extends TestCase { ->method('get') ->with('UserToGet') ->willReturn($targetUser); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor() ->getMock(); $subAdminManager @@ -4070,7 +4070,7 @@ class UsersControllerTest extends TestCase { ->method('get') ->with('UserToGet') ->willReturn($targetUser); - $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + $subAdminManager = $this->getMockBuilder(\OC\SubAdmin::class) ->disableOriginalConstructor() ->getMock(); $subAdminManager diff --git a/apps/settings/lib/Controller/UsersController.php b/apps/settings/lib/Controller/UsersController.php index 4ee359b6fe9..07c5e828d1a 100644 --- a/apps/settings/lib/Controller/UsersController.php +++ b/apps/settings/lib/Controller/UsersController.php @@ -108,7 +108,7 @@ class UsersController extends Controller { } else { if ($this->appManager->isEnabledForUser('user_ldap')) { $isLDAPUsed = - $this->groupManager->isBackendUsed('\OCA\User_LDAP\Group_Proxy'); + $this->groupManager->isBackendUsed(\OCA\User_LDAP\Group_Proxy::class); if ($isLDAPUsed) { // LDAP user count can be slow, so we sort by group name here $sortGroupsBy = \OC\Group\MetaData::SORT_GROUPNAME; diff --git a/apps/settings/lib/SetupChecks/TempSpaceAvailable.php b/apps/settings/lib/SetupChecks/TempSpaceAvailable.php index ef51ffe0e07..f33706df717 100644 --- a/apps/settings/lib/SetupChecks/TempSpaceAvailable.php +++ b/apps/settings/lib/SetupChecks/TempSpaceAvailable.php @@ -40,11 +40,11 @@ class TempSpaceAvailable implements ISetupCheck { return false; } - if (isset($objectStoreMultibucket['class']) && $objectStoreMultibucket['class'] !== 'OC\\Files\\ObjectStore\\S3') { + if (isset($objectStoreMultibucket['class']) && $objectStoreMultibucket['class'] !== \OC\Files\ObjectStore\S3::class) { return false; } - if (isset($objectStore['class']) && $objectStore['class'] !== 'OC\\Files\\ObjectStore\\S3') { + if (isset($objectStore['class']) && $objectStore['class'] !== \OC\Files\ObjectStore\S3::class) { return false; } diff --git a/apps/settings/tests/Controller/CheckSetupControllerTest.php b/apps/settings/tests/Controller/CheckSetupControllerTest.php index 27f7aa1b696..6111cbf249b 100644 --- a/apps/settings/tests/Controller/CheckSetupControllerTest.php +++ b/apps/settings/tests/Controller/CheckSetupControllerTest.php @@ -62,7 +62,7 @@ class CheckSetupControllerTest extends TestCase { ->willReturnCallback(function ($message, array $replace) { return vsprintf($message, $replace); }); - $this->checker = $this->getMockBuilder('\OC\IntegrityCheck\Checker') + $this->checker = $this->getMockBuilder(\OC\IntegrityCheck\Checker::class) ->disableOriginalConstructor()->getMock(); $this->logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); $this->setupCheckManager = $this->createMock(ISetupCheckManager::class); @@ -195,7 +195,7 @@ class CheckSetupControllerTest extends TestCase { $this->checker ->expects($this->once()) ->method('getResults') - ->willReturn([ 'core' => [ 'EXTRA_FILE' => ['/testfile' => []], 'INVALID_HASH' => [ '/.idea/workspace.xml' => [ 'expected' => 'f1c5e2630d784bc9cb02d5a28f55d6f24d06dae2a0fee685f3c2521b050955d9d452769f61454c9ddfa9c308146ade10546cfa829794448eaffbc9a04a29d216', 'current' => 'ce08bf30bcbb879a18b49239a9bec6b8702f52452f88a9d32142cad8d2494d5735e6bfa0d8642b2762c62ca5be49f9bf4ec231d4a230559d4f3e2c471d3ea094', ], '/lib/private/integritycheck/checker.php' => [ 'expected' => 'c5a03bacae8dedf8b239997901ba1fffd2fe51271d13a00cc4b34b09cca5176397a89fc27381cbb1f72855fa18b69b6f87d7d5685c3b45aee373b09be54742ea', 'current' => '88a3a92c11db91dec1ac3be0e1c87f862c95ba6ffaaaa3f2c3b8f682187c66f07af3a3b557a868342ef4a271218fe1c1e300c478e6c156c5955ed53c40d06585', ], '/settings/controller/checksetupcontroller.php' => [ 'expected' => '3e1de26ce93c7bfe0ede7c19cb6c93cadc010340225b375607a7178812e9de163179b0dc33809f451e01f491d93f6f5aaca7929685d21594cccf8bda732327c4', 'current' => '09563164f9904a837f9ca0b5f626db56c838e5098e0ccc1d8b935f68fa03a25c5ec6f6b2d9e44a868e8b85764dafd1605522b4af8db0ae269d73432e9a01e63a', ], ], ], 'bookmarks' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'dav' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'encryption' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'external' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'federation' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'files' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'files_antivirus' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'files_drop' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'files_external' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'files_pdfviewer' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'files_sharing' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'files_trashbin' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'files_versions' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'files_videoviewer' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'firstrunwizard' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'gitsmart' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'logreader' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature could not get verified.', ], ], 'password_policy' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'provisioning_api' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'sketch' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'threatblock' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'two_factor_auth' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'user_ldap' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], 'user_shibboleth' => [ 'EXCEPTION' => [ 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ], ], ]); + ->willReturn([ 'core' => [ 'EXTRA_FILE' => ['/testfile' => []], 'INVALID_HASH' => [ '/.idea/workspace.xml' => [ 'expected' => 'f1c5e2630d784bc9cb02d5a28f55d6f24d06dae2a0fee685f3c2521b050955d9d452769f61454c9ddfa9c308146ade10546cfa829794448eaffbc9a04a29d216', 'current' => 'ce08bf30bcbb879a18b49239a9bec6b8702f52452f88a9d32142cad8d2494d5735e6bfa0d8642b2762c62ca5be49f9bf4ec231d4a230559d4f3e2c471d3ea094', ], '/lib/private/integritycheck/checker.php' => [ 'expected' => 'c5a03bacae8dedf8b239997901ba1fffd2fe51271d13a00cc4b34b09cca5176397a89fc27381cbb1f72855fa18b69b6f87d7d5685c3b45aee373b09be54742ea', 'current' => '88a3a92c11db91dec1ac3be0e1c87f862c95ba6ffaaaa3f2c3b8f682187c66f07af3a3b557a868342ef4a271218fe1c1e300c478e6c156c5955ed53c40d06585', ], '/settings/controller/checksetupcontroller.php' => [ 'expected' => '3e1de26ce93c7bfe0ede7c19cb6c93cadc010340225b375607a7178812e9de163179b0dc33809f451e01f491d93f6f5aaca7929685d21594cccf8bda732327c4', 'current' => '09563164f9904a837f9ca0b5f626db56c838e5098e0ccc1d8b935f68fa03a25c5ec6f6b2d9e44a868e8b85764dafd1605522b4af8db0ae269d73432e9a01e63a', ], ], ], 'bookmarks' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'dav' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'encryption' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'external' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'federation' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'files' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'files_antivirus' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'files_drop' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'files_external' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'files_pdfviewer' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'files_sharing' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'files_trashbin' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'files_versions' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'files_videoviewer' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'firstrunwizard' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'gitsmart' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'logreader' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature could not get verified.', ], ], 'password_policy' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'provisioning_api' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'sketch' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'threatblock' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'two_factor_auth' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'user_ldap' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], 'user_shibboleth' => [ 'EXCEPTION' => [ 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, 'message' => 'Signature data not found.', ], ], ]); $expected = new DataDisplayResponse( 'Technical information diff --git a/apps/settings/tests/Controller/UsersControllerTest.php b/apps/settings/tests/Controller/UsersControllerTest.php index db346ab89f2..3a6b54dbeb9 100644 --- a/apps/settings/tests/Controller/UsersControllerTest.php +++ b/apps/settings/tests/Controller/UsersControllerTest.php @@ -867,7 +867,7 @@ class UsersControllerTest extends \Test\TestCase { if ($onlyVerificationCode === false) { $this->accountManager->expects($this->once())->method('updateAccount')->with($userAccount)->willReturnArgument(1); $this->jobList->expects($this->once())->method('add') - ->with('OCA\Settings\BackgroundJobs\VerifyUserData', + ->with(\OCA\Settings\BackgroundJobs\VerifyUserData::class, [ 'verificationCode' => $code, 'data' => $dataBefore[$type]['value'], diff --git a/apps/settings/tests/Mailer/NewUserMailHelperTest.php b/apps/settings/tests/Mailer/NewUserMailHelperTest.php index 579ab2cdbb0..badd56cf600 100644 --- a/apps/settings/tests/Mailer/NewUserMailHelperTest.php +++ b/apps/settings/tests/Mailer/NewUserMailHelperTest.php @@ -354,7 +354,7 @@ EOF; $result = $this->newUserMailHelper->generateTemplate($user, true); $this->assertEquals($expectedHtmlBody, $result->renderHtml()); $this->assertEquals($expectedTextBody, $result->renderText()); - $this->assertSame('OC\Mail\EMailTemplate', get_class($result)); + $this->assertSame(\OC\Mail\EMailTemplate::class, get_class($result)); } public function testGenerateTemplateWithoutPasswordResetToken(): void { @@ -590,7 +590,7 @@ EOF; $result = $this->newUserMailHelper->generateTemplate($user, false); $this->assertEquals($expectedHtmlBody, $result->renderHtml()); $this->assertEquals($expectedTextBody, $result->renderText()); - $this->assertSame('OC\Mail\EMailTemplate', get_class($result)); + $this->assertSame(\OC\Mail\EMailTemplate::class, get_class($result)); } public function testGenerateTemplateWithoutUserId(): void { @@ -813,7 +813,7 @@ EOF; $result = $this->newUserMailHelper->generateTemplate($user, false); $this->assertEquals($expectedHtmlBody, $result->renderHtml()); $this->assertEquals($expectedTextBody, $result->renderText()); - $this->assertSame('OC\Mail\EMailTemplate', get_class($result)); + $this->assertSame(\OC\Mail\EMailTemplate::class, get_class($result)); } public function testSendMail(): void { diff --git a/apps/sharebymail/tests/ShareByMailProviderTest.php b/apps/sharebymail/tests/ShareByMailProviderTest.php index c01f5b47632..908c2969244 100644 --- a/apps/sharebymail/tests/ShareByMailProviderTest.php +++ b/apps/sharebymail/tests/ShareByMailProviderTest.php @@ -73,13 +73,13 @@ class ShareByMailProviderTest extends TestCase { }); $this->config = $this->getMockBuilder(IConfig::class)->getMock(); $this->logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); - $this->rootFolder = $this->getMockBuilder('OCP\Files\IRootFolder')->getMock(); + $this->rootFolder = $this->getMockBuilder(\OCP\Files\IRootFolder::class)->getMock(); $this->userManager = $this->getMockBuilder(IUserManager::class)->getMock(); - $this->secureRandom = $this->getMockBuilder('\OCP\Security\ISecureRandom')->getMock(); - $this->mailer = $this->getMockBuilder('\OCP\Mail\IMailer')->getMock(); + $this->secureRandom = $this->getMockBuilder(\OCP\Security\ISecureRandom::class)->getMock(); + $this->mailer = $this->getMockBuilder(\OCP\Mail\IMailer::class)->getMock(); $this->urlGenerator = $this->getMockBuilder(IURLGenerator::class)->getMock(); $this->share = $this->getMockBuilder(IShare::class)->getMock(); - $this->activityManager = $this->getMockBuilder('OCP\Activity\IManager')->getMock(); + $this->activityManager = $this->getMockBuilder(\OCP\Activity\IManager::class)->getMock(); $this->settingsManager = $this->getMockBuilder(SettingsManager::class)->disableOriginalConstructor()->getMock(); $this->defaults = $this->createMock(Defaults::class); $this->hasher = $this->getMockBuilder(IHasher::class)->getMock(); @@ -98,7 +98,7 @@ class ShareByMailProviderTest extends TestCase { */ private function getInstance(array $mockedMethods = []) { if (!empty($mockedMethods)) { - return $this->getMockBuilder('OCA\ShareByMail\ShareByMailProvider') + return $this->getMockBuilder(\OCA\ShareByMail\ShareByMailProvider::class) ->setConstructorArgs([ $this->config, $this->connection, @@ -621,7 +621,7 @@ class ShareByMailProviderTest extends TestCase { $this->expectException(\Exception::class); $this->share->expects($this->once())->method('getSharedWith')->willReturn('user1'); - $node = $this->getMockBuilder('OCP\Files\Node')->getMock(); + $node = $this->getMockBuilder(\OCP\Files\Node::class)->getMock(); $node->expects($this->any())->method('getName')->willReturn('fileName'); $this->share->expects($this->any())->method('getNode')->willReturn($node); @@ -645,7 +645,7 @@ class ShareByMailProviderTest extends TestCase { $this->share->expects($this->any())->method('getNote')->willReturn('Check this!'); $this->share->expects($this->any())->method('getMailSend')->willReturn(true); - $node = $this->getMockBuilder('OCP\Files\Node')->getMock(); + $node = $this->getMockBuilder(\OCP\Files\Node::class)->getMock(); $node->expects($this->any())->method('getName')->willReturn('fileName'); $this->share->expects($this->any())->method('getNode')->willReturn($node); @@ -878,7 +878,7 @@ class ShareByMailProviderTest extends TestCase { $result = $instance->getShareById($id2); - $this->assertInstanceOf('OCP\Share\IShare', $result); + $this->assertInstanceOf(\OCP\Share\IShare::class, $result); } @@ -932,7 +932,7 @@ class ShareByMailProviderTest extends TestCase { $this->assertTrue(is_array($result)); $this->assertSame(1, count($result)); - $this->assertInstanceOf('OCP\Share\IShare', $result[0]); + $this->assertInstanceOf(\OCP\Share\IShare::class, $result[0]); } public function testGetShareByToken(): void { @@ -961,7 +961,7 @@ class ShareByMailProviderTest extends TestCase { $result = $instance->getShareByToken('token'); - $this->assertInstanceOf('OCP\Share\IShare', $result); + $this->assertInstanceOf(\OCP\Share\IShare::class, $result); } @@ -984,7 +984,7 @@ class ShareByMailProviderTest extends TestCase { $this->assertTrue($idMail !== $idPublic); - $this->assertInstanceOf('OCP\Share\IShare', + $this->assertInstanceOf(\OCP\Share\IShare::class, $instance->getShareByToken('token2') ); } diff --git a/apps/theming/tests/Controller/IconControllerTest.php b/apps/theming/tests/Controller/IconControllerTest.php index 18fa7de1cc8..303a48a6f73 100644 --- a/apps/theming/tests/Controller/IconControllerTest.php +++ b/apps/theming/tests/Controller/IconControllerTest.php @@ -70,7 +70,7 @@ class IconControllerTest extends TestCase { } private function iconFileMock($filename, $data) { - $icon = $this->getMockBuilder('OCP\Files\File')->getMock(); + $icon = $this->getMockBuilder(\OCP\Files\File::class)->getMock(); $icon->expects($this->any())->method('getContent')->willReturn($data); $icon->expects($this->any())->method('getMimeType')->willReturn('image type'); $icon->expects($this->any())->method('getEtag')->willReturn('my etag'); diff --git a/apps/user_ldap/lib/AppInfo/Application.php b/apps/user_ldap/lib/AppInfo/Application.php index 400315442bb..1ed82c02c2b 100644 --- a/apps/user_ldap/lib/AppInfo/Application.php +++ b/apps/user_ldap/lib/AppInfo/Application.php @@ -132,7 +132,7 @@ class Application extends App implements IBootstrap { \OCP\Util::connectHook( '\OCA\Files_Sharing\API\Server2Server', 'preLoginNameUsedAsUserName', - '\OCA\User_LDAP\Helper', + \OCA\User_LDAP\Helper::class, 'loginName2UserName' ); } diff --git a/apps/user_ldap/tests/ConnectionTest.php b/apps/user_ldap/tests/ConnectionTest.php index bc65de39f94..348a8878ea6 100644 --- a/apps/user_ldap/tests/ConnectionTest.php +++ b/apps/user_ldap/tests/ConnectionTest.php @@ -29,7 +29,7 @@ class ConnectionTest extends \Test\TestCase { $this->ldap = $this->createMock(ILDAPWrapper::class); // we use a mock here to replace the cache mechanism, due to missing DI in LDAP backend. - $this->connection = $this->getMockBuilder('OCA\User_LDAP\Connection') + $this->connection = $this->getMockBuilder(\OCA\User_LDAP\Connection::class) ->setMethods(['getFromCache', 'writeToCache']) ->setConstructorArgs([$this->ldap, '', null]) ->getMock(); diff --git a/apps/user_ldap/tests/GroupLDAPPluginTest.php b/apps/user_ldap/tests/GroupLDAPPluginTest.php index f67de32c2e9..496a86ba245 100644 --- a/apps/user_ldap/tests/GroupLDAPPluginTest.php +++ b/apps/user_ldap/tests/GroupLDAPPluginTest.php @@ -20,7 +20,7 @@ class GroupLDAPPluginTest extends \Test\TestCase { public function testImplementsActions(): void { $pluginManager = $this->getGroupPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') + $plugin = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPGroupPluginDummy::class) ->setMethods(['respondToActions']) ->getMock(); @@ -28,7 +28,7 @@ class GroupLDAPPluginTest extends \Test\TestCase { ->method('respondToActions') ->willReturn(GroupInterface::CREATE_GROUP); - $plugin2 = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') + $plugin2 = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPGroupPluginDummy::class) ->setMethods(['respondToActions']) ->getMock(); @@ -47,7 +47,7 @@ class GroupLDAPPluginTest extends \Test\TestCase { public function testCreateGroup(): void { $pluginManager = $this->getGroupPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') + $plugin = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPGroupPluginDummy::class) ->setMethods(['respondToActions', 'createGroup']) ->getMock(); @@ -77,7 +77,7 @@ class GroupLDAPPluginTest extends \Test\TestCase { public function testDeleteGroup(): void { $pluginManager = $this->getGroupPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') + $plugin = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPGroupPluginDummy::class) ->setMethods(['respondToActions', 'deleteGroup']) ->getMock(); @@ -107,7 +107,7 @@ class GroupLDAPPluginTest extends \Test\TestCase { public function testAddToGroup(): void { $pluginManager = $this->getGroupPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') + $plugin = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPGroupPluginDummy::class) ->setMethods(['respondToActions', 'addToGroup']) ->getMock(); @@ -138,7 +138,7 @@ class GroupLDAPPluginTest extends \Test\TestCase { public function testRemoveFromGroup(): void { $pluginManager = $this->getGroupPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') + $plugin = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPGroupPluginDummy::class) ->setMethods(['respondToActions', 'removeFromGroup']) ->getMock(); @@ -169,7 +169,7 @@ class GroupLDAPPluginTest extends \Test\TestCase { public function testCountUsersInGroup(): void { $pluginManager = $this->getGroupPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') + $plugin = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPGroupPluginDummy::class) ->setMethods(['respondToActions', 'countUsersInGroup']) ->getMock(); @@ -200,7 +200,7 @@ class GroupLDAPPluginTest extends \Test\TestCase { public function testgetGroupDetails(): void { $pluginManager = $this->getGroupPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') + $plugin = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPGroupPluginDummy::class) ->setMethods(['respondToActions', 'getGroupDetails']) ->getMock(); diff --git a/apps/user_ldap/tests/LDAPProviderTest.php b/apps/user_ldap/tests/LDAPProviderTest.php index 514cc137954..11097c6acbd 100644 --- a/apps/user_ldap/tests/LDAPProviderTest.php +++ b/apps/user_ldap/tests/LDAPProviderTest.php @@ -1,865 +1,865 @@ -<?php -/** - * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors - * SPDX-License-Identifier: AGPL-3.0-or-later - */ -namespace OCA\User_LDAP\Tests; - -use OC\User\Manager; -use OCA\User_LDAP\Access; -use OCA\User_LDAP\Connection; -use OCA\User_LDAP\Group_LDAP; -use OCA\User_LDAP\IGroupLDAP; -use OCA\User_LDAP\IUserLDAP; -use OCA\User_LDAP\User_LDAP; -use OCP\EventDispatcher\IEventDispatcher; -use OCP\ICacheFactory; -use OCP\IConfig; -use OCP\IServerContainer; - -/** - * Class LDAPProviderTest - * - * @group DB - * - * @package OCA\User_LDAP\Tests - */ -class LDAPProviderTest extends \Test\TestCase { - protected function setUp(): void { - parent::setUp(); - } - - private function getServerMock(IUserLDAP $userBackend, IGroupLDAP $groupBackend) { - $server = $this->getMockBuilder('OC\Server') - ->setMethods(['getUserManager', 'getBackends', 'getGroupManager']) - ->setConstructorArgs(['', new \OC\Config(\OC::$configDir)]) - ->getMock(); - $server->expects($this->any()) - ->method('getUserManager') - ->willReturn($this->getUserManagerMock($userBackend)); - $server->expects($this->any()) - ->method('getGroupManager') - ->willReturn($this->getGroupManagerMock($groupBackend)); - $server->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - - return $server; - } - - private function getUserManagerMock(IUserLDAP $userBackend) { - $userManager = $this->getMockBuilder(Manager::class) - ->setMethods(['getBackends']) - ->setConstructorArgs([ - $this->createMock(IConfig::class), - $this->createMock(ICacheFactory::class), - $this->createMock(IEventDispatcher::class), - ]) - ->getMock(); - $userManager->expects($this->any()) - ->method('getBackends') - ->willReturn([$userBackend]); - return $userManager; - } - - private function getGroupManagerMock(IGroupLDAP $groupBackend) { - $groupManager = $this->getMockBuilder('OC\Group\Manager') - ->setMethods(['getBackends']) - ->disableOriginalConstructor() - ->getMock(); - $groupManager->expects($this->any()) - ->method('getBackends') - ->willReturn([$groupBackend]); - return $groupManager; - } - - private function getDefaultGroupBackendMock() { - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->disableOriginalConstructor() - ->getMock(); - - return $groupBackend; - } - - private function getLDAPProvider(IServerContainer $serverContainer) { - $factory = new \OCA\User_LDAP\LDAPProviderFactory($serverContainer); - return $factory->getLDAPProvider(); - } - - - public function testGetUserDNUserIDNotFound(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('User id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any())->method('userExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getUserDN('nonexisting_user'); - } - - public function testGetUserDN(): void { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'username2dn']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->once()) - ->method('userExists') - ->willReturn(true); - $userBackend->expects($this->once()) - ->method('username2dn') - ->willReturn('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org'); - $userBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org', - $ldapProvider->getUserDN('existing_user')); - } - - - public function testGetGroupDNGroupIDNotFound(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Group id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists']) - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend->expects($this->any())->method('groupExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getGroupDN('nonexisting_group'); - } - - public function testGetGroupDN(): void { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'username2dn']) - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists', 'getLDAPAccess', 'groupname2dn']) - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend->expects($this->once()) - ->method('groupExists') - ->willReturn(true); - $groupBackend->expects($this->once()) - ->method('groupname2dn') - ->willReturn('cn=existing_group,ou=Are Sufficient To,ou=Test,dc=example,dc=org'); - $groupBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals('cn=existing_group,ou=Are Sufficient To,ou=Test,dc=example,dc=org', - $ldapProvider->getGroupDN('existing_group')); - } - - public function testGetUserName(): void { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['dn2UserName']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any()) - ->method('dn2UserName') - ->willReturn('existing_user'); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals('existing_user', - $ldapProvider->getUserName('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org')); - } - - public function testDNasBaseParameter(): void { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods([]) - ->disableOriginalConstructor() - ->getMock(); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $helper = new \OCA\User_LDAP\Helper(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals( - $helper->DNasBaseParameter('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org'), - $ldapProvider->DNasBaseParameter('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org')); - } - - public function testSanitizeDN(): void { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods([]) - ->disableOriginalConstructor() - ->getMock(); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $helper = new \OCA\User_LDAP\Helper(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals( - $helper->sanitizeDN('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org'), - $ldapProvider->sanitizeDN('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org')); - } - - - public function testGetLDAPConnectionUserIDNotFound(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('User id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any())->method('userExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getLDAPConnection('nonexisting_user'); - } - - public function testGetLDAPConnection(): void { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getNewLDAPConnection']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any()) - ->method('userExists') - ->willReturn(true); - $ldapConnection = ldap_connect('ldap://example.com'); - $userBackend->expects($this->any()) - ->method('getNewLDAPConnection') - ->willReturn($ldapConnection); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals($ldapConnection, $ldapProvider->getLDAPConnection('existing_user')); - } - - - public function testGetGroupLDAPConnectionGroupIDNotFound(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Group id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists']) - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend->expects($this->any())->method('groupExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getGroupLDAPConnection('nonexisting_group'); - } - - public function testGetGroupLDAPConnection(): void { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists','getNewLDAPConnection']) - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend->expects($this->any()) - ->method('groupExists') - ->willReturn(true); - - $ldapConnection = ldap_connect('ldap://example.com'); - $groupBackend->expects($this->any()) - ->method('getNewLDAPConnection') - ->willReturn($ldapConnection); - - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals($ldapConnection, $ldapProvider->getGroupLDAPConnection('existing_group')); - } - - - public function testGetLDAPBaseUsersUserIDNotFound(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('User id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any())->method('userExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getLDAPBaseUsers('nonexisting_user'); - } - - public function testGetLDAPBaseUsers(): void { - $bases = [ - 'ou=users,ou=foobar,dc=example,dc=org', - 'ou=users,ou=barfoo,dc=example,dc=org', - ]; - $dn = 'uid=malik,' . $bases[1]; - - $connection = $this->createMock(Connection::class); - $connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($key) use ($bases) { - switch ($key) { - case 'ldapBaseUsers': - return $bases; - } - return null; - }); - - $access = $this->createMock(Access::class); - $access->expects($this->any()) - ->method('getConnection') - ->willReturn($connection); - $access->expects($this->exactly(2)) - ->method('isDNPartOfBase') - ->willReturnOnConsecutiveCalls(false, true); - $access->expects($this->atLeastOnce()) - ->method('username2dn') - ->willReturn($dn); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->atLeastOnce()) - ->method('userExists') - ->willReturn(true); - $userBackend->expects($this->any()) - ->method('getLDAPAccess') - ->willReturn($access); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals($bases[1], $ldapProvider->getLDAPBaseUsers('existing_user')); - } - - - public function testGetLDAPBaseGroupsUserIDNotFound(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('User id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any())->method('userExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getLDAPBaseGroups('nonexisting_user'); - } - - public function testGetLDAPBaseGroups(): void { - $bases = [ - 'ou=groupd,ou=foobar,dc=example,dc=org', - 'ou=groups,ou=barfoo,dc=example,dc=org', - ]; - - $connection = $this->createMock(Connection::class); - $connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($key) use ($bases) { - switch ($key) { - case 'ldapBaseGroups': - return $bases; - } - return null; - }); - - $access = $this->createMock(Access::class); - $access->expects($this->any()) - ->method('getConnection') - ->willReturn($connection); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any()) - ->method('userExists') - ->willReturn(true); - $userBackend->expects($this->any()) - ->method('getLDAPAccess') - ->willReturn($access); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals($bases[0], $ldapProvider->getLDAPBaseGroups('existing_user')); - } - - - public function testClearCacheUserIDNotFound(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('User id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any())->method('userExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->clearCache('nonexisting_user'); - } - - public function testClearCache(): void { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'clearCache']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->once()) - ->method('userExists') - ->willReturn(true); - $userBackend->expects($this->once()) - ->method('clearCache') - ->willReturn(true); - $userBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->clearCache('existing_user'); - $this->addToAssertionCount(1); - } - - - public function testClearGroupCacheGroupIDNotFound(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Group id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists']) - ->disableOriginalConstructor() - ->getMock(); - $groupBackend->expects($this->any())->method('groupExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->clearGroupCache('nonexisting_group'); - } - - public function testClearGroupCache(): void { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists', 'getLDAPAccess', 'getConnection', 'clearCache']) - ->disableOriginalConstructor() - ->getMock(); - $groupBackend->expects($this->once()) - ->method('groupExists') - ->willReturn(true); - $groupBackend->expects($this->once()) - ->method('clearCache') - ->willReturn(true); - $groupBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->clearGroupCache('existing_group'); - $this->addToAssertionCount(1); - } - - public function testDnExists(): void { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['dn2UserName']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any()) - ->method('dn2UserName') - ->willReturn('existing_user'); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertTrue($ldapProvider->dnExists('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org')); - } - - public function testFlagRecord(): void { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods([]) - ->disableOriginalConstructor() - ->getMock(); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->flagRecord('existing_user'); - $this->addToAssertionCount(1); - } - - public function testUnflagRecord(): void { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods([]) - ->disableOriginalConstructor() - ->getMock(); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->unflagRecord('existing_user'); - $this->addToAssertionCount(1); - } - - - public function testGetLDAPDisplayNameFieldUserIDNotFound(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('User id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any())->method('userExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getLDAPDisplayNameField('nonexisting_user'); - } - - public function testGetLDAPDisplayNameField(): void { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->once()) - ->method('userExists') - ->willReturn(true); - $userBackend->expects($this->once()) - ->method('getConfiguration') - ->willReturn(['ldap_display_name' => 'displayName']); - $userBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals('displayName', $ldapProvider->getLDAPDisplayNameField('existing_user')); - } - - - public function testGetLDAPEmailFieldUserIDNotFound(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('User id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any())->method('userExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getLDAPEmailField('nonexisting_user'); - } - - public function testGetLDAPEmailField(): void { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->once()) - ->method('userExists') - ->willReturn(true); - $userBackend->expects($this->once()) - ->method('getConfiguration') - ->willReturn(['ldap_email_attr' => 'mail']); - $userBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals('mail', $ldapProvider->getLDAPEmailField('existing_user')); - } - - - public function testGetLDAPGroupMemberAssocUserIDNotFound(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Group id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists']) - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend->expects($this->any())->method('groupExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getLDAPGroupMemberAssoc('nonexisting_group'); - } - - public function testgetLDAPGroupMemberAssoc(): void { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend->expects($this->once()) - ->method('groupExists') - ->willReturn(true); - $groupBackend->expects($this->any()) - ->method('getConfiguration') - ->willReturn(['ldap_group_member_assoc_attribute' => 'assoc_type']); - $groupBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals('assoc_type', $ldapProvider->getLDAPGroupMemberAssoc('existing_group')); - } - - public function testGetMultiValueUserAttributeUserNotFound(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('User id not found in LDAP'); - - $userBackend = $this->createMock(User_LDAP::class); - $userBackend->expects(self::once()) - ->method('userExists') - ->with('admin') - ->willReturn(false); - $groupBackend = $this->createMock(Group_LDAP::class); - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getMultiValueUserAttribute('admin', 'mailAlias'); - } - - public function testGetMultiValueUserAttributeCacheHit(): void { - $connection = $this->createMock(Connection::class); - $connection->expects(self::once()) - ->method('getFromCache') - ->with('admin-mailAlias') - ->willReturn(['aliasA@test.local', 'aliasB@test.local']); - $access = $this->createMock(Access::class); - $access->expects(self::once()) - ->method('getConnection') - ->willReturn($connection); - $userBackend = $this->createMock(User_LDAP::class); - $userBackend->expects(self::once()) - ->method('userExists') - ->with('admin') - ->willReturn(true); - $userBackend->expects(self::once()) - ->method('getLDAPAccess') - ->willReturn($access); - $groupBackend = $this->createMock(Group_LDAP::class); - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getMultiValueUserAttribute('admin', 'mailAlias'); - } - - public function testGetMultiValueUserAttributeLdapError(): void { - $connection = $this->createMock(Connection::class); - $connection->expects(self::once()) - ->method('getFromCache') - ->with('admin-mailAlias') - ->willReturn(null); - $access = $this->createMock(Access::class); - $access->expects(self::once()) - ->method('getConnection') - ->willReturn($connection); - $access->expects(self::once()) - ->method('username2dn') - ->with('admin') - ->willReturn('admin'); - $access->expects(self::once()) - ->method('readAttribute') - ->with('admin', 'mailAlias') - ->willReturn(false); - $userBackend = $this->getMockBuilder(User_LDAP::class) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->method('userExists') - ->with('admin') - ->willReturn(true); - $userBackend->method('getLDAPAccess') - ->willReturn($access); - $groupBackend = $this->getMockBuilder(Group_LDAP::class) - ->disableOriginalConstructor() - ->getMock(); - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $values = $ldapProvider->getMultiValueUserAttribute('admin', 'mailAlias'); - - self::assertCount(0, $values); - } - - public function testGetMultiValueUserAttribute(): void { - $connection = $this->createMock(Connection::class); - $connection->expects(self::once()) - ->method('getFromCache') - ->with('admin-mailAlias') - ->willReturn(null); - $access = $this->createMock(Access::class); - $access->expects(self::once()) - ->method('getConnection') - ->willReturn($connection); - $access->expects(self::once()) - ->method('username2dn') - ->with('admin') - ->willReturn('admin'); - $access->expects(self::once()) - ->method('readAttribute') - ->with('admin', 'mailAlias') - ->willReturn(['aliasA@test.local', 'aliasB@test.local']); - $userBackend = $this->getMockBuilder(User_LDAP::class) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->method('userExists') - ->with('admin') - ->willReturn(true); - $userBackend->method('getLDAPAccess') - ->willReturn($access); - $groupBackend = $this->getMockBuilder(Group_LDAP::class) - ->disableOriginalConstructor() - ->getMock(); - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $values = $ldapProvider->getMultiValueUserAttribute('admin', 'mailAlias'); - - self::assertCount(2, $values); - } - - public function testGetUserAttributeLdapError(): void { - $connection = $this->createMock(Connection::class); - $connection->expects(self::once()) - ->method('getFromCache') - ->with('admin-mailAlias') - ->willReturn(null); - $access = $this->createMock(Access::class); - $access->expects(self::once()) - ->method('getConnection') - ->willReturn($connection); - $access->expects(self::once()) - ->method('username2dn') - ->with('admin') - ->willReturn('admin'); - $access->expects(self::once()) - ->method('readAttribute') - ->with('admin', 'mailAlias') - ->willReturn(false); - $userBackend = $this->getMockBuilder(User_LDAP::class) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->method('userExists') - ->with('admin') - ->willReturn(true); - $userBackend->method('getLDAPAccess') - ->willReturn($access); - $groupBackend = $this->getMockBuilder(Group_LDAP::class) - ->disableOriginalConstructor() - ->getMock(); - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $value = $ldapProvider->getUserAttribute('admin', 'mailAlias'); - - self::assertNull($value); - } - - public function testGetUserAttribute(): void { - $connection = $this->createMock(Connection::class); - $connection->expects(self::once()) - ->method('getFromCache') - ->with('admin-mailAlias') - ->willReturn(null); - $access = $this->createMock(Access::class); - $access->expects(self::once()) - ->method('getConnection') - ->willReturn($connection); - $access->expects(self::once()) - ->method('username2dn') - ->with('admin') - ->willReturn('admin'); - $access->expects(self::once()) - ->method('readAttribute') - ->with('admin', 'mailAlias') - ->willReturn(['aliasA@test.local', 'aliasB@test.local']); - $userBackend = $this->getMockBuilder(User_LDAP::class) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->method('userExists') - ->with('admin') - ->willReturn(true); - $userBackend->method('getLDAPAccess') - ->willReturn($access); - $groupBackend = $this->getMockBuilder(Group_LDAP::class) - ->disableOriginalConstructor() - ->getMock(); - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $value = $ldapProvider->getUserAttribute('admin', 'mailAlias'); - - self::assertEquals('aliasA@test.local', $value); - } -} +<?php +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\User_LDAP\Tests; + +use OC\User\Manager; +use OCA\User_LDAP\Access; +use OCA\User_LDAP\Connection; +use OCA\User_LDAP\Group_LDAP; +use OCA\User_LDAP\IGroupLDAP; +use OCA\User_LDAP\IUserLDAP; +use OCA\User_LDAP\User_LDAP; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\ICacheFactory; +use OCP\IConfig; +use OCP\IServerContainer; + +/** + * Class LDAPProviderTest + * + * @group DB + * + * @package OCA\User_LDAP\Tests + */ +class LDAPProviderTest extends \Test\TestCase { + protected function setUp(): void { + parent::setUp(); + } + + private function getServerMock(IUserLDAP $userBackend, IGroupLDAP $groupBackend) { + $server = $this->getMockBuilder(\OC\Server::class) + ->setMethods(['getUserManager', 'getBackends', 'getGroupManager']) + ->setConstructorArgs(['', new \OC\Config(\OC::$configDir)]) + ->getMock(); + $server->expects($this->any()) + ->method('getUserManager') + ->willReturn($this->getUserManagerMock($userBackend)); + $server->expects($this->any()) + ->method('getGroupManager') + ->willReturn($this->getGroupManagerMock($groupBackend)); + $server->expects($this->any()) + ->method($this->anything()) + ->willReturnSelf(); + + return $server; + } + + private function getUserManagerMock(IUserLDAP $userBackend) { + $userManager = $this->getMockBuilder(Manager::class) + ->setMethods(['getBackends']) + ->setConstructorArgs([ + $this->createMock(IConfig::class), + $this->createMock(ICacheFactory::class), + $this->createMock(IEventDispatcher::class), + ]) + ->getMock(); + $userManager->expects($this->any()) + ->method('getBackends') + ->willReturn([$userBackend]); + return $userManager; + } + + private function getGroupManagerMock(IGroupLDAP $groupBackend) { + $groupManager = $this->getMockBuilder(\OC\Group\Manager::class) + ->setMethods(['getBackends']) + ->disableOriginalConstructor() + ->getMock(); + $groupManager->expects($this->any()) + ->method('getBackends') + ->willReturn([$groupBackend]); + return $groupManager; + } + + private function getDefaultGroupBackendMock() { + $groupBackend = $this->getMockBuilder(\OCA\User_LDAP\Group_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + + return $groupBackend; + } + + private function getLDAPProvider(IServerContainer $serverContainer) { + $factory = new \OCA\User_LDAP\LDAPProviderFactory($serverContainer); + return $factory->getLDAPProvider(); + } + + + public function testGetUserDNUserIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User id not found in LDAP'); + + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods(['userExists']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->any())->method('userExists')->willReturn(false); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->getUserDN('nonexisting_user'); + } + + public function testGetUserDN(): void { + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods(['userExists', 'getLDAPAccess', 'username2dn']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->once()) + ->method('userExists') + ->willReturn(true); + $userBackend->expects($this->once()) + ->method('username2dn') + ->willReturn('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org'); + $userBackend->expects($this->any()) + ->method($this->anything()) + ->willReturnSelf(); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $this->assertEquals('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org', + $ldapProvider->getUserDN('existing_user')); + } + + + public function testGetGroupDNGroupIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Group id not found in LDAP'); + + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + + $groupBackend = $this->getMockBuilder(\OCA\User_LDAP\Group_LDAP::class) + ->setMethods(['groupExists']) + ->disableOriginalConstructor() + ->getMock(); + + $groupBackend->expects($this->any())->method('groupExists')->willReturn(false); + + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->getGroupDN('nonexisting_group'); + } + + public function testGetGroupDN(): void { + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods(['userExists', 'getLDAPAccess', 'username2dn']) + ->disableOriginalConstructor() + ->getMock(); + + $groupBackend = $this->getMockBuilder(\OCA\User_LDAP\Group_LDAP::class) + ->setMethods(['groupExists', 'getLDAPAccess', 'groupname2dn']) + ->disableOriginalConstructor() + ->getMock(); + + $groupBackend->expects($this->once()) + ->method('groupExists') + ->willReturn(true); + $groupBackend->expects($this->once()) + ->method('groupname2dn') + ->willReturn('cn=existing_group,ou=Are Sufficient To,ou=Test,dc=example,dc=org'); + $groupBackend->expects($this->any()) + ->method($this->anything()) + ->willReturnSelf(); + + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $this->assertEquals('cn=existing_group,ou=Are Sufficient To,ou=Test,dc=example,dc=org', + $ldapProvider->getGroupDN('existing_group')); + } + + public function testGetUserName(): void { + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods(['dn2UserName']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->any()) + ->method('dn2UserName') + ->willReturn('existing_user'); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $this->assertEquals('existing_user', + $ldapProvider->getUserName('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org')); + } + + public function testDNasBaseParameter(): void { + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods([]) + ->disableOriginalConstructor() + ->getMock(); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $helper = new \OCA\User_LDAP\Helper(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()); + + $ldapProvider = $this->getLDAPProvider($server); + $this->assertEquals( + $helper->DNasBaseParameter('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org'), + $ldapProvider->DNasBaseParameter('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org')); + } + + public function testSanitizeDN(): void { + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods([]) + ->disableOriginalConstructor() + ->getMock(); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $helper = new \OCA\User_LDAP\Helper(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()); + + $ldapProvider = $this->getLDAPProvider($server); + $this->assertEquals( + $helper->sanitizeDN('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org'), + $ldapProvider->sanitizeDN('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org')); + } + + + public function testGetLDAPConnectionUserIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User id not found in LDAP'); + + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods(['userExists']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->any())->method('userExists')->willReturn(false); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->getLDAPConnection('nonexisting_user'); + } + + public function testGetLDAPConnection(): void { + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods(['userExists', 'getNewLDAPConnection']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->any()) + ->method('userExists') + ->willReturn(true); + $ldapConnection = ldap_connect('ldap://example.com'); + $userBackend->expects($this->any()) + ->method('getNewLDAPConnection') + ->willReturn($ldapConnection); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $this->assertEquals($ldapConnection, $ldapProvider->getLDAPConnection('existing_user')); + } + + + public function testGetGroupLDAPConnectionGroupIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Group id not found in LDAP'); + + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + + $groupBackend = $this->getMockBuilder(\OCA\User_LDAP\Group_LDAP::class) + ->setMethods(['groupExists']) + ->disableOriginalConstructor() + ->getMock(); + + $groupBackend->expects($this->any())->method('groupExists')->willReturn(false); + + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->getGroupLDAPConnection('nonexisting_group'); + } + + public function testGetGroupLDAPConnection(): void { + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + + $groupBackend = $this->getMockBuilder(\OCA\User_LDAP\Group_LDAP::class) + ->setMethods(['groupExists','getNewLDAPConnection']) + ->disableOriginalConstructor() + ->getMock(); + + $groupBackend->expects($this->any()) + ->method('groupExists') + ->willReturn(true); + + $ldapConnection = ldap_connect('ldap://example.com'); + $groupBackend->expects($this->any()) + ->method('getNewLDAPConnection') + ->willReturn($ldapConnection); + + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $this->assertEquals($ldapConnection, $ldapProvider->getGroupLDAPConnection('existing_group')); + } + + + public function testGetLDAPBaseUsersUserIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User id not found in LDAP'); + + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods(['userExists']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->any())->method('userExists')->willReturn(false); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->getLDAPBaseUsers('nonexisting_user'); + } + + public function testGetLDAPBaseUsers(): void { + $bases = [ + 'ou=users,ou=foobar,dc=example,dc=org', + 'ou=users,ou=barfoo,dc=example,dc=org', + ]; + $dn = 'uid=malik,' . $bases[1]; + + $connection = $this->createMock(Connection::class); + $connection->expects($this->any()) + ->method('__get') + ->willReturnCallback(function ($key) use ($bases) { + switch ($key) { + case 'ldapBaseUsers': + return $bases; + } + return null; + }); + + $access = $this->createMock(Access::class); + $access->expects($this->any()) + ->method('getConnection') + ->willReturn($connection); + $access->expects($this->exactly(2)) + ->method('isDNPartOfBase') + ->willReturnOnConsecutiveCalls(false, true); + $access->expects($this->atLeastOnce()) + ->method('username2dn') + ->willReturn($dn); + + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->atLeastOnce()) + ->method('userExists') + ->willReturn(true); + $userBackend->expects($this->any()) + ->method('getLDAPAccess') + ->willReturn($access); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $this->assertEquals($bases[1], $ldapProvider->getLDAPBaseUsers('existing_user')); + } + + + public function testGetLDAPBaseGroupsUserIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User id not found in LDAP'); + + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods(['userExists']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->any())->method('userExists')->willReturn(false); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->getLDAPBaseGroups('nonexisting_user'); + } + + public function testGetLDAPBaseGroups(): void { + $bases = [ + 'ou=groupd,ou=foobar,dc=example,dc=org', + 'ou=groups,ou=barfoo,dc=example,dc=org', + ]; + + $connection = $this->createMock(Connection::class); + $connection->expects($this->any()) + ->method('__get') + ->willReturnCallback(function ($key) use ($bases) { + switch ($key) { + case 'ldapBaseGroups': + return $bases; + } + return null; + }); + + $access = $this->createMock(Access::class); + $access->expects($this->any()) + ->method('getConnection') + ->willReturn($connection); + + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->any()) + ->method('userExists') + ->willReturn(true); + $userBackend->expects($this->any()) + ->method('getLDAPAccess') + ->willReturn($access); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $this->assertEquals($bases[0], $ldapProvider->getLDAPBaseGroups('existing_user')); + } + + + public function testClearCacheUserIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User id not found in LDAP'); + + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods(['userExists']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->any())->method('userExists')->willReturn(false); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->clearCache('nonexisting_user'); + } + + public function testClearCache(): void { + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'clearCache']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->once()) + ->method('userExists') + ->willReturn(true); + $userBackend->expects($this->once()) + ->method('clearCache') + ->willReturn(true); + $userBackend->expects($this->any()) + ->method($this->anything()) + ->willReturnSelf(); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->clearCache('existing_user'); + $this->addToAssertionCount(1); + } + + + public function testClearGroupCacheGroupIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Group id not found in LDAP'); + + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $groupBackend = $this->getMockBuilder(\OCA\User_LDAP\Group_LDAP::class) + ->setMethods(['groupExists']) + ->disableOriginalConstructor() + ->getMock(); + $groupBackend->expects($this->any())->method('groupExists')->willReturn(false); + + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->clearGroupCache('nonexisting_group'); + } + + public function testClearGroupCache(): void { + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $groupBackend = $this->getMockBuilder(\OCA\User_LDAP\Group_LDAP::class) + ->setMethods(['groupExists', 'getLDAPAccess', 'getConnection', 'clearCache']) + ->disableOriginalConstructor() + ->getMock(); + $groupBackend->expects($this->once()) + ->method('groupExists') + ->willReturn(true); + $groupBackend->expects($this->once()) + ->method('clearCache') + ->willReturn(true); + $groupBackend->expects($this->any()) + ->method($this->anything()) + ->willReturnSelf(); + + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->clearGroupCache('existing_group'); + $this->addToAssertionCount(1); + } + + public function testDnExists(): void { + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods(['dn2UserName']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->any()) + ->method('dn2UserName') + ->willReturn('existing_user'); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $this->assertTrue($ldapProvider->dnExists('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org')); + } + + public function testFlagRecord(): void { + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods([]) + ->disableOriginalConstructor() + ->getMock(); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->flagRecord('existing_user'); + $this->addToAssertionCount(1); + } + + public function testUnflagRecord(): void { + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods([]) + ->disableOriginalConstructor() + ->getMock(); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->unflagRecord('existing_user'); + $this->addToAssertionCount(1); + } + + + public function testGetLDAPDisplayNameFieldUserIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User id not found in LDAP'); + + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods(['userExists']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->any())->method('userExists')->willReturn(false); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->getLDAPDisplayNameField('nonexisting_user'); + } + + public function testGetLDAPDisplayNameField(): void { + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->once()) + ->method('userExists') + ->willReturn(true); + $userBackend->expects($this->once()) + ->method('getConfiguration') + ->willReturn(['ldap_display_name' => 'displayName']); + $userBackend->expects($this->any()) + ->method($this->anything()) + ->willReturnSelf(); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $this->assertEquals('displayName', $ldapProvider->getLDAPDisplayNameField('existing_user')); + } + + + public function testGetLDAPEmailFieldUserIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User id not found in LDAP'); + + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods(['userExists']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->any())->method('userExists')->willReturn(false); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->getLDAPEmailField('nonexisting_user'); + } + + public function testGetLDAPEmailField(): void { + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->once()) + ->method('userExists') + ->willReturn(true); + $userBackend->expects($this->once()) + ->method('getConfiguration') + ->willReturn(['ldap_email_attr' => 'mail']); + $userBackend->expects($this->any()) + ->method($this->anything()) + ->willReturnSelf(); + + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); + + $ldapProvider = $this->getLDAPProvider($server); + $this->assertEquals('mail', $ldapProvider->getLDAPEmailField('existing_user')); + } + + + public function testGetLDAPGroupMemberAssocUserIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Group id not found in LDAP'); + + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + + $groupBackend = $this->getMockBuilder(\OCA\User_LDAP\Group_LDAP::class) + ->setMethods(['groupExists']) + ->disableOriginalConstructor() + ->getMock(); + + $groupBackend->expects($this->any())->method('groupExists')->willReturn(false); + + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->getLDAPGroupMemberAssoc('nonexisting_group'); + } + + public function testgetLDAPGroupMemberAssoc(): void { + $userBackend = $this->getMockBuilder(\OCA\User_LDAP\User_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + + $groupBackend = $this->getMockBuilder(\OCA\User_LDAP\Group_LDAP::class) + ->setMethods(['groupExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) + ->disableOriginalConstructor() + ->getMock(); + + $groupBackend->expects($this->once()) + ->method('groupExists') + ->willReturn(true); + $groupBackend->expects($this->any()) + ->method('getConfiguration') + ->willReturn(['ldap_group_member_assoc_attribute' => 'assoc_type']); + $groupBackend->expects($this->any()) + ->method($this->anything()) + ->willReturnSelf(); + + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $this->assertEquals('assoc_type', $ldapProvider->getLDAPGroupMemberAssoc('existing_group')); + } + + public function testGetMultiValueUserAttributeUserNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User id not found in LDAP'); + + $userBackend = $this->createMock(User_LDAP::class); + $userBackend->expects(self::once()) + ->method('userExists') + ->with('admin') + ->willReturn(false); + $groupBackend = $this->createMock(Group_LDAP::class); + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->getMultiValueUserAttribute('admin', 'mailAlias'); + } + + public function testGetMultiValueUserAttributeCacheHit(): void { + $connection = $this->createMock(Connection::class); + $connection->expects(self::once()) + ->method('getFromCache') + ->with('admin-mailAlias') + ->willReturn(['aliasA@test.local', 'aliasB@test.local']); + $access = $this->createMock(Access::class); + $access->expects(self::once()) + ->method('getConnection') + ->willReturn($connection); + $userBackend = $this->createMock(User_LDAP::class); + $userBackend->expects(self::once()) + ->method('userExists') + ->with('admin') + ->willReturn(true); + $userBackend->expects(self::once()) + ->method('getLDAPAccess') + ->willReturn($access); + $groupBackend = $this->createMock(Group_LDAP::class); + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->getMultiValueUserAttribute('admin', 'mailAlias'); + } + + public function testGetMultiValueUserAttributeLdapError(): void { + $connection = $this->createMock(Connection::class); + $connection->expects(self::once()) + ->method('getFromCache') + ->with('admin-mailAlias') + ->willReturn(null); + $access = $this->createMock(Access::class); + $access->expects(self::once()) + ->method('getConnection') + ->willReturn($connection); + $access->expects(self::once()) + ->method('username2dn') + ->with('admin') + ->willReturn('admin'); + $access->expects(self::once()) + ->method('readAttribute') + ->with('admin', 'mailAlias') + ->willReturn(false); + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->method('userExists') + ->with('admin') + ->willReturn(true); + $userBackend->method('getLDAPAccess') + ->willReturn($access); + $groupBackend = $this->getMockBuilder(Group_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $values = $ldapProvider->getMultiValueUserAttribute('admin', 'mailAlias'); + + self::assertCount(0, $values); + } + + public function testGetMultiValueUserAttribute(): void { + $connection = $this->createMock(Connection::class); + $connection->expects(self::once()) + ->method('getFromCache') + ->with('admin-mailAlias') + ->willReturn(null); + $access = $this->createMock(Access::class); + $access->expects(self::once()) + ->method('getConnection') + ->willReturn($connection); + $access->expects(self::once()) + ->method('username2dn') + ->with('admin') + ->willReturn('admin'); + $access->expects(self::once()) + ->method('readAttribute') + ->with('admin', 'mailAlias') + ->willReturn(['aliasA@test.local', 'aliasB@test.local']); + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->method('userExists') + ->with('admin') + ->willReturn(true); + $userBackend->method('getLDAPAccess') + ->willReturn($access); + $groupBackend = $this->getMockBuilder(Group_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $values = $ldapProvider->getMultiValueUserAttribute('admin', 'mailAlias'); + + self::assertCount(2, $values); + } + + public function testGetUserAttributeLdapError(): void { + $connection = $this->createMock(Connection::class); + $connection->expects(self::once()) + ->method('getFromCache') + ->with('admin-mailAlias') + ->willReturn(null); + $access = $this->createMock(Access::class); + $access->expects(self::once()) + ->method('getConnection') + ->willReturn($connection); + $access->expects(self::once()) + ->method('username2dn') + ->with('admin') + ->willReturn('admin'); + $access->expects(self::once()) + ->method('readAttribute') + ->with('admin', 'mailAlias') + ->willReturn(false); + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->method('userExists') + ->with('admin') + ->willReturn(true); + $userBackend->method('getLDAPAccess') + ->willReturn($access); + $groupBackend = $this->getMockBuilder(Group_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $value = $ldapProvider->getUserAttribute('admin', 'mailAlias'); + + self::assertNull($value); + } + + public function testGetUserAttribute(): void { + $connection = $this->createMock(Connection::class); + $connection->expects(self::once()) + ->method('getFromCache') + ->with('admin-mailAlias') + ->willReturn(null); + $access = $this->createMock(Access::class); + $access->expects(self::once()) + ->method('getConnection') + ->willReturn($connection); + $access->expects(self::once()) + ->method('username2dn') + ->with('admin') + ->willReturn('admin'); + $access->expects(self::once()) + ->method('readAttribute') + ->with('admin', 'mailAlias') + ->willReturn(['aliasA@test.local', 'aliasB@test.local']); + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->method('userExists') + ->with('admin') + ->willReturn(true); + $userBackend->method('getLDAPAccess') + ->willReturn($access); + $groupBackend = $this->getMockBuilder(Group_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $value = $ldapProvider->getUserAttribute('admin', 'mailAlias'); + + self::assertEquals('aliasA@test.local', $value); + } +} diff --git a/apps/user_ldap/tests/UserLDAPPluginTest.php b/apps/user_ldap/tests/UserLDAPPluginTest.php index 5f11f817771..cefc98b3a5e 100644 --- a/apps/user_ldap/tests/UserLDAPPluginTest.php +++ b/apps/user_ldap/tests/UserLDAPPluginTest.php @@ -20,7 +20,7 @@ class UserLDAPPluginTest extends \Test\TestCase { public function testImplementsActions(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') + $plugin = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPUserPluginDummy::class) ->setMethods(['respondToActions']) ->getMock(); @@ -28,7 +28,7 @@ class UserLDAPPluginTest extends \Test\TestCase { ->method('respondToActions') ->willReturn(Backend::CREATE_USER); - $plugin2 = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') + $plugin2 = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPUserPluginDummy::class) ->setMethods(['respondToActions']) ->getMock(); @@ -47,7 +47,7 @@ class UserLDAPPluginTest extends \Test\TestCase { public function testCreateUser(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') + $plugin = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPUserPluginDummy::class) ->setMethods(['respondToActions', 'createUser']) ->getMock(); @@ -78,7 +78,7 @@ class UserLDAPPluginTest extends \Test\TestCase { public function testSetPassword(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') + $plugin = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPUserPluginDummy::class) ->setMethods(['respondToActions', 'setPassword']) ->getMock(); @@ -109,7 +109,7 @@ class UserLDAPPluginTest extends \Test\TestCase { public function testGetHome(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') + $plugin = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPUserPluginDummy::class) ->setMethods(['respondToActions', 'getHome']) ->getMock(); @@ -139,7 +139,7 @@ class UserLDAPPluginTest extends \Test\TestCase { public function testGetDisplayName(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') + $plugin = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPUserPluginDummy::class) ->setMethods(['respondToActions', 'getDisplayName']) ->getMock(); @@ -169,7 +169,7 @@ class UserLDAPPluginTest extends \Test\TestCase { public function testSetDisplayName(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') + $plugin = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPUserPluginDummy::class) ->setMethods(['respondToActions', 'setDisplayName']) ->getMock(); @@ -200,7 +200,7 @@ class UserLDAPPluginTest extends \Test\TestCase { public function testCanChangeAvatar(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') + $plugin = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPUserPluginDummy::class) ->setMethods(['respondToActions', 'canChangeAvatar']) ->getMock(); @@ -230,7 +230,7 @@ class UserLDAPPluginTest extends \Test\TestCase { public function testCountUsers(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') + $plugin = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPUserPluginDummy::class) ->setMethods(['respondToActions', 'countUsers']) ->getMock(); @@ -257,7 +257,7 @@ class UserLDAPPluginTest extends \Test\TestCase { public function testDeleteUser(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') + $plugin = $this->getMockBuilder(\OCA\User_LDAP\Tests\LDAPUserPluginDummy::class) ->setMethods(['respondToActions', 'canDeleteUser','deleteUser']) ->getMock(); diff --git a/apps/user_ldap/tests/WizardTest.php b/apps/user_ldap/tests/WizardTest.php index 31fd28e2fa1..9595af15a99 100644 --- a/apps/user_ldap/tests/WizardTest.php +++ b/apps/user_ldap/tests/WizardTest.php @@ -41,9 +41,9 @@ class WizardTest extends TestCase { static $accMethods; if (is_null($confMethods)) { - $confMethods = get_class_methods('\OCA\User_LDAP\Configuration'); - $connMethods = get_class_methods('\OCA\User_LDAP\Connection'); - $accMethods = get_class_methods('\OCA\User_LDAP\Access'); + $confMethods = get_class_methods(\OCA\User_LDAP\Configuration::class); + $connMethods = get_class_methods(\OCA\User_LDAP\Connection::class); + $accMethods = get_class_methods(\OCA\User_LDAP\Access::class); } /** @var ILDAPWrapper|\PHPUnit\Framework\MockObject\MockObject $lw */ $lw = $this->createMock(ILDAPWrapper::class); diff --git a/apps/workflowengine/tests/Check/AbstractStringCheckTest.php b/apps/workflowengine/tests/Check/AbstractStringCheckTest.php index eb40b164176..e96a3b4cc71 100644 --- a/apps/workflowengine/tests/Check/AbstractStringCheckTest.php +++ b/apps/workflowengine/tests/Check/AbstractStringCheckTest.php @@ -18,7 +18,7 @@ class AbstractStringCheckTest extends \Test\TestCase { return sprintf($string, $args); }); - $check = $this->getMockBuilder('OCA\WorkflowEngine\Check\AbstractStringCheck') + $check = $this->getMockBuilder(\OCA\WorkflowEngine\Check\AbstractStringCheck::class) ->setConstructorArgs([ $l, ]) diff --git a/apps/workflowengine/tests/Check/FileMimeTypeTest.php b/apps/workflowengine/tests/Check/FileMimeTypeTest.php index 1fc5118c5c4..35cd4728ca5 100644 --- a/apps/workflowengine/tests/Check/FileMimeTypeTest.php +++ b/apps/workflowengine/tests/Check/FileMimeTypeTest.php @@ -17,7 +17,7 @@ use Test\TestCase; class TemporaryNoLocal extends Temporary { public function instanceOfStorage($className) { - if ($className === '\OC\Files\Storage\Local') { + if ($className === \OC\Files\Storage\Local::class) { return false; } else { return parent::instanceOfStorage($className); diff --git a/apps/workflowengine/tests/Check/RequestTimeTest.php b/apps/workflowengine/tests/Check/RequestTimeTest.php index 34ea656f416..410378d5839 100644 --- a/apps/workflowengine/tests/Check/RequestTimeTest.php +++ b/apps/workflowengine/tests/Check/RequestTimeTest.php @@ -30,7 +30,7 @@ class RequestTimeTest extends \Test\TestCase { protected function setUp(): void { parent::setUp(); - $this->timeFactory = $this->getMockBuilder('OCP\AppFramework\Utility\ITimeFactory') + $this->timeFactory = $this->getMockBuilder(\OCP\AppFramework\Utility\ITimeFactory::class) ->getMock(); } diff --git a/core/Command/Upgrade.php b/core/Command/Upgrade.php index 7b1526766f3..d367b263ff0 100644 --- a/core/Command/Upgrade.php +++ b/core/Command/Upgrade.php @@ -130,16 +130,16 @@ class Upgrade extends Command { $dispatcher->addListener(RepairErrorEvent::class, $repairListener); - $updater->listen('\OC\Updater', 'maintenanceEnabled', function () use ($output) { + $updater->listen(\OC\Updater::class, 'maintenanceEnabled', function () use ($output) { $output->writeln('<info>Turned on maintenance mode</info>'); }); - $updater->listen('\OC\Updater', 'maintenanceDisabled', function () use ($output) { + $updater->listen(\OC\Updater::class, 'maintenanceDisabled', function () use ($output) { $output->writeln('<info>Turned off maintenance mode</info>'); }); - $updater->listen('\OC\Updater', 'maintenanceActive', function () use ($output) { + $updater->listen(\OC\Updater::class, 'maintenanceActive', function () use ($output) { $output->writeln('<info>Maintenance mode is kept active</info>'); }); - $updater->listen('\OC\Updater', 'updateEnd', + $updater->listen(\OC\Updater::class, 'updateEnd', function ($success) use ($output, $self) { if ($success) { $message = '<info>Update successful</info>'; @@ -148,42 +148,42 @@ class Upgrade extends Command { } $output->writeln($message); }); - $updater->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($output) { + $updater->listen(\OC\Updater::class, 'dbUpgradeBefore', function () use ($output) { $output->writeln('<info>Updating database schema</info>'); }); - $updater->listen('\OC\Updater', 'dbUpgrade', function () use ($output) { + $updater->listen(\OC\Updater::class, 'dbUpgrade', function () use ($output) { $output->writeln('<info>Updated database</info>'); }); - $updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use ($output, &$incompatibleOverwrites) { + $updater->listen(\OC\Updater::class, 'incompatibleAppDisabled', function ($app) use ($output, &$incompatibleOverwrites) { if (!in_array($app, $incompatibleOverwrites)) { $output->writeln('<comment>Disabled incompatible app: ' . $app . '</comment>'); } }); - $updater->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($output) { + $updater->listen(\OC\Updater::class, 'upgradeAppStoreApp', function ($app) use ($output) { $output->writeln('<info>Update app ' . $app . ' from App Store</info>'); }); - $updater->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($output) { + $updater->listen(\OC\Updater::class, 'appSimulateUpdate', function ($app) use ($output) { $output->writeln("<info>Checking whether the database schema for <$app> can be updated (this can take a long time depending on the database size)</info>"); }); - $updater->listen('\OC\Updater', 'appUpgradeStarted', function ($app, $version) use ($output) { + $updater->listen(\OC\Updater::class, 'appUpgradeStarted', function ($app, $version) use ($output) { $output->writeln("<info>Updating <$app> ...</info>"); }); - $updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($output) { + $updater->listen(\OC\Updater::class, 'appUpgrade', function ($app, $version) use ($output) { $output->writeln("<info>Updated <$app> to $version</info>"); }); - $updater->listen('\OC\Updater', 'failure', function ($message) use ($output, $self) { + $updater->listen(\OC\Updater::class, 'failure', function ($message) use ($output, $self) { $output->writeln("<error>$message</error>"); }); - $updater->listen('\OC\Updater', 'setDebugLogLevel', function ($logLevel, $logLevelName) use ($output) { + $updater->listen(\OC\Updater::class, 'setDebugLogLevel', function ($logLevel, $logLevelName) use ($output) { $output->writeln('<info>Setting log level to debug</info>'); }); - $updater->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($output) { + $updater->listen(\OC\Updater::class, 'resetLogLevel', function ($logLevel, $logLevelName) use ($output) { $output->writeln('<info>Resetting log level</info>'); }); - $updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($output) { + $updater->listen(\OC\Updater::class, 'startCheckCodeIntegrity', function () use ($output) { $output->writeln('<info>Starting code integrity check...</info>'); }); - $updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($output) { + $updater->listen(\OC\Updater::class, 'finishedCheckCodeIntegrity', function () use ($output) { $output->writeln('<info>Finished code integrity check</info>'); }); diff --git a/core/Controller/OCMController.php b/core/Controller/OCMController.php index d79b5b1669e..524313552d1 100644 --- a/core/Controller/OCMController.php +++ b/core/Controller/OCMController.php @@ -57,7 +57,7 @@ class OCMController extends Controller { $this->config->getAppValue( 'core', 'ocm_providers', - '\OCA\CloudFederationAPI\Capabilities' + \OCA\CloudFederationAPI\Capabilities::class ) ); diff --git a/core/ajax/update.php b/core/ajax/update.php index 575a1f159e5..49fe5ec3bbf 100644 --- a/core/ajax/update.php +++ b/core/ajax/update.php @@ -117,50 +117,50 @@ if (\OCP\Util::needUpgrade()) { $dispatcher->addListener(RepairWarningEvent::class, [$feedBack, 'handleRepairFeedback']); $dispatcher->addListener(RepairErrorEvent::class, [$feedBack, 'handleRepairFeedback']); - $updater->listen('\OC\Updater', 'maintenanceEnabled', function () use ($eventSource, $l) { + $updater->listen(\OC\Updater::class, 'maintenanceEnabled', function () use ($eventSource, $l) { $eventSource->send('success', $l->t('Turned on maintenance mode')); }); - $updater->listen('\OC\Updater', 'maintenanceDisabled', function () use ($eventSource, $l) { + $updater->listen(\OC\Updater::class, 'maintenanceDisabled', function () use ($eventSource, $l) { $eventSource->send('success', $l->t('Turned off maintenance mode')); }); - $updater->listen('\OC\Updater', 'maintenanceActive', function () use ($eventSource, $l) { + $updater->listen(\OC\Updater::class, 'maintenanceActive', function () use ($eventSource, $l) { $eventSource->send('success', $l->t('Maintenance mode is kept active')); }); - $updater->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($eventSource, $l) { + $updater->listen(\OC\Updater::class, 'dbUpgradeBefore', function () use ($eventSource, $l) { $eventSource->send('success', $l->t('Updating database schema')); }); - $updater->listen('\OC\Updater', 'dbUpgrade', function () use ($eventSource, $l) { + $updater->listen(\OC\Updater::class, 'dbUpgrade', function () use ($eventSource, $l) { $eventSource->send('success', $l->t('Updated database')); }); - $updater->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($eventSource, $l) { + $updater->listen(\OC\Updater::class, 'upgradeAppStoreApp', function ($app) use ($eventSource, $l) { $eventSource->send('success', $l->t('Update app "%s" from App Store', [$app])); }); - $updater->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($eventSource, $l) { + $updater->listen(\OC\Updater::class, 'appSimulateUpdate', function ($app) use ($eventSource, $l) { $eventSource->send('success', $l->t('Checking whether the database schema for %s can be updated (this can take a long time depending on the database size)', [$app])); }); - $updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($eventSource, $l) { + $updater->listen(\OC\Updater::class, 'appUpgrade', function ($app, $version) use ($eventSource, $l) { $eventSource->send('success', $l->t('Updated "%1$s" to %2$s', [$app, $version])); }); - $updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use (&$incompatibleApps, &$incompatibleOverwrites) { + $updater->listen(\OC\Updater::class, 'incompatibleAppDisabled', function ($app) use (&$incompatibleApps, &$incompatibleOverwrites) { if (!in_array($app, $incompatibleOverwrites)) { $incompatibleApps[] = $app; } }); - $updater->listen('\OC\Updater', 'failure', function ($message) use ($eventSource, $config) { + $updater->listen(\OC\Updater::class, 'failure', function ($message) use ($eventSource, $config) { $eventSource->send('failure', $message); $eventSource->close(); $config->setSystemValue('maintenance', false); }); - $updater->listen('\OC\Updater', 'setDebugLogLevel', function ($logLevel, $logLevelName) use ($eventSource, $l) { + $updater->listen(\OC\Updater::class, 'setDebugLogLevel', function ($logLevel, $logLevelName) use ($eventSource, $l) { $eventSource->send('success', $l->t('Set log level to debug')); }); - $updater->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($eventSource, $l) { + $updater->listen(\OC\Updater::class, 'resetLogLevel', function ($logLevel, $logLevelName) use ($eventSource, $l) { $eventSource->send('success', $l->t('Reset log level')); }); - $updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($eventSource, $l) { + $updater->listen(\OC\Updater::class, 'startCheckCodeIntegrity', function () use ($eventSource, $l) { $eventSource->send('success', $l->t('Starting code integrity check')); }); - $updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($eventSource, $l) { + $updater->listen(\OC\Updater::class, 'finishedCheckCodeIntegrity', function () use ($eventSource, $l) { $eventSource->send('success', $l->t('Finished code integrity check')); }); diff --git a/lib/autoloader.php b/lib/autoloader.php index 41b272a457c..333718ef4d2 100644 --- a/lib/autoloader.php +++ b/lib/autoloader.php @@ -97,7 +97,7 @@ class Autoloader { } catch (AppPathNotFoundException) { // App not found, ignore } - } elseif ($class === 'Test\\TestCase') { + } elseif ($class === \Test\TestCase::class) { // This File is considered public API, so we make sure that the class // can still be loaded, although the PSR-4 paths have not been loaded. $paths[] = \OC::$SERVERROOT . '/tests/lib/TestCase.php'; diff --git a/lib/base.php b/lib/base.php index 1f9caf473e2..5958f0b714a 100644 --- a/lib/base.php +++ b/lib/base.php @@ -725,7 +725,7 @@ class OC { \OCP\Util::connectHook( '\OCA\Files_Sharing\API\Server2Server', 'preLoginNameUsedAsUserName', - '\OC\User\Database', + \OC\User\Database::class, 'preLoginNameUsedAsUserName' ); @@ -866,7 +866,7 @@ class OC { \OCP\Util::connectHook(Share::class, 'post_shared', HookManager::class, 'postShared'); \OCP\Util::connectHook(Share::class, 'post_unshare', HookManager::class, 'postUnshared'); \OCP\Util::connectHook('OC_Filesystem', 'post_rename', HookManager::class, 'postRename'); - \OCP\Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', HookManager::class, 'postRestore'); + \OCP\Util::connectHook(\OCA\Files_Trashbin\Trashbin::class, 'post_restore', HookManager::class, 'postRestore'); } } diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php index a96e050c0e6..cff8b5fe438 100644 --- a/lib/private/AppFramework/DependencyInjection/DIContainer.php +++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php @@ -389,7 +389,7 @@ class DIContainer extends SimpleContainer implements IAppContainer { * @param string $serviceName e.g. 'OCA\Files\Capabilities' */ public function registerCapability($serviceName) { - $this->query('OC\CapabilitiesManager')->registerCapability(function () use ($serviceName) { + $this->query(\OC\CapabilitiesManager::class)->registerCapability(function () use ($serviceName) { return $this->query($serviceName); }); } diff --git a/lib/private/Encryption/DecryptAll.php b/lib/private/Encryption/DecryptAll.php index 0007467298c..d72cfa6c925 100644 --- a/lib/private/Encryption/DecryptAll.php +++ b/lib/private/Encryption/DecryptAll.php @@ -173,7 +173,7 @@ class DecryptAll { $content = $this->rootView->getDirectoryContent($root); foreach ($content as $file) { // only decrypt files owned by the user - if ($file->getStorage()->instanceOfStorage('OCA\Files_Sharing\SharedStorage')) { + if ($file->getStorage()->instanceOfStorage(\OCA\Files_Sharing\SharedStorage::class)) { continue; } $path = $root . '/' . $file['name']; diff --git a/lib/private/Encryption/Util.php b/lib/private/Encryption/Util.php index 1fb08b15696..0e65d4c2238 100644 --- a/lib/private/Encryption/Util.php +++ b/lib/private/Encryption/Util.php @@ -92,7 +92,7 @@ class Util { if (isset($header[$encryptionModuleKey])) { $id = $header[$encryptionModuleKey]; } elseif (isset($header['cipher'])) { - if (class_exists('\OCA\Encryption\Crypto\Encryption')) { + if (class_exists(\OCA\Encryption\Crypto\Encryption::class)) { // fall back to default encryption if the user migrated from // ownCloud <= 8.0 with the old encryption $id = \OCA\Encryption\Crypto\Encryption::ID; diff --git a/lib/private/Files/Cache/Scanner.php b/lib/private/Files/Cache/Scanner.php index c85104ac4b9..92ea035124c 100644 --- a/lib/private/Files/Cache/Scanner.php +++ b/lib/private/Files/Cache/Scanner.php @@ -125,7 +125,7 @@ class Scanner extends BasicEmitter implements IScanner { if (!self::isPartialFile($file)) { // acquire a lock if ($lock) { - if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + if ($this->storage->instanceOfStorage(\OCP\Files\Storage\ILockingStorage::class)) { $this->storage->acquireLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider); } } @@ -134,7 +134,7 @@ class Scanner extends BasicEmitter implements IScanner { $data = $data ?? $this->getData($file); } catch (ForbiddenException $e) { if ($lock) { - if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + if ($this->storage->instanceOfStorage(\OCP\Files\Storage\ILockingStorage::class)) { $this->storage->releaseLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider); } } @@ -146,8 +146,8 @@ class Scanner extends BasicEmitter implements IScanner { if ($data) { // pre-emit only if it was a file. By that we avoid counting/treating folders as files if ($data['mimetype'] !== 'httpd/unix-directory') { - $this->emit('\OC\Files\Cache\Scanner', 'scanFile', [$file, $this->storageId]); - \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', ['path' => $file, 'storage' => $this->storageId]); + $this->emit(\OC\Files\Cache\Scanner::class, 'scanFile', [$file, $this->storageId]); + \OC_Hook::emit(\OC\Files\Cache\Scanner::class, 'scan_file', ['path' => $file, 'storage' => $this->storageId]); } $parent = dirname($file); @@ -225,15 +225,15 @@ class Scanner extends BasicEmitter implements IScanner { // post-emit only if it was a file. By that we avoid counting/treating folders as files if ($data['mimetype'] !== 'httpd/unix-directory') { - $this->emit('\OC\Files\Cache\Scanner', 'postScanFile', [$file, $this->storageId]); - \OC_Hook::emit('\OC\Files\Cache\Scanner', 'post_scan_file', ['path' => $file, 'storage' => $this->storageId]); + $this->emit(\OC\Files\Cache\Scanner::class, 'postScanFile', [$file, $this->storageId]); + \OC_Hook::emit(\OC\Files\Cache\Scanner::class, 'post_scan_file', ['path' => $file, 'storage' => $this->storageId]); } } else { $this->removeFromCache($file); } } catch (\Exception $e) { if ($lock) { - if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + if ($this->storage->instanceOfStorage(\OCP\Files\Storage\ILockingStorage::class)) { $this->storage->releaseLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider); } } @@ -242,7 +242,7 @@ class Scanner extends BasicEmitter implements IScanner { // release the acquired lock if ($lock) { - if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + if ($this->storage->instanceOfStorage(\OCP\Files\Storage\ILockingStorage::class)) { $this->storage->releaseLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider); } } @@ -258,7 +258,7 @@ class Scanner extends BasicEmitter implements IScanner { protected function removeFromCache($path) { \OC_Hook::emit('Scanner', 'removeFromCache', ['file' => $path]); - $this->emit('\OC\Files\Cache\Scanner', 'removeFromCache', [$path]); + $this->emit(\OC\Files\Cache\Scanner::class, 'removeFromCache', [$path]); if ($this->cacheActive) { $this->cache->remove($path); } @@ -275,7 +275,7 @@ class Scanner extends BasicEmitter implements IScanner { $data['permissions'] = $data['scan_permissions']; } \OC_Hook::emit('Scanner', 'addToCache', ['file' => $path, 'data' => $data]); - $this->emit('\OC\Files\Cache\Scanner', 'addToCache', [$path, $this->storageId, $data, $fileId]); + $this->emit(\OC\Files\Cache\Scanner::class, 'addToCache', [$path, $this->storageId, $data, $fileId]); if ($this->cacheActive) { if ($fileId !== -1) { $this->cache->update($fileId, $data); @@ -295,7 +295,7 @@ class Scanner extends BasicEmitter implements IScanner { */ protected function updateCache($path, $data, $fileId = -1) { \OC_Hook::emit('Scanner', 'addToCache', ['file' => $path, 'data' => $data]); - $this->emit('\OC\Files\Cache\Scanner', 'updateCache', [$path, $this->storageId, $data]); + $this->emit(\OC\Files\Cache\Scanner::class, 'updateCache', [$path, $this->storageId, $data]); if ($this->cacheActive) { if ($fileId !== -1) { $this->cache->update($fileId, $data); @@ -319,7 +319,7 @@ class Scanner extends BasicEmitter implements IScanner { $reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : self::REUSE_ETAG; } if ($lock) { - if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + if ($this->storage->instanceOfStorage(\OCP\Files\Storage\ILockingStorage::class)) { $this->storage->acquireLock('scanner::' . $path, ILockingProvider::LOCK_EXCLUSIVE, $this->lockingProvider); $this->storage->acquireLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider); } @@ -337,7 +337,7 @@ class Scanner extends BasicEmitter implements IScanner { } } finally { if ($lock) { - if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + if ($this->storage->instanceOfStorage(\OCP\Files\Storage\ILockingStorage::class)) { $this->storage->releaseLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider); $this->storage->releaseLock('scanner::' . $path, ILockingProvider::LOCK_EXCLUSIVE, $this->lockingProvider); } @@ -420,7 +420,7 @@ class Scanner extends BasicEmitter implements IScanner { if ($reuse === -1) { $reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : self::REUSE_ETAG; } - $this->emit('\OC\Files\Cache\Scanner', 'scanFolder', [$path, $this->storageId]); + $this->emit(\OC\Files\Cache\Scanner::class, 'scanFolder', [$path, $this->storageId]); $size = 0; $childQueue = $this->handleChildren($path, $recursive, $reuse, $folderId, $lock, $size, $etagChanged); @@ -455,7 +455,7 @@ class Scanner extends BasicEmitter implements IScanner { } } } - $this->emit('\OC\Files\Cache\Scanner', 'postScanFolder', [$path, $this->storageId]); + $this->emit(\OC\Files\Cache\Scanner::class, 'postScanFolder', [$path, $this->storageId]); return $size; } @@ -489,7 +489,7 @@ class Scanner extends BasicEmitter implements IScanner { if (trim($originalFile, '/') !== $file) { // encoding mismatch, might require compatibility wrapper \OC::$server->get(LoggerInterface::class)->debug('Scanner: Skipping non-normalized file name "'. $originalFile . '" in path "' . $path . '".', ['app' => 'core']); - $this->emit('\OC\Files\Cache\Scanner', 'normalizedNameMismatch', [$path ? $path . '/' . $originalFile : $originalFile]); + $this->emit(\OC\Files\Cache\Scanner::class, 'normalizedNameMismatch', [$path ? $path . '/' . $originalFile : $originalFile]); // skip this entry continue; } diff --git a/lib/private/Files/Config/MountProviderCollection.php b/lib/private/Files/Config/MountProviderCollection.php index 1dbc469c8c3..d54be1996aa 100644 --- a/lib/private/Files/Config/MountProviderCollection.php +++ b/lib/private/Files/Config/MountProviderCollection.php @@ -112,10 +112,10 @@ class MountProviderCollection implements IMountProviderCollection, Emitter { $providers = $this->providers; } $firstProviders = array_filter($providers, function (IMountProvider $provider) { - return (get_class($provider) !== 'OCA\Files_Sharing\MountProvider'); + return (get_class($provider) !== \OCA\Files_Sharing\MountProvider::class); }); $lastProviders = array_filter($providers, function (IMountProvider $provider) { - return (get_class($provider) === 'OCA\Files_Sharing\MountProvider'); + return (get_class($provider) === \OCA\Files_Sharing\MountProvider::class); }); foreach ($firstProviders as $provider) { $mounts = $this->getMountsFromProvider($provider, $user, $this->loader); diff --git a/lib/private/Files/Mount/CacheMountProvider.php b/lib/private/Files/Mount/CacheMountProvider.php index 27c7eec9da3..a3bbc6f9035 100644 --- a/lib/private/Files/Mount/CacheMountProvider.php +++ b/lib/private/Files/Mount/CacheMountProvider.php @@ -47,8 +47,8 @@ class CacheMountProvider implements IMountProvider { } return [ - new MountPoint('\OC\Files\Storage\Local', '/' . $user->getUID() . '/cache', ['datadir' => $cacheDir], $loader, null, null, self::class), - new MountPoint('\OC\Files\Storage\Local', '/' . $user->getUID() . '/uploads', ['datadir' => $cacheDir . '/uploads'], $loader, null, null, self::class) + new MountPoint(\OC\Files\Storage\Local::class, '/' . $user->getUID() . '/cache', ['datadir' => $cacheDir], $loader, null, null, self::class), + new MountPoint(\OC\Files\Storage\Local::class, '/' . $user->getUID() . '/uploads', ['datadir' => $cacheDir . '/uploads'], $loader, null, null, self::class) ]; } else { return []; diff --git a/lib/private/Files/Mount/LocalHomeMountProvider.php b/lib/private/Files/Mount/LocalHomeMountProvider.php index a2b3d3b2a99..857542988a9 100644 --- a/lib/private/Files/Mount/LocalHomeMountProvider.php +++ b/lib/private/Files/Mount/LocalHomeMountProvider.php @@ -24,6 +24,6 @@ class LocalHomeMountProvider implements IHomeMountProvider { */ public function getHomeMountForUser(IUser $user, IStorageFactory $loader) { $arguments = ['user' => $user]; - return new HomeMountPoint($user, '\OC\Files\Storage\Home', '/' . $user->getUID(), $arguments, $loader, null, null, self::class); + return new HomeMountPoint($user, \OC\Files\Storage\Home::class, '/' . $user->getUID(), $arguments, $loader, null, null, self::class); } } diff --git a/lib/private/Files/Mount/ObjectHomeMountProvider.php b/lib/private/Files/Mount/ObjectHomeMountProvider.php index 99c52108fa8..cd069c73f4c 100644 --- a/lib/private/Files/Mount/ObjectHomeMountProvider.php +++ b/lib/private/Files/Mount/ObjectHomeMountProvider.php @@ -48,7 +48,7 @@ class ObjectHomeMountProvider implements IHomeMountProvider { return null; } - return new HomeMountPoint($user, '\OC\Files\ObjectStore\HomeObjectStoreStorage', '/' . $user->getUID(), $config['arguments'], $loader, null, null, self::class); + return new HomeMountPoint($user, \OC\Files\ObjectStore\HomeObjectStoreStorage::class, '/' . $user->getUID(), $config['arguments'], $loader, null, null, self::class); } /** diff --git a/lib/private/Files/Storage/Common.php b/lib/private/Files/Storage/Common.php index cefba66683b..e3e1b7b0bee 100644 --- a/lib/private/Files/Storage/Common.php +++ b/lib/private/Files/Storage/Common.php @@ -470,7 +470,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage { public function instanceOfStorage($class) { if (ltrim($class, '\\') === 'OC\Files\Storage\Shared') { // FIXME Temporary fix to keep existing checks working - $class = '\OCA\Files_Sharing\SharedStorage'; + $class = \OCA\Files_Sharing\SharedStorage::class; } return is_a($this, $class); } diff --git a/lib/private/Files/Storage/Wrapper/Wrapper.php b/lib/private/Files/Storage/Wrapper/Wrapper.php index f8aa9d963dc..6cb371a7876 100644 --- a/lib/private/Files/Storage/Wrapper/Wrapper.php +++ b/lib/private/Files/Storage/Wrapper/Wrapper.php @@ -474,7 +474,7 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea public function instanceOfStorage($class) { if (ltrim($class, '\\') === 'OC\Files\Storage\Shared') { // FIXME Temporary fix to keep existing checks working - $class = '\OCA\Files_Sharing\SharedStorage'; + $class = \OCA\Files_Sharing\SharedStorage::class; } return is_a($this, $class) or $this->getWrapperStorage()->instanceOfStorage($class); } @@ -588,7 +588,7 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea * @throws \OCP\Lock\LockedException */ public function acquireLock($path, $type, ILockingProvider $provider) { - if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + if ($this->getWrapperStorage()->instanceOfStorage(\OCP\Files\Storage\ILockingStorage::class)) { $this->getWrapperStorage()->acquireLock($path, $type, $provider); } } @@ -599,7 +599,7 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea * @param \OCP\Lock\ILockingProvider $provider */ public function releaseLock($path, $type, ILockingProvider $provider) { - if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + if ($this->getWrapperStorage()->instanceOfStorage(\OCP\Files\Storage\ILockingStorage::class)) { $this->getWrapperStorage()->releaseLock($path, $type, $provider); } } @@ -610,7 +610,7 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea * @param \OCP\Lock\ILockingProvider $provider */ public function changeLock($path, $type, ILockingProvider $provider) { - if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + if ($this->getWrapperStorage()->instanceOfStorage(\OCP\Files\Storage\ILockingStorage::class)) { $this->getWrapperStorage()->changeLock($path, $type, $provider); } } diff --git a/lib/private/Files/Utils/Scanner.php b/lib/private/Files/Utils/Scanner.php index bcc54dea0dc..9f6bcbde84d 100644 --- a/lib/private/Files/Utils/Scanner.php +++ b/lib/private/Files/Utils/Scanner.php @@ -107,24 +107,24 @@ class Scanner extends PublicEmitter { */ protected function attachListener($mount) { $scanner = $mount->getStorage()->getScanner(); - $scanner->listen('\OC\Files\Cache\Scanner', 'scanFile', function ($path) use ($mount) { - $this->emit('\OC\Files\Utils\Scanner', 'scanFile', [$mount->getMountPoint() . $path]); + $scanner->listen(\OC\Files\Cache\Scanner::class, 'scanFile', function ($path) use ($mount) { + $this->emit(\OC\Files\Utils\Scanner::class, 'scanFile', [$mount->getMountPoint() . $path]); $this->dispatcher->dispatchTyped(new BeforeFileScannedEvent($mount->getMountPoint() . $path)); }); - $scanner->listen('\OC\Files\Cache\Scanner', 'scanFolder', function ($path) use ($mount) { - $this->emit('\OC\Files\Utils\Scanner', 'scanFolder', [$mount->getMountPoint() . $path]); + $scanner->listen(\OC\Files\Cache\Scanner::class, 'scanFolder', function ($path) use ($mount) { + $this->emit(\OC\Files\Utils\Scanner::class, 'scanFolder', [$mount->getMountPoint() . $path]); $this->dispatcher->dispatchTyped(new BeforeFolderScannedEvent($mount->getMountPoint() . $path)); }); - $scanner->listen('\OC\Files\Cache\Scanner', 'postScanFile', function ($path) use ($mount) { - $this->emit('\OC\Files\Utils\Scanner', 'postScanFile', [$mount->getMountPoint() . $path]); + $scanner->listen(\OC\Files\Cache\Scanner::class, 'postScanFile', function ($path) use ($mount) { + $this->emit(\OC\Files\Utils\Scanner::class, 'postScanFile', [$mount->getMountPoint() . $path]); $this->dispatcher->dispatchTyped(new FileScannedEvent($mount->getMountPoint() . $path)); }); - $scanner->listen('\OC\Files\Cache\Scanner', 'postScanFolder', function ($path) use ($mount) { - $this->emit('\OC\Files\Utils\Scanner', 'postScanFolder', [$mount->getMountPoint() . $path]); + $scanner->listen(\OC\Files\Cache\Scanner::class, 'postScanFolder', function ($path) use ($mount) { + $this->emit(\OC\Files\Utils\Scanner::class, 'postScanFolder', [$mount->getMountPoint() . $path]); $this->dispatcher->dispatchTyped(new FolderScannedEvent($mount->getMountPoint() . $path)); }); - $scanner->listen('\OC\Files\Cache\Scanner', 'normalizedNameMismatch', function ($path) use ($mount) { - $this->emit('\OC\Files\Utils\Scanner', 'normalizedNameMismatch', [$path]); + $scanner->listen(\OC\Files\Cache\Scanner::class, 'normalizedNameMismatch', function ($path) use ($mount) { + $this->emit(\OC\Files\Utils\Scanner::class, 'normalizedNameMismatch', [$path]); }); } @@ -148,13 +148,13 @@ class Scanner extends PublicEmitter { $scanner = $storage->getScanner(); $this->attachListener($mount); - $scanner->listen('\OC\Files\Cache\Scanner', 'removeFromCache', function ($path) use ($storage) { + $scanner->listen(\OC\Files\Cache\Scanner::class, 'removeFromCache', function ($path) use ($storage) { $this->triggerPropagator($storage, $path); }); - $scanner->listen('\OC\Files\Cache\Scanner', 'updateCache', function ($path) use ($storage) { + $scanner->listen(\OC\Files\Cache\Scanner::class, 'updateCache', function ($path) use ($storage) { $this->triggerPropagator($storage, $path); }); - $scanner->listen('\OC\Files\Cache\Scanner', 'addToCache', function ($path) use ($storage) { + $scanner->listen(\OC\Files\Cache\Scanner::class, 'addToCache', function ($path) use ($storage) { $this->triggerPropagator($storage, $path); }); @@ -225,15 +225,15 @@ class Scanner extends PublicEmitter { $scanner->setUseTransactions(false); $this->attachListener($mount); - $scanner->listen('\OC\Files\Cache\Scanner', 'removeFromCache', function ($path) use ($storage) { + $scanner->listen(\OC\Files\Cache\Scanner::class, 'removeFromCache', function ($path) use ($storage) { $this->postProcessEntry($storage, $path); $this->dispatcher->dispatchTyped(new NodeRemovedFromCache($storage, $path)); }); - $scanner->listen('\OC\Files\Cache\Scanner', 'updateCache', function ($path) use ($storage) { + $scanner->listen(\OC\Files\Cache\Scanner::class, 'updateCache', function ($path) use ($storage) { $this->postProcessEntry($storage, $path); $this->dispatcher->dispatchTyped(new FileCacheUpdated($storage, $path)); }); - $scanner->listen('\OC\Files\Cache\Scanner', 'addToCache', function ($path, $storageId, $data, $fileId) use ($storage) { + $scanner->listen(\OC\Files\Cache\Scanner::class, 'addToCache', function ($path, $storageId, $data, $fileId) use ($storage) { $this->postProcessEntry($storage, $path); if ($fileId) { $this->dispatcher->dispatchTyped(new FileCacheUpdated($storage, $path)); @@ -261,7 +261,7 @@ class Scanner extends PublicEmitter { $propagator->commitBatch(); } catch (StorageNotAvailableException $e) { $this->logger->error('Storage ' . $storage->getId() . ' not available', ['exception' => $e]); - $this->emit('\OC\Files\Utils\Scanner', 'StorageNotAvailable', [$e]); + $this->emit(\OC\Files\Utils\Scanner::class, 'StorageNotAvailable', [$e]); } if ($this->useTransaction) { $this->db->commit(); diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php index 336349c680b..e8fabf759d5 100644 --- a/lib/private/Files/View.php +++ b/lib/private/Files/View.php @@ -1948,7 +1948,7 @@ class View { $mount = $this->getMountForLock($absolutePath, $lockMountPoint); try { $storage = $mount->getStorage(); - if ($storage && $storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + if ($storage && $storage->instanceOfStorage(\OCP\Files\Storage\ILockingStorage::class)) { $storage->acquireLock( $mount->getInternalPath($absolutePath), $type, @@ -1988,7 +1988,7 @@ class View { $mount = $this->getMountForLock($absolutePath, $lockMountPoint); try { $storage = $mount->getStorage(); - if ($storage && $storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + if ($storage && $storage->instanceOfStorage(\OCP\Files\Storage\ILockingStorage::class)) { $storage->changeLock( $mount->getInternalPath($absolutePath), $type, @@ -2034,7 +2034,7 @@ class View { $mount = $this->getMountForLock($absolutePath, $lockMountPoint); $storage = $mount->getStorage(); - if ($storage && $storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + if ($storage && $storage->instanceOfStorage(\OCP\Files\Storage\ILockingStorage::class)) { $storage->releaseLock( $mount->getInternalPath($absolutePath), $type, diff --git a/lib/private/Server.php b/lib/private/Server.php index c514a4b93ff..3288b0cc87e 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -1143,7 +1143,7 @@ class Server extends ServerContainer implements IServerContainer { $this->registerAlias(\OC_Defaults::class, 'ThemingDefaults'); $this->registerService('ThemingDefaults', function (Server $c) { try { - $classExists = class_exists('OCA\Theming\ThemingDefaults'); + $classExists = class_exists(\OCA\Theming\ThemingDefaults::class); } catch (\OCP\AutoloadNotAllowedException $e) { // App disabled or in maintenance mode $classExists = false; diff --git a/lib/private/Share/Share.php b/lib/private/Share/Share.php index 0af264fb968..684cd7d4b06 100644 --- a/lib/private/Share/Share.php +++ b/lib/private/Share/Share.php @@ -80,20 +80,20 @@ class Share extends Constants { if (!(self::$backends[$itemType] instanceof \OCP\Share_Backend)) { $message = 'Sharing backend %s must implement the interface OCP\Share_Backend'; $message_t = $l->t('Sharing backend %s must implement the interface OCP\Share_Backend', [$class]); - $logger->error(sprintf($message, $class), ['app' => 'OCP\Share']); + $logger->error(sprintf($message, $class), ['app' => \OCP\Share::class]); throw new \Exception($message_t); } return self::$backends[$itemType]; } else { $message = 'Sharing backend %s not found'; $message_t = $l->t('Sharing backend %s not found', [$class]); - $logger->error(sprintf($message, $class), ['app' => 'OCP\Share']); + $logger->error(sprintf($message, $class), ['app' => \OCP\Share::class]); throw new \Exception($message_t); } } $message = 'Sharing backend for %s not found'; $message_t = $l->t('Sharing backend for %s not found', [$itemType]); - $logger->error(sprintf($message, $itemType), ['app' => 'OCP\Share']); + $logger->error(sprintf($message, $itemType), ['app' => \OCP\Share::class]); throw new \Exception($message_t); } diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php index 5457e8024a4..5dcfcb1050f 100644 --- a/lib/private/Share20/Manager.php +++ b/lib/private/Share20/Manager.php @@ -578,7 +578,7 @@ class Manager implements IManager { if ($path instanceof \OCP\Files\Folder) { $mounts = $this->mountManager->findIn($path->getPath()); foreach ($mounts as $mount) { - if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) { + if ($mount->getStorage()->instanceOfStorage(\OCA\Files_Sharing\ISharedStorage::class)) { throw new \InvalidArgumentException($this->l->t('Path contains files shared with you')); } } @@ -623,9 +623,9 @@ class Manager implements IManager { * Except for mounted federated shares. */ $storage = $share->getNode()->getStorage(); - if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) { + if ($storage->instanceOfStorage(\OCA\Files_Sharing\External\Storage::class)) { $parent = $share->getNode()->getParent(); - while ($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) { + while ($parent->getStorage()->instanceOfStorage(\OCA\Files_Sharing\External\Storage::class)) { $parent = $parent->getParent(); } $share->setShareOwner($parent->getOwner()->getUID()); diff --git a/lib/private/SubAdmin.php b/lib/private/SubAdmin.php index c025ab7b012..6dad75545e6 100644 --- a/lib/private/SubAdmin.php +++ b/lib/private/SubAdmin.php @@ -69,7 +69,7 @@ class SubAdmin extends PublicEmitter implements ISubAdmin { ->execute(); /** @deprecated 21.0.0 - use type SubAdminAddedEvent instead */ - $this->emit('\OC\SubAdmin', 'postCreateSubAdmin', [$user, $group]); + $this->emit(\OC\SubAdmin::class, 'postCreateSubAdmin', [$user, $group]); $event = new SubAdminAddedEvent($group, $user); $this->eventDispatcher->dispatchTyped($event); } @@ -88,7 +88,7 @@ class SubAdmin extends PublicEmitter implements ISubAdmin { ->execute(); /** @deprecated 21.0.0 - use type SubAdminRemovedEvent instead */ - $this->emit('\OC\SubAdmin', 'postDeleteSubAdmin', [$user, $group]); + $this->emit(\OC\SubAdmin::class, 'postDeleteSubAdmin', [$user, $group]); $event = new SubAdminRemovedEvent($group, $user); $this->eventDispatcher->dispatchTyped($event); } diff --git a/lib/private/TemplateLayout.php b/lib/private/TemplateLayout.php index 0ef4ec197cf..b93695ab500 100644 --- a/lib/private/TemplateLayout.php +++ b/lib/private/TemplateLayout.php @@ -89,7 +89,7 @@ class TemplateLayout extends \OC_Template { } // Set body data-theme $this->assign('enabledThemes', []); - if (\OC::$server->getAppManager()->isEnabledForUser('theming') && class_exists('\OCA\Theming\Service\ThemesService')) { + if (\OC::$server->getAppManager()->isEnabledForUser('theming') && class_exists(\OCA\Theming\Service\ThemesService::class)) { /** @var \OCA\Theming\Service\ThemesService */ $themesService = \OC::$server->get(\OCA\Theming\Service\ThemesService::class); $this->assign('enabledThemes', $themesService->getEnabledThemes()); diff --git a/lib/private/Updater.php b/lib/private/Updater.php index 2722c172f1a..fca88e22774 100644 --- a/lib/private/Updater.php +++ b/lib/private/Updater.php @@ -71,14 +71,14 @@ class Updater extends BasicEmitter { $this->logAllEvents(); $logLevel = $this->config->getSystemValue('loglevel', ILogger::WARN); - $this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]); + $this->emit(\OC\Updater::class, 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]); $this->config->setSystemValue('loglevel', ILogger::DEBUG); $wasMaintenanceModeEnabled = $this->config->getSystemValueBool('maintenance'); if (!$wasMaintenanceModeEnabled) { $this->config->setSystemValue('maintenance', true); - $this->emit('\OC\Updater', 'maintenanceEnabled'); + $this->emit(\OC\Updater::class, 'maintenanceEnabled'); } // Clear CAN_INSTALL file if not on git @@ -100,26 +100,26 @@ class Updater extends BasicEmitter { $this->log->error($exception->getMessage(), [ 'exception' => $exception, ]); - $this->emit('\OC\Updater', 'failure', [$exception->getMessage() . ': ' .$exception->getHint()]); + $this->emit(\OC\Updater::class, 'failure', [$exception->getMessage() . ': ' .$exception->getHint()]); $success = false; } catch (\Exception $exception) { $this->log->error($exception->getMessage(), [ 'exception' => $exception, ]); - $this->emit('\OC\Updater', 'failure', [get_class($exception) . ': ' .$exception->getMessage()]); + $this->emit(\OC\Updater::class, 'failure', [get_class($exception) . ': ' .$exception->getMessage()]); $success = false; } - $this->emit('\OC\Updater', 'updateEnd', [$success]); + $this->emit(\OC\Updater::class, 'updateEnd', [$success]); if (!$wasMaintenanceModeEnabled && $success) { $this->config->setSystemValue('maintenance', false); - $this->emit('\OC\Updater', 'maintenanceDisabled'); + $this->emit(\OC\Updater::class, 'maintenanceDisabled'); } else { - $this->emit('\OC\Updater', 'maintenanceActive'); + $this->emit(\OC\Updater::class, 'maintenanceActive'); } - $this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]); + $this->emit(\OC\Updater::class, 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]); $this->config->setSystemValue('loglevel', $logLevel); $this->config->setSystemValue('installed', true); @@ -254,7 +254,7 @@ class Updater extends BasicEmitter { 'exception' => $exception, 'app' => $appId, ]); - $this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]); + $this->emit(\OC\Updater::class, 'failure', [$appId . ': ' . $exception->getMessage()]); } // post-upgrade repairs @@ -267,9 +267,9 @@ class Updater extends BasicEmitter { // Check for code integrity if not disabled if (\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) { - $this->emit('\OC\Updater', 'startCheckCodeIntegrity'); + $this->emit(\OC\Updater::class, 'startCheckCodeIntegrity'); $this->checker->runInstanceVerification(); - $this->emit('\OC\Updater', 'finishedCheckCodeIntegrity'); + $this->emit(\OC\Updater::class, 'finishedCheckCodeIntegrity'); } // only set the final version if everything went well @@ -278,13 +278,13 @@ class Updater extends BasicEmitter { } protected function doCoreUpgrade(): void { - $this->emit('\OC\Updater', 'dbUpgradeBefore'); + $this->emit(\OC\Updater::class, 'dbUpgradeBefore'); // execute core migrations $ms = new MigrationService('core', \OC::$server->get(Connection::class)); $ms->migrate(); - $this->emit('\OC\Updater', 'dbUpgrade'); + $this->emit(\OC\Updater::class, 'dbUpgrade'); } /** @@ -319,9 +319,9 @@ class Updater extends BasicEmitter { $stack = $stacks[$type]; foreach ($stack as $appId) { if (\OC_App::shouldUpgrade($appId)) { - $this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, \OCP\Server::get(IAppManager::class)->getAppVersion($appId)]); + $this->emit(\OC\Updater::class, 'appUpgradeStarted', [$appId, \OCP\Server::get(IAppManager::class)->getAppVersion($appId)]); \OC_App::updateApp($appId); - $this->emit('\OC\Updater', 'appUpgrade', [$appId, \OCP\Server::get(IAppManager::class)->getAppVersion($appId)]); + $this->emit(\OC\Updater::class, 'appUpgrade', [$appId, \OCP\Server::get(IAppManager::class)->getAppVersion($appId)]); } if ($type !== $pseudoOtherType) { // load authentication, filesystem and logging apps after @@ -354,7 +354,7 @@ class Updater extends BasicEmitter { throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update'); } $appManager->disableApp($app, true); - $this->emit('\OC\Updater', 'incompatibleAppDisabled', [$app]); + $this->emit(\OC\Updater::class, 'incompatibleAppDisabled', [$app]); } } } @@ -379,12 +379,12 @@ class Updater extends BasicEmitter { private function upgradeAppStoreApps(array $apps, array $previousEnableStates = []): void { foreach ($apps as $app) { try { - $this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]); + $this->emit(\OC\Updater::class, 'checkAppStoreAppBefore', [$app]); if ($this->installer->isUpdateAvailable($app)) { - $this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]); + $this->emit(\OC\Updater::class, 'upgradeAppStoreApp', [$app]); $this->installer->updateAppstoreApp($app); } - $this->emit('\OC\Updater', 'checkAppStoreApp', [$app]); + $this->emit(\OC\Updater::class, 'checkAppStoreApp', [$app]); if (!empty($previousEnableStates)) { $ocApp = new \OC_App(); @@ -445,62 +445,62 @@ class Updater extends BasicEmitter { $dispatcher->addListener(RepairErrorEvent::class, $repairListener); - $this->listen('\OC\Updater', 'maintenanceEnabled', function () use ($log) { + $this->listen(\OC\Updater::class, 'maintenanceEnabled', function () use ($log) { $log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']); }); - $this->listen('\OC\Updater', 'maintenanceDisabled', function () use ($log) { + $this->listen(\OC\Updater::class, 'maintenanceDisabled', function () use ($log) { $log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']); }); - $this->listen('\OC\Updater', 'maintenanceActive', function () use ($log) { + $this->listen(\OC\Updater::class, 'maintenanceActive', function () use ($log) { $log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']); }); - $this->listen('\OC\Updater', 'updateEnd', function ($success) use ($log) { + $this->listen(\OC\Updater::class, 'updateEnd', function ($success) use ($log) { if ($success) { $log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']); } else { $log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']); } }); - $this->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($log) { + $this->listen(\OC\Updater::class, 'dbUpgradeBefore', function () use ($log) { $log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']); }); - $this->listen('\OC\Updater', 'dbUpgrade', function () use ($log) { + $this->listen(\OC\Updater::class, 'dbUpgrade', function () use ($log) { $log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']); }); - $this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use ($log) { + $this->listen(\OC\Updater::class, 'incompatibleAppDisabled', function ($app) use ($log) { $log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']); }); - $this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use ($log) { + $this->listen(\OC\Updater::class, 'checkAppStoreAppBefore', function ($app) use ($log) { $log->debug('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']); }); - $this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($log) { + $this->listen(\OC\Updater::class, 'upgradeAppStoreApp', function ($app) use ($log) { $log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']); }); - $this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use ($log) { + $this->listen(\OC\Updater::class, 'checkAppStoreApp', function ($app) use ($log) { $log->debug('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']); }); - $this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) { + $this->listen(\OC\Updater::class, 'appSimulateUpdate', function ($app) use ($log) { $log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <' . $app . '> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']); }); - $this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) { + $this->listen(\OC\Updater::class, 'appUpgradeStarted', function ($app) use ($log) { $log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']); }); - $this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) { + $this->listen(\OC\Updater::class, 'appUpgrade', function ($app, $version) use ($log) { $log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']); }); - $this->listen('\OC\Updater', 'failure', function ($message) use ($log) { + $this->listen(\OC\Updater::class, 'failure', function ($message) use ($log) { $log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']); }); - $this->listen('\OC\Updater', 'setDebugLogLevel', function () use ($log) { + $this->listen(\OC\Updater::class, 'setDebugLogLevel', function () use ($log) { $log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']); }); - $this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($log) { + $this->listen(\OC\Updater::class, 'resetLogLevel', function ($logLevel, $logLevelName) use ($log) { $log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']); }); - $this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($log) { + $this->listen(\OC\Updater::class, 'startCheckCodeIntegrity', function () use ($log) { $log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']); }); - $this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($log) { + $this->listen(\OC\Updater::class, 'finishedCheckCodeIntegrity', function () use ($log) { $log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']); }); } diff --git a/lib/private/legacy/OC_App.php b/lib/private/legacy/OC_App.php index ef84d35d7bc..c07aca015c1 100644 --- a/lib/private/legacy/OC_App.php +++ b/lib/private/legacy/OC_App.php @@ -790,7 +790,7 @@ class OC_App { private static function setupLiveMigrations(string $appId, array $steps) { $queue = \OC::$server->getJobList(); foreach ($steps as $step) { - $queue->add('OC\Migration\BackgroundRepair', [ + $queue->add(\OC\Migration\BackgroundRepair::class, [ 'app' => $appId, 'step' => $step]); } diff --git a/lib/private/legacy/OC_Helper.php b/lib/private/legacy/OC_Helper.php index 33cc966da2a..d05f1e108c2 100644 --- a/lib/private/legacy/OC_Helper.php +++ b/lib/private/legacy/OC_Helper.php @@ -486,12 +486,12 @@ class OC_Helper { $mount = $rootInfo->getMountPoint(); $storage = $mount->getStorage(); $sourceStorage = $storage; - if ($storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) { + if ($storage->instanceOfStorage(\OCA\Files_Sharing\SharedStorage::class)) { self::$quotaIncludeExternalStorage = false; } if (self::$quotaIncludeExternalStorage) { - if ($storage->instanceOfStorage('\OC\Files\Storage\Home') - || $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage') + if ($storage->instanceOfStorage(\OC\Files\Storage\Home::class) + || $storage->instanceOfStorage(\OC\Files\ObjectStore\HomeObjectStoreStorage::class) ) { /** @var \OC\Files\Storage\Home $storage */ $user = $storage->getUser(); @@ -506,7 +506,7 @@ class OC_Helper { } // TODO: need a better way to get total space from storage - if ($sourceStorage->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota')) { + if ($sourceStorage->instanceOfStorage(\OC\Files\Storage\Wrapper\Quota::class)) { /** @var \OC\Files\Storage\Wrapper\Quota $storage */ $quota = $sourceStorage->getQuota(); } diff --git a/tests/Core/Command/Config/ListConfigsTest.php b/tests/Core/Command/Config/ListConfigsTest.php index 0cee870d45c..e9cf13773be 100644 --- a/tests/Core/Command/Config/ListConfigsTest.php +++ b/tests/Core/Command/Config/ListConfigsTest.php @@ -131,7 +131,7 @@ class ListConfigsTest extends TestCase { [ ['secret', 'N;', IConfig::SENSITIVE_VALUE], ['objectstore', 'N;', [ - 'class' => 'OC\\Files\\ObjectStore\\Swift', + 'class' => \OC\Files\ObjectStore\Swift::class, 'arguments' => [ 'username' => 'facebook100000123456789', 'password' => IConfig::SENSITIVE_VALUE, @@ -153,7 +153,7 @@ class ListConfigsTest extends TestCase { 'system' => [ 'secret' => IConfig::SENSITIVE_VALUE, 'objectstore' => [ - 'class' => 'OC\\Files\\ObjectStore\\Swift', + 'class' => \OC\Files\ObjectStore\Swift::class, 'arguments' => [ 'username' => 'facebook100000123456789', 'password' => IConfig::SENSITIVE_VALUE, diff --git a/tests/Core/Command/Encryption/ChangeKeyStorageRootTest.php b/tests/Core/Command/Encryption/ChangeKeyStorageRootTest.php index b124a27f9ab..a1dcdfb51a9 100644 --- a/tests/Core/Command/Encryption/ChangeKeyStorageRootTest.php +++ b/tests/Core/Command/Encryption/ChangeKeyStorageRootTest.php @@ -1,362 +1,362 @@ -<?php -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-only - */ - -namespace Tests\Core\Command\Encryption; - -use OC\Core\Command\Encryption\ChangeKeyStorageRoot; -use OC\Encryption\Util; -use OC\Files\View; -use OCP\IConfig; -use OCP\IUserManager; -use OCP\UserInterface; -use Symfony\Component\Console\Formatter\OutputFormatterInterface; -use Symfony\Component\Console\Helper\QuestionHelper; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; -use Test\TestCase; - -class ChangeKeyStorageRootTest extends TestCase { - /** @var ChangeKeyStorageRoot */ - protected $changeKeyStorageRoot; - - /** @var View | \PHPUnit\Framework\MockObject\MockObject */ - protected $view; - - /** @var IUserManager | \PHPUnit\Framework\MockObject\MockObject */ - protected $userManager; - - /** @var IConfig | \PHPUnit\Framework\MockObject\MockObject */ - protected $config; - - /** @var Util | \PHPUnit\Framework\MockObject\MockObject */ - protected $util; - - /** @var QuestionHelper | \PHPUnit\Framework\MockObject\MockObject */ - protected $questionHelper; - - /** @var InputInterface | \PHPUnit\Framework\MockObject\MockObject */ - protected $inputInterface; - - /** @var OutputInterface | \PHPUnit\Framework\MockObject\MockObject */ - protected $outputInterface; - - /** @var \OCP\UserInterface | \PHPUnit\Framework\MockObject\MockObject */ - protected $userInterface; - - protected function setUp(): void { - parent::setUp(); - - $this->view = $this->getMockBuilder(View::class)->getMock(); - $this->userManager = $this->getMockBuilder(IUserManager::class)->getMock(); - $this->config = $this->getMockBuilder(IConfig::class)->getMock(); - $this->util = $this->getMockBuilder('OC\Encryption\Util')->disableOriginalConstructor()->getMock(); - $this->questionHelper = $this->getMockBuilder(QuestionHelper::class)->getMock(); - $this->inputInterface = $this->getMockBuilder(InputInterface::class)->getMock(); - $this->outputInterface = $this->getMockBuilder(OutputInterface::class)->getMock(); - $this->userInterface = $this->getMockBuilder(UserInterface::class)->getMock(); - - /* We need format method to return a string */ - $outputFormatter = $this->createMock(OutputFormatterInterface::class); - $outputFormatter->method('isDecorated')->willReturn(false); - $outputFormatter->method('format')->willReturnArgument(0); - - $this->outputInterface->expects($this->any())->method('getFormatter') - ->willReturn($outputFormatter); - - $this->changeKeyStorageRoot = new ChangeKeyStorageRoot( - $this->view, - $this->userManager, - $this->config, - $this->util, - $this->questionHelper - ); - } - - /** - * @dataProvider dataTestExecute - */ - public function testExecute($newRoot, $answer, $successMoveKey): void { - $changeKeyStorageRoot = $this->getMockBuilder('OC\Core\Command\Encryption\ChangeKeyStorageRoot') - ->setConstructorArgs( - [ - $this->view, - $this->userManager, - $this->config, - $this->util, - $this->questionHelper - ] - )->setMethods(['moveAllKeys'])->getMock(); - - $this->util->expects($this->once())->method('getKeyStorageRoot') - ->willReturn(''); - $this->inputInterface->expects($this->once())->method('getArgument') - ->with('newRoot')->willReturn($newRoot); - - if ($answer === true || $newRoot !== null) { - $changeKeyStorageRoot->expects($this->once())->method('moveAllKeys') - ->willReturn($successMoveKey); - } else { - $changeKeyStorageRoot->expects($this->never())->method('moveAllKeys'); - } - - if ($successMoveKey === true) { - $this->util->expects($this->once())->method('setKeyStorageRoot'); - } else { - $this->util->expects($this->never())->method('setKeyStorageRoot'); - } - - if ($newRoot === null) { - $this->questionHelper->expects($this->once())->method('ask')->willReturn($answer); - } else { - $this->questionHelper->expects($this->never())->method('ask'); - } - - $this->invokePrivate( - $changeKeyStorageRoot, - 'execute', - [$this->inputInterface, $this->outputInterface] - ); - } - - public function dataTestExecute() { - return [ - [null, true, true], - [null, true, false], - [null, false, null], - ['/newRoot', null, true], - ['/newRoot', null, false] - ]; - } - - public function testMoveAllKeys(): void { - /** @var \OC\Core\Command\Encryption\ChangeKeyStorageRoot $changeKeyStorageRoot */ - $changeKeyStorageRoot = $this->getMockBuilder('OC\Core\Command\Encryption\ChangeKeyStorageRoot') - ->setConstructorArgs( - [ - $this->view, - $this->userManager, - $this->config, - $this->util, - $this->questionHelper - ] - )->setMethods(['prepareNewRoot', 'moveSystemKeys', 'moveUserKeys'])->getMock(); - - $changeKeyStorageRoot->expects($this->once())->method('prepareNewRoot')->with('newRoot'); - $changeKeyStorageRoot->expects($this->once())->method('moveSystemKeys')->with('oldRoot', 'newRoot'); - $changeKeyStorageRoot->expects($this->once())->method('moveUserKeys')->with('oldRoot', 'newRoot', $this->outputInterface); - - $this->invokePrivate($changeKeyStorageRoot, 'moveAllKeys', ['oldRoot', 'newRoot', $this->outputInterface]); - } - - public function testPrepareNewRoot(): void { - $this->view->expects($this->once())->method('is_dir')->with('newRoot') - ->willReturn(true); - - $this->view->expects($this->once())->method('file_put_contents') - ->with('newRoot/' . \OC\Encryption\Keys\Storage::KEY_STORAGE_MARKER, - 'Nextcloud will detect this folder as key storage root only if this file exists')->willReturn(true); - - $this->invokePrivate($this->changeKeyStorageRoot, 'prepareNewRoot', ['newRoot']); - } - - /** - * @dataProvider dataTestPrepareNewRootException - * - * @param bool $dirExists - * @param bool $couldCreateFile - */ - public function testPrepareNewRootException($dirExists, $couldCreateFile): void { - $this->expectException(\Exception::class); - - $this->view->expects($this->once())->method('is_dir')->with('newRoot') - ->willReturn($dirExists); - $this->view->expects($this->any())->method('file_put_contents')->willReturn($couldCreateFile); - - $this->invokePrivate($this->changeKeyStorageRoot, 'prepareNewRoot', ['newRoot']); - } - - public function dataTestPrepareNewRootException() { - return [ - [true, false], - [true, null], - [false, true] - ]; - } - - /** - * @dataProvider dataTestMoveSystemKeys - * - * @param bool $dirExists - * @param bool $targetExists - * @param bool $executeRename - */ - public function testMoveSystemKeys($dirExists, $targetExists, $executeRename): void { - $changeKeyStorageRoot = $this->getMockBuilder('OC\Core\Command\Encryption\ChangeKeyStorageRoot') - ->setConstructorArgs( - [ - $this->view, - $this->userManager, - $this->config, - $this->util, - $this->questionHelper - ] - )->setMethods(['targetExists'])->getMock(); - - $this->view->expects($this->once())->method('is_dir') - ->with('oldRoot/files_encryption')->willReturn($dirExists); - $changeKeyStorageRoot->expects($this->any())->method('targetExists') - ->with('newRoot/files_encryption')->willReturn($targetExists); - - if ($executeRename) { - $this->view->expects($this->once())->method('rename') - ->with('oldRoot/files_encryption', 'newRoot/files_encryption'); - } else { - $this->view->expects($this->never())->method('rename'); - } - - $this->invokePrivate($changeKeyStorageRoot, 'moveSystemKeys', ['oldRoot', 'newRoot']); - } - - public function dataTestMoveSystemKeys() { - return [ - [true, false, true], - [false, true, false], - [true, true, false], - [false, false, false] - ]; - } - - - public function testMoveUserKeys(): void { - $changeKeyStorageRoot = $this->getMockBuilder('OC\Core\Command\Encryption\ChangeKeyStorageRoot') - ->setConstructorArgs( - [ - $this->view, - $this->userManager, - $this->config, - $this->util, - $this->questionHelper - ] - )->setMethods(['setupUserFS', 'moveUserEncryptionFolder'])->getMock(); - - $this->userManager->expects($this->once())->method('getBackends') - ->willReturn([$this->userInterface]); - $this->userInterface->expects($this->once())->method('getUsers') - ->willReturn(['user1', 'user2']); - $changeKeyStorageRoot->expects($this->exactly(2))->method('setupUserFS'); - $changeKeyStorageRoot->expects($this->exactly(2))->method('moveUserEncryptionFolder'); - - $this->invokePrivate($changeKeyStorageRoot, 'moveUserKeys', ['oldRoot', 'newRoot', $this->outputInterface]); - } - - /** - * @dataProvider dataTestMoveUserEncryptionFolder - * - * @param bool $userExists - * @param bool $isDir - * @param bool $targetExists - * @param bool $shouldRename - */ - public function testMoveUserEncryptionFolder($userExists, $isDir, $targetExists, $shouldRename): void { - $changeKeyStorageRoot = $this->getMockBuilder('OC\Core\Command\Encryption\ChangeKeyStorageRoot') - ->setConstructorArgs( - [ - $this->view, - $this->userManager, - $this->config, - $this->util, - $this->questionHelper - ] - )->setMethods(['targetExists', 'prepareParentFolder'])->getMock(); - - $this->userManager->expects($this->once())->method('userExists') - ->willReturn($userExists); - $this->view->expects($this->any())->method('is_dir') - ->willReturn($isDir); - $changeKeyStorageRoot->expects($this->any())->method('targetExists') - ->willReturn($targetExists); - - if ($shouldRename) { - $changeKeyStorageRoot->expects($this->once())->method('prepareParentFolder') - ->with('newRoot/user1'); - $this->view->expects($this->once())->method('rename') - ->with('oldRoot/user1/files_encryption', 'newRoot/user1/files_encryption'); - } else { - $changeKeyStorageRoot->expects($this->never())->method('prepareParentFolder'); - $this->view->expects($this->never())->method('rename'); - } - - $this->invokePrivate($changeKeyStorageRoot, 'moveUserEncryptionFolder', ['user1', 'oldRoot', 'newRoot']); - } - - public function dataTestMoveUserEncryptionFolder() { - return [ - [true, true, false, true], - [true, false, true, false], - [false, true, true, false], - [false, false, true, false], - [false, true, false, false], - [false, true, true, false], - [false, false, false, false] - ]; - } - - - /** - * @dataProvider dataTestPrepareParentFolder - */ - public function testPrepareParentFolder($path, $pathExists): void { - $this->view->expects($this->any())->method('file_exists') - ->willReturnCallback( - function ($fileExistsPath) use ($path, $pathExists) { - if ($path === $fileExistsPath) { - return $pathExists; - } - return false; - } - ); - - if ($pathExists === false) { - $subDirs = explode('/', ltrim($path, '/')); - $this->view->expects($this->exactly(count($subDirs)))->method('mkdir'); - } else { - $this->view->expects($this->never())->method('mkdir'); - } - - $this->invokePrivate( - $this->changeKeyStorageRoot, - 'prepareParentFolder', - [$path] - ); - } - - public function dataTestPrepareParentFolder() { - return [ - ['/user/folder/sub_folder/keystorage', true], - ['/user/folder/sub_folder/keystorage', false] - ]; - } - - public function testTargetExists(): void { - $this->view->expects($this->once())->method('file_exists')->with('path') - ->willReturn(false); - - $this->assertFalse( - $this->invokePrivate($this->changeKeyStorageRoot, 'targetExists', ['path']) - ); - } - - - public function testTargetExistsException(): void { - $this->expectException(\Exception::class); - - $this->view->expects($this->once())->method('file_exists')->with('path') - ->willReturn(true); - - $this->invokePrivate($this->changeKeyStorageRoot, 'targetExists', ['path']); - } -} +<?php +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace Tests\Core\Command\Encryption; + +use OC\Core\Command\Encryption\ChangeKeyStorageRoot; +use OC\Encryption\Util; +use OC\Files\View; +use OCP\IConfig; +use OCP\IUserManager; +use OCP\UserInterface; +use Symfony\Component\Console\Formatter\OutputFormatterInterface; +use Symfony\Component\Console\Helper\QuestionHelper; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Test\TestCase; + +class ChangeKeyStorageRootTest extends TestCase { + /** @var ChangeKeyStorageRoot */ + protected $changeKeyStorageRoot; + + /** @var View | \PHPUnit\Framework\MockObject\MockObject */ + protected $view; + + /** @var IUserManager | \PHPUnit\Framework\MockObject\MockObject */ + protected $userManager; + + /** @var IConfig | \PHPUnit\Framework\MockObject\MockObject */ + protected $config; + + /** @var Util | \PHPUnit\Framework\MockObject\MockObject */ + protected $util; + + /** @var QuestionHelper | \PHPUnit\Framework\MockObject\MockObject */ + protected $questionHelper; + + /** @var InputInterface | \PHPUnit\Framework\MockObject\MockObject */ + protected $inputInterface; + + /** @var OutputInterface | \PHPUnit\Framework\MockObject\MockObject */ + protected $outputInterface; + + /** @var \OCP\UserInterface | \PHPUnit\Framework\MockObject\MockObject */ + protected $userInterface; + + protected function setUp(): void { + parent::setUp(); + + $this->view = $this->getMockBuilder(View::class)->getMock(); + $this->userManager = $this->getMockBuilder(IUserManager::class)->getMock(); + $this->config = $this->getMockBuilder(IConfig::class)->getMock(); + $this->util = $this->getMockBuilder(\OC\Encryption\Util::class)->disableOriginalConstructor()->getMock(); + $this->questionHelper = $this->getMockBuilder(QuestionHelper::class)->getMock(); + $this->inputInterface = $this->getMockBuilder(InputInterface::class)->getMock(); + $this->outputInterface = $this->getMockBuilder(OutputInterface::class)->getMock(); + $this->userInterface = $this->getMockBuilder(UserInterface::class)->getMock(); + + /* We need format method to return a string */ + $outputFormatter = $this->createMock(OutputFormatterInterface::class); + $outputFormatter->method('isDecorated')->willReturn(false); + $outputFormatter->method('format')->willReturnArgument(0); + + $this->outputInterface->expects($this->any())->method('getFormatter') + ->willReturn($outputFormatter); + + $this->changeKeyStorageRoot = new ChangeKeyStorageRoot( + $this->view, + $this->userManager, + $this->config, + $this->util, + $this->questionHelper + ); + } + + /** + * @dataProvider dataTestExecute + */ + public function testExecute($newRoot, $answer, $successMoveKey): void { + $changeKeyStorageRoot = $this->getMockBuilder(\OC\Core\Command\Encryption\ChangeKeyStorageRoot::class) + ->setConstructorArgs( + [ + $this->view, + $this->userManager, + $this->config, + $this->util, + $this->questionHelper + ] + )->setMethods(['moveAllKeys'])->getMock(); + + $this->util->expects($this->once())->method('getKeyStorageRoot') + ->willReturn(''); + $this->inputInterface->expects($this->once())->method('getArgument') + ->with('newRoot')->willReturn($newRoot); + + if ($answer === true || $newRoot !== null) { + $changeKeyStorageRoot->expects($this->once())->method('moveAllKeys') + ->willReturn($successMoveKey); + } else { + $changeKeyStorageRoot->expects($this->never())->method('moveAllKeys'); + } + + if ($successMoveKey === true) { + $this->util->expects($this->once())->method('setKeyStorageRoot'); + } else { + $this->util->expects($this->never())->method('setKeyStorageRoot'); + } + + if ($newRoot === null) { + $this->questionHelper->expects($this->once())->method('ask')->willReturn($answer); + } else { + $this->questionHelper->expects($this->never())->method('ask'); + } + + $this->invokePrivate( + $changeKeyStorageRoot, + 'execute', + [$this->inputInterface, $this->outputInterface] + ); + } + + public function dataTestExecute() { + return [ + [null, true, true], + [null, true, false], + [null, false, null], + ['/newRoot', null, true], + ['/newRoot', null, false] + ]; + } + + public function testMoveAllKeys(): void { + /** @var \OC\Core\Command\Encryption\ChangeKeyStorageRoot $changeKeyStorageRoot */ + $changeKeyStorageRoot = $this->getMockBuilder(\OC\Core\Command\Encryption\ChangeKeyStorageRoot::class) + ->setConstructorArgs( + [ + $this->view, + $this->userManager, + $this->config, + $this->util, + $this->questionHelper + ] + )->setMethods(['prepareNewRoot', 'moveSystemKeys', 'moveUserKeys'])->getMock(); + + $changeKeyStorageRoot->expects($this->once())->method('prepareNewRoot')->with('newRoot'); + $changeKeyStorageRoot->expects($this->once())->method('moveSystemKeys')->with('oldRoot', 'newRoot'); + $changeKeyStorageRoot->expects($this->once())->method('moveUserKeys')->with('oldRoot', 'newRoot', $this->outputInterface); + + $this->invokePrivate($changeKeyStorageRoot, 'moveAllKeys', ['oldRoot', 'newRoot', $this->outputInterface]); + } + + public function testPrepareNewRoot(): void { + $this->view->expects($this->once())->method('is_dir')->with('newRoot') + ->willReturn(true); + + $this->view->expects($this->once())->method('file_put_contents') + ->with('newRoot/' . \OC\Encryption\Keys\Storage::KEY_STORAGE_MARKER, + 'Nextcloud will detect this folder as key storage root only if this file exists')->willReturn(true); + + $this->invokePrivate($this->changeKeyStorageRoot, 'prepareNewRoot', ['newRoot']); + } + + /** + * @dataProvider dataTestPrepareNewRootException + * + * @param bool $dirExists + * @param bool $couldCreateFile + */ + public function testPrepareNewRootException($dirExists, $couldCreateFile): void { + $this->expectException(\Exception::class); + + $this->view->expects($this->once())->method('is_dir')->with('newRoot') + ->willReturn($dirExists); + $this->view->expects($this->any())->method('file_put_contents')->willReturn($couldCreateFile); + + $this->invokePrivate($this->changeKeyStorageRoot, 'prepareNewRoot', ['newRoot']); + } + + public function dataTestPrepareNewRootException() { + return [ + [true, false], + [true, null], + [false, true] + ]; + } + + /** + * @dataProvider dataTestMoveSystemKeys + * + * @param bool $dirExists + * @param bool $targetExists + * @param bool $executeRename + */ + public function testMoveSystemKeys($dirExists, $targetExists, $executeRename): void { + $changeKeyStorageRoot = $this->getMockBuilder(\OC\Core\Command\Encryption\ChangeKeyStorageRoot::class) + ->setConstructorArgs( + [ + $this->view, + $this->userManager, + $this->config, + $this->util, + $this->questionHelper + ] + )->setMethods(['targetExists'])->getMock(); + + $this->view->expects($this->once())->method('is_dir') + ->with('oldRoot/files_encryption')->willReturn($dirExists); + $changeKeyStorageRoot->expects($this->any())->method('targetExists') + ->with('newRoot/files_encryption')->willReturn($targetExists); + + if ($executeRename) { + $this->view->expects($this->once())->method('rename') + ->with('oldRoot/files_encryption', 'newRoot/files_encryption'); + } else { + $this->view->expects($this->never())->method('rename'); + } + + $this->invokePrivate($changeKeyStorageRoot, 'moveSystemKeys', ['oldRoot', 'newRoot']); + } + + public function dataTestMoveSystemKeys() { + return [ + [true, false, true], + [false, true, false], + [true, true, false], + [false, false, false] + ]; + } + + + public function testMoveUserKeys(): void { + $changeKeyStorageRoot = $this->getMockBuilder(\OC\Core\Command\Encryption\ChangeKeyStorageRoot::class) + ->setConstructorArgs( + [ + $this->view, + $this->userManager, + $this->config, + $this->util, + $this->questionHelper + ] + )->setMethods(['setupUserFS', 'moveUserEncryptionFolder'])->getMock(); + + $this->userManager->expects($this->once())->method('getBackends') + ->willReturn([$this->userInterface]); + $this->userInterface->expects($this->once())->method('getUsers') + ->willReturn(['user1', 'user2']); + $changeKeyStorageRoot->expects($this->exactly(2))->method('setupUserFS'); + $changeKeyStorageRoot->expects($this->exactly(2))->method('moveUserEncryptionFolder'); + + $this->invokePrivate($changeKeyStorageRoot, 'moveUserKeys', ['oldRoot', 'newRoot', $this->outputInterface]); + } + + /** + * @dataProvider dataTestMoveUserEncryptionFolder + * + * @param bool $userExists + * @param bool $isDir + * @param bool $targetExists + * @param bool $shouldRename + */ + public function testMoveUserEncryptionFolder($userExists, $isDir, $targetExists, $shouldRename): void { + $changeKeyStorageRoot = $this->getMockBuilder(\OC\Core\Command\Encryption\ChangeKeyStorageRoot::class) + ->setConstructorArgs( + [ + $this->view, + $this->userManager, + $this->config, + $this->util, + $this->questionHelper + ] + )->setMethods(['targetExists', 'prepareParentFolder'])->getMock(); + + $this->userManager->expects($this->once())->method('userExists') + ->willReturn($userExists); + $this->view->expects($this->any())->method('is_dir') + ->willReturn($isDir); + $changeKeyStorageRoot->expects($this->any())->method('targetExists') + ->willReturn($targetExists); + + if ($shouldRename) { + $changeKeyStorageRoot->expects($this->once())->method('prepareParentFolder') + ->with('newRoot/user1'); + $this->view->expects($this->once())->method('rename') + ->with('oldRoot/user1/files_encryption', 'newRoot/user1/files_encryption'); + } else { + $changeKeyStorageRoot->expects($this->never())->method('prepareParentFolder'); + $this->view->expects($this->never())->method('rename'); + } + + $this->invokePrivate($changeKeyStorageRoot, 'moveUserEncryptionFolder', ['user1', 'oldRoot', 'newRoot']); + } + + public function dataTestMoveUserEncryptionFolder() { + return [ + [true, true, false, true], + [true, false, true, false], + [false, true, true, false], + [false, false, true, false], + [false, true, false, false], + [false, true, true, false], + [false, false, false, false] + ]; + } + + + /** + * @dataProvider dataTestPrepareParentFolder + */ + public function testPrepareParentFolder($path, $pathExists): void { + $this->view->expects($this->any())->method('file_exists') + ->willReturnCallback( + function ($fileExistsPath) use ($path, $pathExists) { + if ($path === $fileExistsPath) { + return $pathExists; + } + return false; + } + ); + + if ($pathExists === false) { + $subDirs = explode('/', ltrim($path, '/')); + $this->view->expects($this->exactly(count($subDirs)))->method('mkdir'); + } else { + $this->view->expects($this->never())->method('mkdir'); + } + + $this->invokePrivate( + $this->changeKeyStorageRoot, + 'prepareParentFolder', + [$path] + ); + } + + public function dataTestPrepareParentFolder() { + return [ + ['/user/folder/sub_folder/keystorage', true], + ['/user/folder/sub_folder/keystorage', false] + ]; + } + + public function testTargetExists(): void { + $this->view->expects($this->once())->method('file_exists')->with('path') + ->willReturn(false); + + $this->assertFalse( + $this->invokePrivate($this->changeKeyStorageRoot, 'targetExists', ['path']) + ); + } + + + public function testTargetExistsException(): void { + $this->expectException(\Exception::class); + + $this->view->expects($this->once())->method('file_exists')->with('path') + ->willReturn(true); + + $this->invokePrivate($this->changeKeyStorageRoot, 'targetExists', ['path']); + } +} diff --git a/tests/Core/Command/User/SettingTest.php b/tests/Core/Command/User/SettingTest.php index 6848b0bb350..8c0edc46e72 100644 --- a/tests/Core/Command/User/SettingTest.php +++ b/tests/Core/Command/User/SettingTest.php @@ -51,7 +51,7 @@ class SettingTest extends TestCase { if (empty($methods)) { return new Setting($this->userManager, $this->config, $this->connection); } else { - $mock = $this->getMockBuilder('OC\Core\Command\User\Setting') + $mock = $this->getMockBuilder(\OC\Core\Command\User\Setting::class) ->setConstructorArgs([ $this->userManager, $this->config, diff --git a/tests/Core/Controller/AvatarControllerTest.php b/tests/Core/Controller/AvatarControllerTest.php index 3a1123c940b..ac9a6d33488 100644 --- a/tests/Core/Controller/AvatarControllerTest.php +++ b/tests/Core/Controller/AvatarControllerTest.php @@ -1,566 +1,566 @@ -<?php -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-only - */ - -namespace OC\Core\Controller; - -/** - * Overwrite is_uploaded_file in the OC\Core\Controller namespace to allow - * proper unit testing of the postAvatar call. - */ -function is_uploaded_file($filename) { - return file_exists($filename); -} - -namespace Tests\Core\Controller; - -use OC\AppFramework\Utility\TimeFactory; -use OC\Core\Controller\AvatarController; -use OC\Core\Controller\GuestAvatarController; -use OCP\AppFramework\Http; -use OCP\Files\File; -use OCP\Files\IRootFolder; -use OCP\Files\NotFoundException; -use OCP\Files\NotPermittedException; -use OCP\Files\SimpleFS\ISimpleFile; -use OCP\IAvatar; -use OCP\IAvatarManager; -use OCP\ICache; -use OCP\IL10N; -use OCP\IRequest; -use OCP\IUser; -use OCP\IUserManager; -use Psr\Log\LoggerInterface; - -/** - * Class AvatarControllerTest - * - * @package OC\Core\Controller - */ -class AvatarControllerTest extends \Test\TestCase { - /** @var AvatarController */ - private $avatarController; - /** @var GuestAvatarController */ - private $guestAvatarController; - - /** @var IAvatar|\PHPUnit\Framework\MockObject\MockObject */ - private $avatarMock; - /** @var IUser|\PHPUnit\Framework\MockObject\MockObject */ - private $userMock; - /** @var ISimpleFile|\PHPUnit\Framework\MockObject\MockObject */ - private $avatarFile; - /** @var IAvatarManager|\PHPUnit\Framework\MockObject\MockObject */ - private $avatarManager; - /** @var ICache|\PHPUnit\Framework\MockObject\MockObject */ - private $cache; - /** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */ - private $l; - /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */ - private $userManager; - /** @var IRootFolder|\PHPUnit\Framework\MockObject\MockObject */ - private $rootFolder; - /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */ - private $logger; - /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */ - private $request; - /** @var TimeFactory|\PHPUnit\Framework\MockObject\MockObject */ - private $timeFactory; - - protected function setUp(): void { - parent::setUp(); - - $this->avatarManager = $this->getMockBuilder('OCP\IAvatarManager')->getMock(); - $this->cache = $this->getMockBuilder('OCP\ICache') - ->disableOriginalConstructor()->getMock(); - $this->l = $this->getMockBuilder(IL10N::class)->getMock(); - $this->l->method('t')->willReturnArgument(0); - $this->userManager = $this->getMockBuilder(IUserManager::class)->getMock(); - $this->request = $this->getMockBuilder(IRequest::class)->getMock(); - $this->rootFolder = $this->getMockBuilder('OCP\Files\IRootFolder')->getMock(); - $this->logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); - $this->timeFactory = $this->getMockBuilder('OC\AppFramework\Utility\TimeFactory')->getMock(); - - $this->avatarMock = $this->getMockBuilder('OCP\IAvatar')->getMock(); - $this->userMock = $this->getMockBuilder(IUser::class)->getMock(); - - $this->guestAvatarController = new GuestAvatarController( - 'core', - $this->request, - $this->avatarManager, - $this->logger - ); - - $this->avatarController = new AvatarController( - 'core', - $this->request, - $this->avatarManager, - $this->cache, - $this->l, - $this->userManager, - $this->rootFolder, - $this->logger, - 'userid', - $this->timeFactory, - $this->guestAvatarController, - ); - - // Configure userMock - $this->userMock->method('getDisplayName')->willReturn('displayName'); - $this->userMock->method('getUID')->willReturn('userId'); - $this->userManager->method('get') - ->willReturnMap([['userId', $this->userMock]]); - - $this->avatarFile = $this->getMockBuilder(ISimpleFile::class)->getMock(); - $this->avatarFile->method('getContent')->willReturn('image data'); - $this->avatarFile->method('getMimeType')->willReturn('image type'); - $this->avatarFile->method('getEtag')->willReturn('my etag'); - $this->avatarFile->method('getName')->willReturn('my name'); - $this->avatarFile->method('getMTime')->willReturn(42); - } - - protected function tearDown(): void { - parent::tearDown(); - } - - /** - * Fetch an avatar if a user has no avatar - */ - public function testGetAvatarNoAvatar(): void { - $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); - $this->avatarMock->method('getFile')->will($this->throwException(new NotFoundException())); - $response = $this->avatarController->getAvatar('userId', 32); - - //Comment out until JS is fixed - $this->assertEquals(Http::STATUS_NOT_FOUND, $response->getStatus()); - } - - /** - * Fetch the user's avatar - */ - public function testGetAvatar(): void { - $this->avatarMock->method('getFile')->willReturn($this->avatarFile); - $this->avatarManager->method('getAvatar')->with('userId')->willReturn($this->avatarMock); - $this->avatarMock->expects($this->once()) - ->method('isCustomAvatar') - ->willReturn(true); - - $response = $this->avatarController->getAvatar('userId', 32); - - $this->assertEquals(Http::STATUS_OK, $response->getStatus()); - $this->assertArrayHasKey('Content-Type', $response->getHeaders()); - $this->assertEquals('image type', $response->getHeaders()['Content-Type']); - $this->assertArrayHasKey('X-NC-IsCustomAvatar', $response->getHeaders()); - $this->assertEquals('1', $response->getHeaders()['X-NC-IsCustomAvatar']); - - $this->assertEquals('my etag', $response->getETag()); - } - - /** - * Fetch the user's avatar - */ - public function testGetGeneratedAvatar(): void { - $this->avatarMock->method('getFile')->willReturn($this->avatarFile); - $this->avatarManager->method('getAvatar')->with('userId')->willReturn($this->avatarMock); - - $response = $this->avatarController->getAvatar('userId', 32); - - $this->assertEquals(Http::STATUS_OK, $response->getStatus()); - $this->assertArrayHasKey('Content-Type', $response->getHeaders()); - $this->assertEquals('image type', $response->getHeaders()['Content-Type']); - $this->assertArrayHasKey('X-NC-IsCustomAvatar', $response->getHeaders()); - $this->assertEquals('0', $response->getHeaders()['X-NC-IsCustomAvatar']); - - $this->assertEquals('my etag', $response->getETag()); - } - - /** - * Fetch the avatar of a non-existing user - */ - public function testGetAvatarNoUser(): void { - $this->avatarManager - ->method('getAvatar') - ->with('userDoesNotExist') - ->will($this->throwException(new \Exception('user does not exist'))); - - $response = $this->avatarController->getAvatar('userDoesNotExist', 32); - - //Comment out until JS is fixed - $this->assertEquals(Http::STATUS_NOT_FOUND, $response->getStatus()); - } - - public function testGetAvatarSize64(): void { - $this->avatarMock->expects($this->once()) - ->method('getFile') - ->with($this->equalTo(64)) - ->willReturn($this->avatarFile); - - $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); - - $this->logger->expects($this->never()) - ->method('debug'); - - $this->avatarController->getAvatar('userId', 64); - } - - public function testGetAvatarSize512(): void { - $this->avatarMock->expects($this->once()) - ->method('getFile') - ->with($this->equalTo(512)) - ->willReturn($this->avatarFile); - - $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); - - $this->logger->expects($this->never()) - ->method('debug'); - - $this->avatarController->getAvatar('userId', 512); - } - - /** - * Small sizes return 64 and generate a log - */ - public function testGetAvatarSizeTooSmall(): void { - $this->avatarMock->expects($this->once()) - ->method('getFile') - ->with($this->equalTo(64)) - ->willReturn($this->avatarFile); - - $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); - - $this->logger->expects($this->once()) - ->method('debug') - ->with('Avatar requested in deprecated size 32'); - - $this->avatarController->getAvatar('userId', 32); - } - - /** - * Avatars between 64 and 512 are upgraded to 512 - */ - public function testGetAvatarSizeBetween(): void { - $this->avatarMock->expects($this->once()) - ->method('getFile') - ->with($this->equalTo(512)) - ->willReturn($this->avatarFile); - - $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); - - $this->logger->expects($this->once()) - ->method('debug') - ->with('Avatar requested in deprecated size 65'); - - $this->avatarController->getAvatar('userId', 65); - } - - /** - * We do not support avatars larger than 512 - */ - public function testGetAvatarSizeTooBig(): void { - $this->avatarMock->expects($this->once()) - ->method('getFile') - ->with($this->equalTo(512)) - ->willReturn($this->avatarFile); - - $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); - - $this->logger->expects($this->once()) - ->method('debug') - ->with('Avatar requested in deprecated size 513'); - - $this->avatarController->getAvatar('userId', 513); - } - - /** - * Remove an avatar - */ - public function testDeleteAvatar(): void { - $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); - - $response = $this->avatarController->deleteAvatar(); - $this->assertEquals(Http::STATUS_OK, $response->getStatus()); - } - - /** - * Test what happens if the removing of the avatar fails - */ - public function testDeleteAvatarException(): void { - $this->avatarMock->method('remove')->will($this->throwException(new \Exception('foo'))); - $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); - - $this->logger->expects($this->once()) - ->method('error') - ->with('foo', ['exception' => new \Exception('foo'), 'app' => 'core']); - $expectedResponse = new Http\JSONResponse(['data' => ['message' => 'An error occurred. Please contact your admin.']], Http::STATUS_BAD_REQUEST); - $this->assertEquals($expectedResponse, $this->avatarController->deleteAvatar()); - } - - /** - * Trying to get a tmp avatar when it is not available. 404 - */ - public function testTmpAvatarNoTmp(): void { - $response = $this->avatarController->getTmpAvatar(); - $this->assertEquals(Http::STATUS_NOT_FOUND, $response->getStatus()); - } - - /** - * Fetch tmp avatar - */ - public function testTmpAvatarValid(): void { - $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); - - $response = $this->avatarController->getTmpAvatar(); - $this->assertEquals(Http::STATUS_OK, $response->getStatus()); - } - - - /** - * When trying to post a new avatar a path or image should be posted. - */ - public function testPostAvatarNoPathOrImage(): void { - $response = $this->avatarController->postAvatar(null); - - $this->assertEquals(Http::STATUS_BAD_REQUEST, $response->getStatus()); - } - - /** - * Test a correct post of an avatar using POST - */ - public function testPostAvatarFile(): void { - //Create temp file - $fileName = tempnam('', 'avatarTest'); - $copyRes = copy(\OC::$SERVERROOT.'/tests/data/testimage.jpg', $fileName); - $this->assertTrue($copyRes); - - //Create file in cache - $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); - - //Create request return - $reqRet = ['error' => [0], 'tmp_name' => [$fileName], 'size' => [filesize(\OC::$SERVERROOT.'/tests/data/testimage.jpg')]]; - $this->request->method('getUploadedFile')->willReturn($reqRet); - - $response = $this->avatarController->postAvatar(null); - - //On correct upload always respond with the notsquare message - $this->assertEquals('notsquare', $response->getData()['data']); - - //File should be deleted - $this->assertFalse(file_exists($fileName)); - } - - /** - * Test invalid post os an avatar using POST - */ - public function testPostAvatarInvalidFile(): void { - //Create request return - $reqRet = ['error' => [1], 'tmp_name' => ['foo']]; - $this->request->method('getUploadedFile')->willReturn($reqRet); - - $response = $this->avatarController->postAvatar(null); - - $this->assertEquals(Http::STATUS_BAD_REQUEST, $response->getStatus()); - } - - /** - * Check what happens when we upload a GIF - */ - public function testPostAvatarFileGif(): void { - //Create temp file - $fileName = tempnam('', 'avatarTest'); - $copyRes = copy(\OC::$SERVERROOT.'/tests/data/testimage.gif', $fileName); - $this->assertTrue($copyRes); - - //Create file in cache - $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.gif')); - - //Create request return - $reqRet = ['error' => [0], 'tmp_name' => [$fileName], 'size' => [filesize(\OC::$SERVERROOT.'/tests/data/testimage.gif')]]; - $this->request->method('getUploadedFile')->willReturn($reqRet); - - $response = $this->avatarController->postAvatar(null); - - $this->assertEquals('Unknown filetype', $response->getData()['data']['message']); - - //File should be deleted - $this->assertFalse(file_exists($fileName)); - } - - /** - * Test posting avatar from existing file - */ - public function testPostAvatarFromFile(): void { - //Mock node API call - $file = $this->getMockBuilder('OCP\Files\File') - ->disableOriginalConstructor()->getMock(); - $file->expects($this->once()) - ->method('getContent') - ->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); - $file->expects($this->once()) - ->method('getMimeType') - ->willReturn('image/jpeg'); - $userFolder = $this->getMockBuilder('OCP\Files\Folder')->getMock(); - $this->rootFolder->method('getUserFolder')->with('userid')->willReturn($userFolder); - $userFolder->method('get')->willReturn($file); - - //Create request return - $response = $this->avatarController->postAvatar('avatar.jpg'); - - //On correct upload always respond with the notsquare message - $this->assertEquals('notsquare', $response->getData()['data']); - } - - /** - * Test posting avatar from existing folder - */ - public function testPostAvatarFromNoFile(): void { - $file = $this->getMockBuilder('OCP\Files\Node')->getMock(); - $userFolder = $this->getMockBuilder('OCP\Files\Folder')->getMock(); - $this->rootFolder->method('getUserFolder')->with('userid')->willReturn($userFolder); - $userFolder - ->method('get') - ->with('folder') - ->willReturn($file); - - //Create request return - $response = $this->avatarController->postAvatar('folder'); - - //On correct upload always respond with the notsquare message - $this->assertEquals(['data' => ['message' => 'Please select a file.']], $response->getData()); - } - - public function testPostAvatarInvalidType(): void { - $file = $this->getMockBuilder('OCP\Files\File') - ->disableOriginalConstructor()->getMock(); - $file->expects($this->never()) - ->method('getContent'); - $file->expects($this->exactly(2)) - ->method('getMimeType') - ->willReturn('text/plain'); - $userFolder = $this->getMockBuilder('OCP\Files\Folder')->getMock(); - $this->rootFolder->method('getUserFolder')->with('userid')->willReturn($userFolder); - $userFolder->method('get')->willReturn($file); - - $expectedResponse = new Http\JSONResponse(['data' => ['message' => 'The selected file is not an image.']], Http::STATUS_BAD_REQUEST); - $this->assertEquals($expectedResponse, $this->avatarController->postAvatar('avatar.jpg')); - } - - public function testPostAvatarNotPermittedException(): void { - $file = $this->getMockBuilder('OCP\Files\File') - ->disableOriginalConstructor()->getMock(); - $file->expects($this->once()) - ->method('getContent') - ->willThrowException(new NotPermittedException()); - $file->expects($this->once()) - ->method('getMimeType') - ->willReturn('image/jpeg'); - $userFolder = $this->getMockBuilder('OCP\Files\Folder')->getMock(); - $this->rootFolder->method('getUserFolder')->with('userid')->willReturn($userFolder); - $userFolder->method('get')->willReturn($file); - - $expectedResponse = new Http\JSONResponse(['data' => ['message' => 'The selected file cannot be read.']], Http::STATUS_BAD_REQUEST); - $this->assertEquals($expectedResponse, $this->avatarController->postAvatar('avatar.jpg')); - } - - /** - * Test what happens if the upload of the avatar fails - */ - public function testPostAvatarException(): void { - $this->cache->expects($this->once()) - ->method('set') - ->will($this->throwException(new \Exception('foo'))); - $file = $this->getMockBuilder('OCP\Files\File') - ->disableOriginalConstructor()->getMock(); - $file->expects($this->once()) - ->method('getContent') - ->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); - $file->expects($this->once()) - ->method('getMimeType') - ->willReturn('image/jpeg'); - $userFolder = $this->getMockBuilder('OCP\Files\Folder')->getMock(); - $this->rootFolder->method('getUserFolder')->with('userid')->willReturn($userFolder); - $userFolder->method('get')->willReturn($file); - - $this->logger->expects($this->once()) - ->method('error') - ->with('foo', ['exception' => new \Exception('foo'), 'app' => 'core']); - $expectedResponse = new Http\JSONResponse(['data' => ['message' => 'An error occurred. Please contact your admin.']], Http::STATUS_OK); - $this->assertEquals($expectedResponse, $this->avatarController->postAvatar('avatar.jpg')); - } - - - /** - * Test invalid crop argument - */ - public function testPostCroppedAvatarInvalidCrop(): void { - $response = $this->avatarController->postCroppedAvatar([]); - - $this->assertEquals(Http::STATUS_BAD_REQUEST, $response->getStatus()); - } - - /** - * Test no tmp avatar to crop - */ - public function testPostCroppedAvatarNoTmpAvatar(): void { - $response = $this->avatarController->postCroppedAvatar(['x' => 0, 'y' => 0, 'w' => 10, 'h' => 10]); - - $this->assertEquals(Http::STATUS_BAD_REQUEST, $response->getStatus()); - } - - /** - * Test with non square crop - */ - public function testPostCroppedAvatarNoSquareCrop(): void { - $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); - - $this->avatarMock->method('set')->will($this->throwException(new \OC\NotSquareException)); - $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); - $response = $this->avatarController->postCroppedAvatar(['x' => 0, 'y' => 0, 'w' => 10, 'h' => 11]); - - $this->assertEquals(Http::STATUS_BAD_REQUEST, $response->getStatus()); - } - - /** - * Check for proper reply on proper crop argument - */ - public function testPostCroppedAvatarValidCrop(): void { - $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); - $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); - $response = $this->avatarController->postCroppedAvatar(['x' => 0, 'y' => 0, 'w' => 10, 'h' => 10]); - - $this->assertEquals(Http::STATUS_OK, $response->getStatus()); - $this->assertEquals('success', $response->getData()['status']); - } - - /** - * Test what happens if the cropping of the avatar fails - */ - public function testPostCroppedAvatarException(): void { - $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); - - $this->avatarMock->method('set')->will($this->throwException(new \Exception('foo'))); - $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); - - $this->logger->expects($this->once()) - ->method('error') - ->with('foo', ['exception' => new \Exception('foo'), 'app' => 'core']); - $expectedResponse = new Http\JSONResponse(['data' => ['message' => 'An error occurred. Please contact your admin.']], Http::STATUS_BAD_REQUEST); - $this->assertEquals($expectedResponse, $this->avatarController->postCroppedAvatar(['x' => 0, 'y' => 0, 'w' => 10, 'h' => 11])); - } - - - /** - * Check for proper reply on proper crop argument - */ - public function testFileTooBig(): void { - $fileName = \OC::$SERVERROOT.'/tests/data/testimage.jpg'; - //Create request return - $reqRet = ['error' => [0], 'tmp_name' => [$fileName], 'size' => [21 * 1024 * 1024]]; - $this->request->method('getUploadedFile')->willReturn($reqRet); - - $response = $this->avatarController->postAvatar(null); - - $this->assertEquals('File is too big', $response->getData()['data']['message']); - } -} +<?php +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace OC\Core\Controller; + +/** + * Overwrite is_uploaded_file in the OC\Core\Controller namespace to allow + * proper unit testing of the postAvatar call. + */ +function is_uploaded_file($filename) { + return file_exists($filename); +} + +namespace Tests\Core\Controller; + +use OC\AppFramework\Utility\TimeFactory; +use OC\Core\Controller\AvatarController; +use OC\Core\Controller\GuestAvatarController; +use OCP\AppFramework\Http; +use OCP\Files\File; +use OCP\Files\IRootFolder; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; +use OCP\Files\SimpleFS\ISimpleFile; +use OCP\IAvatar; +use OCP\IAvatarManager; +use OCP\ICache; +use OCP\IL10N; +use OCP\IRequest; +use OCP\IUser; +use OCP\IUserManager; +use Psr\Log\LoggerInterface; + +/** + * Class AvatarControllerTest + * + * @package OC\Core\Controller + */ +class AvatarControllerTest extends \Test\TestCase { + /** @var AvatarController */ + private $avatarController; + /** @var GuestAvatarController */ + private $guestAvatarController; + + /** @var IAvatar|\PHPUnit\Framework\MockObject\MockObject */ + private $avatarMock; + /** @var IUser|\PHPUnit\Framework\MockObject\MockObject */ + private $userMock; + /** @var ISimpleFile|\PHPUnit\Framework\MockObject\MockObject */ + private $avatarFile; + /** @var IAvatarManager|\PHPUnit\Framework\MockObject\MockObject */ + private $avatarManager; + /** @var ICache|\PHPUnit\Framework\MockObject\MockObject */ + private $cache; + /** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */ + private $l; + /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */ + private $userManager; + /** @var IRootFolder|\PHPUnit\Framework\MockObject\MockObject */ + private $rootFolder; + /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */ + private $logger; + /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */ + private $request; + /** @var TimeFactory|\PHPUnit\Framework\MockObject\MockObject */ + private $timeFactory; + + protected function setUp(): void { + parent::setUp(); + + $this->avatarManager = $this->getMockBuilder(\OCP\IAvatarManager::class)->getMock(); + $this->cache = $this->getMockBuilder(\OCP\ICache::class) + ->disableOriginalConstructor()->getMock(); + $this->l = $this->getMockBuilder(IL10N::class)->getMock(); + $this->l->method('t')->willReturnArgument(0); + $this->userManager = $this->getMockBuilder(IUserManager::class)->getMock(); + $this->request = $this->getMockBuilder(IRequest::class)->getMock(); + $this->rootFolder = $this->getMockBuilder(\OCP\Files\IRootFolder::class)->getMock(); + $this->logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); + $this->timeFactory = $this->getMockBuilder(\OC\AppFramework\Utility\TimeFactory::class)->getMock(); + + $this->avatarMock = $this->getMockBuilder(\OCP\IAvatar::class)->getMock(); + $this->userMock = $this->getMockBuilder(IUser::class)->getMock(); + + $this->guestAvatarController = new GuestAvatarController( + 'core', + $this->request, + $this->avatarManager, + $this->logger + ); + + $this->avatarController = new AvatarController( + 'core', + $this->request, + $this->avatarManager, + $this->cache, + $this->l, + $this->userManager, + $this->rootFolder, + $this->logger, + 'userid', + $this->timeFactory, + $this->guestAvatarController, + ); + + // Configure userMock + $this->userMock->method('getDisplayName')->willReturn('displayName'); + $this->userMock->method('getUID')->willReturn('userId'); + $this->userManager->method('get') + ->willReturnMap([['userId', $this->userMock]]); + + $this->avatarFile = $this->getMockBuilder(ISimpleFile::class)->getMock(); + $this->avatarFile->method('getContent')->willReturn('image data'); + $this->avatarFile->method('getMimeType')->willReturn('image type'); + $this->avatarFile->method('getEtag')->willReturn('my etag'); + $this->avatarFile->method('getName')->willReturn('my name'); + $this->avatarFile->method('getMTime')->willReturn(42); + } + + protected function tearDown(): void { + parent::tearDown(); + } + + /** + * Fetch an avatar if a user has no avatar + */ + public function testGetAvatarNoAvatar(): void { + $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); + $this->avatarMock->method('getFile')->will($this->throwException(new NotFoundException())); + $response = $this->avatarController->getAvatar('userId', 32); + + //Comment out until JS is fixed + $this->assertEquals(Http::STATUS_NOT_FOUND, $response->getStatus()); + } + + /** + * Fetch the user's avatar + */ + public function testGetAvatar(): void { + $this->avatarMock->method('getFile')->willReturn($this->avatarFile); + $this->avatarManager->method('getAvatar')->with('userId')->willReturn($this->avatarMock); + $this->avatarMock->expects($this->once()) + ->method('isCustomAvatar') + ->willReturn(true); + + $response = $this->avatarController->getAvatar('userId', 32); + + $this->assertEquals(Http::STATUS_OK, $response->getStatus()); + $this->assertArrayHasKey('Content-Type', $response->getHeaders()); + $this->assertEquals('image type', $response->getHeaders()['Content-Type']); + $this->assertArrayHasKey('X-NC-IsCustomAvatar', $response->getHeaders()); + $this->assertEquals('1', $response->getHeaders()['X-NC-IsCustomAvatar']); + + $this->assertEquals('my etag', $response->getETag()); + } + + /** + * Fetch the user's avatar + */ + public function testGetGeneratedAvatar(): void { + $this->avatarMock->method('getFile')->willReturn($this->avatarFile); + $this->avatarManager->method('getAvatar')->with('userId')->willReturn($this->avatarMock); + + $response = $this->avatarController->getAvatar('userId', 32); + + $this->assertEquals(Http::STATUS_OK, $response->getStatus()); + $this->assertArrayHasKey('Content-Type', $response->getHeaders()); + $this->assertEquals('image type', $response->getHeaders()['Content-Type']); + $this->assertArrayHasKey('X-NC-IsCustomAvatar', $response->getHeaders()); + $this->assertEquals('0', $response->getHeaders()['X-NC-IsCustomAvatar']); + + $this->assertEquals('my etag', $response->getETag()); + } + + /** + * Fetch the avatar of a non-existing user + */ + public function testGetAvatarNoUser(): void { + $this->avatarManager + ->method('getAvatar') + ->with('userDoesNotExist') + ->will($this->throwException(new \Exception('user does not exist'))); + + $response = $this->avatarController->getAvatar('userDoesNotExist', 32); + + //Comment out until JS is fixed + $this->assertEquals(Http::STATUS_NOT_FOUND, $response->getStatus()); + } + + public function testGetAvatarSize64(): void { + $this->avatarMock->expects($this->once()) + ->method('getFile') + ->with($this->equalTo(64)) + ->willReturn($this->avatarFile); + + $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); + + $this->logger->expects($this->never()) + ->method('debug'); + + $this->avatarController->getAvatar('userId', 64); + } + + public function testGetAvatarSize512(): void { + $this->avatarMock->expects($this->once()) + ->method('getFile') + ->with($this->equalTo(512)) + ->willReturn($this->avatarFile); + + $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); + + $this->logger->expects($this->never()) + ->method('debug'); + + $this->avatarController->getAvatar('userId', 512); + } + + /** + * Small sizes return 64 and generate a log + */ + public function testGetAvatarSizeTooSmall(): void { + $this->avatarMock->expects($this->once()) + ->method('getFile') + ->with($this->equalTo(64)) + ->willReturn($this->avatarFile); + + $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); + + $this->logger->expects($this->once()) + ->method('debug') + ->with('Avatar requested in deprecated size 32'); + + $this->avatarController->getAvatar('userId', 32); + } + + /** + * Avatars between 64 and 512 are upgraded to 512 + */ + public function testGetAvatarSizeBetween(): void { + $this->avatarMock->expects($this->once()) + ->method('getFile') + ->with($this->equalTo(512)) + ->willReturn($this->avatarFile); + + $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); + + $this->logger->expects($this->once()) + ->method('debug') + ->with('Avatar requested in deprecated size 65'); + + $this->avatarController->getAvatar('userId', 65); + } + + /** + * We do not support avatars larger than 512 + */ + public function testGetAvatarSizeTooBig(): void { + $this->avatarMock->expects($this->once()) + ->method('getFile') + ->with($this->equalTo(512)) + ->willReturn($this->avatarFile); + + $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); + + $this->logger->expects($this->once()) + ->method('debug') + ->with('Avatar requested in deprecated size 513'); + + $this->avatarController->getAvatar('userId', 513); + } + + /** + * Remove an avatar + */ + public function testDeleteAvatar(): void { + $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); + + $response = $this->avatarController->deleteAvatar(); + $this->assertEquals(Http::STATUS_OK, $response->getStatus()); + } + + /** + * Test what happens if the removing of the avatar fails + */ + public function testDeleteAvatarException(): void { + $this->avatarMock->method('remove')->will($this->throwException(new \Exception('foo'))); + $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); + + $this->logger->expects($this->once()) + ->method('error') + ->with('foo', ['exception' => new \Exception('foo'), 'app' => 'core']); + $expectedResponse = new Http\JSONResponse(['data' => ['message' => 'An error occurred. Please contact your admin.']], Http::STATUS_BAD_REQUEST); + $this->assertEquals($expectedResponse, $this->avatarController->deleteAvatar()); + } + + /** + * Trying to get a tmp avatar when it is not available. 404 + */ + public function testTmpAvatarNoTmp(): void { + $response = $this->avatarController->getTmpAvatar(); + $this->assertEquals(Http::STATUS_NOT_FOUND, $response->getStatus()); + } + + /** + * Fetch tmp avatar + */ + public function testTmpAvatarValid(): void { + $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); + + $response = $this->avatarController->getTmpAvatar(); + $this->assertEquals(Http::STATUS_OK, $response->getStatus()); + } + + + /** + * When trying to post a new avatar a path or image should be posted. + */ + public function testPostAvatarNoPathOrImage(): void { + $response = $this->avatarController->postAvatar(null); + + $this->assertEquals(Http::STATUS_BAD_REQUEST, $response->getStatus()); + } + + /** + * Test a correct post of an avatar using POST + */ + public function testPostAvatarFile(): void { + //Create temp file + $fileName = tempnam('', 'avatarTest'); + $copyRes = copy(\OC::$SERVERROOT.'/tests/data/testimage.jpg', $fileName); + $this->assertTrue($copyRes); + + //Create file in cache + $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); + + //Create request return + $reqRet = ['error' => [0], 'tmp_name' => [$fileName], 'size' => [filesize(\OC::$SERVERROOT.'/tests/data/testimage.jpg')]]; + $this->request->method('getUploadedFile')->willReturn($reqRet); + + $response = $this->avatarController->postAvatar(null); + + //On correct upload always respond with the notsquare message + $this->assertEquals('notsquare', $response->getData()['data']); + + //File should be deleted + $this->assertFalse(file_exists($fileName)); + } + + /** + * Test invalid post os an avatar using POST + */ + public function testPostAvatarInvalidFile(): void { + //Create request return + $reqRet = ['error' => [1], 'tmp_name' => ['foo']]; + $this->request->method('getUploadedFile')->willReturn($reqRet); + + $response = $this->avatarController->postAvatar(null); + + $this->assertEquals(Http::STATUS_BAD_REQUEST, $response->getStatus()); + } + + /** + * Check what happens when we upload a GIF + */ + public function testPostAvatarFileGif(): void { + //Create temp file + $fileName = tempnam('', 'avatarTest'); + $copyRes = copy(\OC::$SERVERROOT.'/tests/data/testimage.gif', $fileName); + $this->assertTrue($copyRes); + + //Create file in cache + $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.gif')); + + //Create request return + $reqRet = ['error' => [0], 'tmp_name' => [$fileName], 'size' => [filesize(\OC::$SERVERROOT.'/tests/data/testimage.gif')]]; + $this->request->method('getUploadedFile')->willReturn($reqRet); + + $response = $this->avatarController->postAvatar(null); + + $this->assertEquals('Unknown filetype', $response->getData()['data']['message']); + + //File should be deleted + $this->assertFalse(file_exists($fileName)); + } + + /** + * Test posting avatar from existing file + */ + public function testPostAvatarFromFile(): void { + //Mock node API call + $file = $this->getMockBuilder(\OCP\Files\File::class) + ->disableOriginalConstructor()->getMock(); + $file->expects($this->once()) + ->method('getContent') + ->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); + $file->expects($this->once()) + ->method('getMimeType') + ->willReturn('image/jpeg'); + $userFolder = $this->getMockBuilder(\OCP\Files\Folder::class)->getMock(); + $this->rootFolder->method('getUserFolder')->with('userid')->willReturn($userFolder); + $userFolder->method('get')->willReturn($file); + + //Create request return + $response = $this->avatarController->postAvatar('avatar.jpg'); + + //On correct upload always respond with the notsquare message + $this->assertEquals('notsquare', $response->getData()['data']); + } + + /** + * Test posting avatar from existing folder + */ + public function testPostAvatarFromNoFile(): void { + $file = $this->getMockBuilder(\OCP\Files\Node::class)->getMock(); + $userFolder = $this->getMockBuilder(\OCP\Files\Folder::class)->getMock(); + $this->rootFolder->method('getUserFolder')->with('userid')->willReturn($userFolder); + $userFolder + ->method('get') + ->with('folder') + ->willReturn($file); + + //Create request return + $response = $this->avatarController->postAvatar('folder'); + + //On correct upload always respond with the notsquare message + $this->assertEquals(['data' => ['message' => 'Please select a file.']], $response->getData()); + } + + public function testPostAvatarInvalidType(): void { + $file = $this->getMockBuilder(\OCP\Files\File::class) + ->disableOriginalConstructor()->getMock(); + $file->expects($this->never()) + ->method('getContent'); + $file->expects($this->exactly(2)) + ->method('getMimeType') + ->willReturn('text/plain'); + $userFolder = $this->getMockBuilder(\OCP\Files\Folder::class)->getMock(); + $this->rootFolder->method('getUserFolder')->with('userid')->willReturn($userFolder); + $userFolder->method('get')->willReturn($file); + + $expectedResponse = new Http\JSONResponse(['data' => ['message' => 'The selected file is not an image.']], Http::STATUS_BAD_REQUEST); + $this->assertEquals($expectedResponse, $this->avatarController->postAvatar('avatar.jpg')); + } + + public function testPostAvatarNotPermittedException(): void { + $file = $this->getMockBuilder(\OCP\Files\File::class) + ->disableOriginalConstructor()->getMock(); + $file->expects($this->once()) + ->method('getContent') + ->willThrowException(new NotPermittedException()); + $file->expects($this->once()) + ->method('getMimeType') + ->willReturn('image/jpeg'); + $userFolder = $this->getMockBuilder(\OCP\Files\Folder::class)->getMock(); + $this->rootFolder->method('getUserFolder')->with('userid')->willReturn($userFolder); + $userFolder->method('get')->willReturn($file); + + $expectedResponse = new Http\JSONResponse(['data' => ['message' => 'The selected file cannot be read.']], Http::STATUS_BAD_REQUEST); + $this->assertEquals($expectedResponse, $this->avatarController->postAvatar('avatar.jpg')); + } + + /** + * Test what happens if the upload of the avatar fails + */ + public function testPostAvatarException(): void { + $this->cache->expects($this->once()) + ->method('set') + ->will($this->throwException(new \Exception('foo'))); + $file = $this->getMockBuilder(\OCP\Files\File::class) + ->disableOriginalConstructor()->getMock(); + $file->expects($this->once()) + ->method('getContent') + ->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); + $file->expects($this->once()) + ->method('getMimeType') + ->willReturn('image/jpeg'); + $userFolder = $this->getMockBuilder(\OCP\Files\Folder::class)->getMock(); + $this->rootFolder->method('getUserFolder')->with('userid')->willReturn($userFolder); + $userFolder->method('get')->willReturn($file); + + $this->logger->expects($this->once()) + ->method('error') + ->with('foo', ['exception' => new \Exception('foo'), 'app' => 'core']); + $expectedResponse = new Http\JSONResponse(['data' => ['message' => 'An error occurred. Please contact your admin.']], Http::STATUS_OK); + $this->assertEquals($expectedResponse, $this->avatarController->postAvatar('avatar.jpg')); + } + + + /** + * Test invalid crop argument + */ + public function testPostCroppedAvatarInvalidCrop(): void { + $response = $this->avatarController->postCroppedAvatar([]); + + $this->assertEquals(Http::STATUS_BAD_REQUEST, $response->getStatus()); + } + + /** + * Test no tmp avatar to crop + */ + public function testPostCroppedAvatarNoTmpAvatar(): void { + $response = $this->avatarController->postCroppedAvatar(['x' => 0, 'y' => 0, 'w' => 10, 'h' => 10]); + + $this->assertEquals(Http::STATUS_BAD_REQUEST, $response->getStatus()); + } + + /** + * Test with non square crop + */ + public function testPostCroppedAvatarNoSquareCrop(): void { + $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); + + $this->avatarMock->method('set')->will($this->throwException(new \OC\NotSquareException)); + $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); + $response = $this->avatarController->postCroppedAvatar(['x' => 0, 'y' => 0, 'w' => 10, 'h' => 11]); + + $this->assertEquals(Http::STATUS_BAD_REQUEST, $response->getStatus()); + } + + /** + * Check for proper reply on proper crop argument + */ + public function testPostCroppedAvatarValidCrop(): void { + $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); + $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); + $response = $this->avatarController->postCroppedAvatar(['x' => 0, 'y' => 0, 'w' => 10, 'h' => 10]); + + $this->assertEquals(Http::STATUS_OK, $response->getStatus()); + $this->assertEquals('success', $response->getData()['status']); + } + + /** + * Test what happens if the cropping of the avatar fails + */ + public function testPostCroppedAvatarException(): void { + $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); + + $this->avatarMock->method('set')->will($this->throwException(new \Exception('foo'))); + $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); + + $this->logger->expects($this->once()) + ->method('error') + ->with('foo', ['exception' => new \Exception('foo'), 'app' => 'core']); + $expectedResponse = new Http\JSONResponse(['data' => ['message' => 'An error occurred. Please contact your admin.']], Http::STATUS_BAD_REQUEST); + $this->assertEquals($expectedResponse, $this->avatarController->postCroppedAvatar(['x' => 0, 'y' => 0, 'w' => 10, 'h' => 11])); + } + + + /** + * Check for proper reply on proper crop argument + */ + public function testFileTooBig(): void { + $fileName = \OC::$SERVERROOT.'/tests/data/testimage.jpg'; + //Create request return + $reqRet = ['error' => [0], 'tmp_name' => [$fileName], 'size' => [21 * 1024 * 1024]]; + $this->request->method('getUploadedFile')->willReturn($reqRet); + + $response = $this->avatarController->postAvatar(null); + + $this->assertEquals('File is too big', $response->getData()['data']['message']); + } +} diff --git a/tests/Core/Controller/LostControllerTest.php b/tests/Core/Controller/LostControllerTest.php index 2a99c9f9d16..0f4a5f41f84 100644 --- a/tests/Core/Controller/LostControllerTest.php +++ b/tests/Core/Controller/LostControllerTest.php @@ -244,7 +244,7 @@ class LostControllerTest extends TestCase { ->method('linkToRouteAbsolute') ->with('core.lost.resetform', ['userId' => 'ExistingUser', 'token' => 'ThisIsMaybeANotSoSecretToken!']) ->willReturn('https://example.tld/index.php/lostpassword/'); - $message = $this->getMockBuilder('\OC\Mail\Message') + $message = $this->getMockBuilder(\OC\Mail\Message::class) ->disableOriginalConstructor()->getMock(); $message ->expects($this->once()) @@ -306,7 +306,7 @@ class LostControllerTest extends TestCase { ->method('linkToRouteAbsolute') ->with('core.lost.resetform', ['userId' => 'ExistingUser', 'token' => 'ThisIsMaybeANotSoSecretToken!']) ->willReturn('https://example.tld/index.php/lostpassword/'); - $message = $this->getMockBuilder('\OC\Mail\Message') + $message = $this->getMockBuilder(\OC\Mail\Message::class) ->disableOriginalConstructor()->getMock(); $message ->expects($this->once()) diff --git a/tests/lib/Activity/ManagerTest.php b/tests/lib/Activity/ManagerTest.php index bb73aea4f6d..c042a3a76a7 100644 --- a/tests/lib/Activity/ManagerTest.php +++ b/tests/lib/Activity/ManagerTest.php @@ -221,7 +221,7 @@ class ManagerTest extends TestCase { ->setAffectedUser('test_affected') ->setObject('file', 123); - $consumer = $this->getMockBuilder('OCP\Activity\IConsumer') + $consumer = $this->getMockBuilder(\OCP\Activity\IConsumer::class) ->disableOriginalConstructor() ->getMock(); $consumer->expects($this->once()) @@ -252,7 +252,7 @@ class ManagerTest extends TestCase { ->setLink('test_link') ; - $consumer = $this->getMockBuilder('OCP\Activity\IConsumer') + $consumer = $this->getMockBuilder(\OCP\Activity\IConsumer::class) ->disableOriginalConstructor() ->getMock(); $consumer->expects($this->once()) diff --git a/tests/lib/AllConfigTest.php b/tests/lib/AllConfigTest.php index f8b2e8e857f..ed3079e4c92 100644 --- a/tests/lib/AllConfigTest.php +++ b/tests/lib/AllConfigTest.php @@ -30,7 +30,7 @@ class AllConfigTest extends \Test\TestCase { $connection = $this->connection; } if ($systemConfig === null) { - $systemConfig = $this->getMockBuilder('\OC\SystemConfig') + $systemConfig = $this->getMockBuilder(\OC\SystemConfig::class) ->disableOriginalConstructor() ->getMock(); } @@ -465,7 +465,7 @@ class AllConfigTest extends \Test\TestCase { public function testGetUsersForUserValue(): void { // mock the check for the database to run the correct SQL statements for each database type - $systemConfig = $this->getMockBuilder('\OC\SystemConfig') + $systemConfig = $this->getMockBuilder(\OC\SystemConfig::class) ->disableOriginalConstructor() ->getMock(); $config = $this->getConfig($systemConfig); diff --git a/tests/lib/AppFramework/AppTest.php b/tests/lib/AppFramework/AppTest.php index 3c535a4bf7a..c23c94716f2 100644 --- a/tests/lib/AppFramework/AppTest.php +++ b/tests/lib/AppFramework/AppTest.php @@ -1,221 +1,221 @@ -<?php - -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -namespace Test\AppFramework; - -use OC\AppFramework\App; -use OC\AppFramework\Http\Dispatcher; -use OCP\AppFramework\Controller; -use OCP\AppFramework\Http; -use OCP\AppFramework\Http\Response; - -function rrmdir($directory) { - $files = array_diff(scandir($directory), ['.','..']); - foreach ($files as $file) { - if (is_dir($directory . '/' . $file)) { - rrmdir($directory . '/' . $file); - } else { - unlink($directory . '/' . $file); - } - } - return rmdir($directory); -} - - -class AppTest extends \Test\TestCase { - private $container; - private $io; - private $api; - private $controller; - private $dispatcher; - private $params; - private $headers; - private $output; - private $controllerName; - private $controllerMethod; - private $appPath; - - protected function setUp(): void { - parent::setUp(); - - $this->container = new \OC\AppFramework\DependencyInjection\DIContainer('test', []); - $this->controller = $this->createMock(Controller::class); - $this->dispatcher = $this->createMock(Dispatcher::class); - $this->io = $this->createMock(Http\IOutput::class); - - $this->headers = ['key' => 'value']; - $this->output = 'hi'; - $this->controllerName = 'Controller'; - $this->controllerMethod = 'method'; - - $this->container[$this->controllerName] = $this->controller; - $this->container['Dispatcher'] = $this->dispatcher; - $this->container['OCP\\AppFramework\\Http\\IOutput'] = $this->io; - $this->container['urlParams'] = ['_route' => 'not-profiler']; - - $this->appPath = __DIR__ . '/../../../apps/namespacetestapp'; - $infoXmlPath = $this->appPath . '/appinfo/info.xml'; - mkdir($this->appPath . '/appinfo', 0777, true); - - $xml = '<?xml version="1.0" encoding="UTF-8"?>' . - '<info>' . - '<id>namespacetestapp</id>' . - '<namespace>NameSpaceTestApp</namespace>' . - '</info>'; - file_put_contents($infoXmlPath, $xml); - } - - - public function testControllerNameAndMethodAreBeingPassed(): void { - $return = ['HTTP/2.0 200 OK', [], [], null, new Response()]; - $this->dispatcher->expects($this->once()) - ->method('dispatch') - ->with($this->equalTo($this->controller), - $this->equalTo($this->controllerMethod)) - ->willReturn($return); - - $this->io->expects($this->never()) - ->method('setOutput'); - - App::main($this->controllerName, $this->controllerMethod, - $this->container); - } - - - public function testBuildAppNamespace(): void { - $ns = App::buildAppNamespace('someapp'); - $this->assertEquals('OCA\Someapp', $ns); - } - - - public function testBuildAppNamespaceCore(): void { - $ns = App::buildAppNamespace('someapp', 'OC\\'); - $this->assertEquals('OC\Someapp', $ns); - } - - - public function testBuildAppNamespaceInfoXml(): void { - $ns = App::buildAppNamespace('namespacetestapp', 'OCA\\'); - $this->assertEquals('OCA\NameSpaceTestApp', $ns); - } - - - protected function tearDown(): void { - rrmdir($this->appPath); - parent::tearDown(); - } - - - public function testOutputIsPrinted(): void { - $return = ['HTTP/2.0 200 OK', [], [], $this->output, new Response()]; - $this->dispatcher->expects($this->once()) - ->method('dispatch') - ->with($this->equalTo($this->controller), - $this->equalTo($this->controllerMethod)) - ->willReturn($return); - $this->io->expects($this->once()) - ->method('setOutput') - ->with($this->equalTo($this->output)); - App::main($this->controllerName, $this->controllerMethod, $this->container, []); - } - - public function dataNoOutput() { - return [ - ['HTTP/2.0 204 No content'], - ['HTTP/2.0 304 Not modified'], - ]; - } - - /** - * @dataProvider dataNoOutput - */ - public function testNoOutput(string $statusCode): void { - $return = [$statusCode, [], [], $this->output, new Response()]; - $this->dispatcher->expects($this->once()) - ->method('dispatch') - ->with($this->equalTo($this->controller), - $this->equalTo($this->controllerMethod)) - ->willReturn($return); - $this->io->expects($this->once()) - ->method('setHeader') - ->with($this->equalTo($statusCode)); - $this->io->expects($this->never()) - ->method('setOutput'); - App::main($this->controllerName, $this->controllerMethod, $this->container, []); - } - - - public function testCallbackIsCalled(): void { - $mock = $this->getMockBuilder('OCP\AppFramework\Http\ICallbackResponse') - ->getMock(); - - $return = ['HTTP/2.0 200 OK', [], [], $this->output, $mock]; - $this->dispatcher->expects($this->once()) - ->method('dispatch') - ->with($this->equalTo($this->controller), - $this->equalTo($this->controllerMethod)) - ->willReturn($return); - $mock->expects($this->once()) - ->method('callback'); - App::main($this->controllerName, $this->controllerMethod, $this->container, []); - } - - public function testCoreApp(): void { - $this->container['AppName'] = 'core'; - $this->container['OC\Core\Controller\Foo'] = $this->controller; - $this->container['urlParams'] = ['_route' => 'not-profiler']; - - $return = ['HTTP/2.0 200 OK', [], [], null, new Response()]; - $this->dispatcher->expects($this->once()) - ->method('dispatch') - ->with($this->equalTo($this->controller), - $this->equalTo($this->controllerMethod)) - ->willReturn($return); - - $this->io->expects($this->never()) - ->method('setOutput'); - - App::main('Foo', $this->controllerMethod, $this->container); - } - - public function testSettingsApp(): void { - $this->container['AppName'] = 'settings'; - $this->container['OCA\Settings\Controller\Foo'] = $this->controller; - $this->container['urlParams'] = ['_route' => 'not-profiler']; - - $return = ['HTTP/2.0 200 OK', [], [], null, new Response()]; - $this->dispatcher->expects($this->once()) - ->method('dispatch') - ->with($this->equalTo($this->controller), - $this->equalTo($this->controllerMethod)) - ->willReturn($return); - - $this->io->expects($this->never()) - ->method('setOutput'); - - App::main('Foo', $this->controllerMethod, $this->container); - } - - public function testApp(): void { - $this->container['AppName'] = 'bar'; - $this->container['OCA\Bar\Controller\Foo'] = $this->controller; - $this->container['urlParams'] = ['_route' => 'not-profiler']; - - $return = ['HTTP/2.0 200 OK', [], [], null, new Response()]; - $this->dispatcher->expects($this->once()) - ->method('dispatch') - ->with($this->equalTo($this->controller), - $this->equalTo($this->controllerMethod)) - ->willReturn($return); - - $this->io->expects($this->never()) - ->method('setOutput'); - - App::main('Foo', $this->controllerMethod, $this->container); - } -} +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\AppFramework; + +use OC\AppFramework\App; +use OC\AppFramework\Http\Dispatcher; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Response; + +function rrmdir($directory) { + $files = array_diff(scandir($directory), ['.','..']); + foreach ($files as $file) { + if (is_dir($directory . '/' . $file)) { + rrmdir($directory . '/' . $file); + } else { + unlink($directory . '/' . $file); + } + } + return rmdir($directory); +} + + +class AppTest extends \Test\TestCase { + private $container; + private $io; + private $api; + private $controller; + private $dispatcher; + private $params; + private $headers; + private $output; + private $controllerName; + private $controllerMethod; + private $appPath; + + protected function setUp(): void { + parent::setUp(); + + $this->container = new \OC\AppFramework\DependencyInjection\DIContainer('test', []); + $this->controller = $this->createMock(Controller::class); + $this->dispatcher = $this->createMock(Dispatcher::class); + $this->io = $this->createMock(Http\IOutput::class); + + $this->headers = ['key' => 'value']; + $this->output = 'hi'; + $this->controllerName = 'Controller'; + $this->controllerMethod = 'method'; + + $this->container[$this->controllerName] = $this->controller; + $this->container['Dispatcher'] = $this->dispatcher; + $this->container[\OCP\AppFramework\Http\IOutput::class] = $this->io; + $this->container['urlParams'] = ['_route' => 'not-profiler']; + + $this->appPath = __DIR__ . '/../../../apps/namespacetestapp'; + $infoXmlPath = $this->appPath . '/appinfo/info.xml'; + mkdir($this->appPath . '/appinfo', 0777, true); + + $xml = '<?xml version="1.0" encoding="UTF-8"?>' . + '<info>' . + '<id>namespacetestapp</id>' . + '<namespace>NameSpaceTestApp</namespace>' . + '</info>'; + file_put_contents($infoXmlPath, $xml); + } + + + public function testControllerNameAndMethodAreBeingPassed(): void { + $return = ['HTTP/2.0 200 OK', [], [], null, new Response()]; + $this->dispatcher->expects($this->once()) + ->method('dispatch') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod)) + ->willReturn($return); + + $this->io->expects($this->never()) + ->method('setOutput'); + + App::main($this->controllerName, $this->controllerMethod, + $this->container); + } + + + public function testBuildAppNamespace(): void { + $ns = App::buildAppNamespace('someapp'); + $this->assertEquals('OCA\Someapp', $ns); + } + + + public function testBuildAppNamespaceCore(): void { + $ns = App::buildAppNamespace('someapp', 'OC\\'); + $this->assertEquals('OC\Someapp', $ns); + } + + + public function testBuildAppNamespaceInfoXml(): void { + $ns = App::buildAppNamespace('namespacetestapp', 'OCA\\'); + $this->assertEquals('OCA\NameSpaceTestApp', $ns); + } + + + protected function tearDown(): void { + rrmdir($this->appPath); + parent::tearDown(); + } + + + public function testOutputIsPrinted(): void { + $return = ['HTTP/2.0 200 OK', [], [], $this->output, new Response()]; + $this->dispatcher->expects($this->once()) + ->method('dispatch') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod)) + ->willReturn($return); + $this->io->expects($this->once()) + ->method('setOutput') + ->with($this->equalTo($this->output)); + App::main($this->controllerName, $this->controllerMethod, $this->container, []); + } + + public function dataNoOutput() { + return [ + ['HTTP/2.0 204 No content'], + ['HTTP/2.0 304 Not modified'], + ]; + } + + /** + * @dataProvider dataNoOutput + */ + public function testNoOutput(string $statusCode): void { + $return = [$statusCode, [], [], $this->output, new Response()]; + $this->dispatcher->expects($this->once()) + ->method('dispatch') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod)) + ->willReturn($return); + $this->io->expects($this->once()) + ->method('setHeader') + ->with($this->equalTo($statusCode)); + $this->io->expects($this->never()) + ->method('setOutput'); + App::main($this->controllerName, $this->controllerMethod, $this->container, []); + } + + + public function testCallbackIsCalled(): void { + $mock = $this->getMockBuilder(\OCP\AppFramework\Http\ICallbackResponse::class) + ->getMock(); + + $return = ['HTTP/2.0 200 OK', [], [], $this->output, $mock]; + $this->dispatcher->expects($this->once()) + ->method('dispatch') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod)) + ->willReturn($return); + $mock->expects($this->once()) + ->method('callback'); + App::main($this->controllerName, $this->controllerMethod, $this->container, []); + } + + public function testCoreApp(): void { + $this->container['AppName'] = 'core'; + $this->container['OC\Core\Controller\Foo'] = $this->controller; + $this->container['urlParams'] = ['_route' => 'not-profiler']; + + $return = ['HTTP/2.0 200 OK', [], [], null, new Response()]; + $this->dispatcher->expects($this->once()) + ->method('dispatch') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod)) + ->willReturn($return); + + $this->io->expects($this->never()) + ->method('setOutput'); + + App::main('Foo', $this->controllerMethod, $this->container); + } + + public function testSettingsApp(): void { + $this->container['AppName'] = 'settings'; + $this->container['OCA\Settings\Controller\Foo'] = $this->controller; + $this->container['urlParams'] = ['_route' => 'not-profiler']; + + $return = ['HTTP/2.0 200 OK', [], [], null, new Response()]; + $this->dispatcher->expects($this->once()) + ->method('dispatch') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod)) + ->willReturn($return); + + $this->io->expects($this->never()) + ->method('setOutput'); + + App::main('Foo', $this->controllerMethod, $this->container); + } + + public function testApp(): void { + $this->container['AppName'] = 'bar'; + $this->container['OCA\Bar\Controller\Foo'] = $this->controller; + $this->container['urlParams'] = ['_route' => 'not-profiler']; + + $return = ['HTTP/2.0 200 OK', [], [], null, new Response()]; + $this->dispatcher->expects($this->once()) + ->method('dispatch') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod)) + ->willReturn($return); + + $this->io->expects($this->never()) + ->method('setOutput'); + + App::main('Foo', $this->controllerMethod, $this->container); + } +} diff --git a/tests/lib/AppFramework/Http/DispatcherTest.php b/tests/lib/AppFramework/Http/DispatcherTest.php index 94bcfcc4af2..8ed8732ba7f 100644 --- a/tests/lib/AppFramework/Http/DispatcherTest.php +++ b/tests/lib/AppFramework/Http/DispatcherTest.php @@ -105,11 +105,11 @@ class DispatcherTest extends \Test\TestCase { $this->eventLogger = $this->createMock(IEventLogger::class); $this->container = $this->createMock(ContainerInterface::class); $app = $this->getMockBuilder( - 'OC\AppFramework\DependencyInjection\DIContainer') + \OC\AppFramework\DependencyInjection\DIContainer::class) ->disableOriginalConstructor() ->getMock(); $request = $this->getMockBuilder( - '\OC\AppFramework\Http\Request') + \OC\AppFramework\Http\Request::class) ->disableOriginalConstructor() ->getMock(); $this->http = $this->getMockBuilder( @@ -118,17 +118,17 @@ class DispatcherTest extends \Test\TestCase { ->getMock(); $this->middlewareDispatcher = $this->getMockBuilder( - '\OC\AppFramework\Middleware\MiddlewareDispatcher') + \OC\AppFramework\Middleware\MiddlewareDispatcher::class) ->disableOriginalConstructor() ->getMock(); $this->controller = $this->getMockBuilder( - '\OCP\AppFramework\Controller') + \OCP\AppFramework\Controller::class) ->setMethods([$this->controllerMethod]) ->setConstructorArgs([$app, $request]) ->getMock(); $this->request = $this->getMockBuilder( - '\OC\AppFramework\Http\Request') + \OC\AppFramework\Http\Request::class) ->disableOriginalConstructor() ->getMock(); diff --git a/tests/lib/AppFramework/Http/FileDisplayResponseTest.php b/tests/lib/AppFramework/Http/FileDisplayResponseTest.php index 5f602b2e1c6..029cdab630a 100644 --- a/tests/lib/AppFramework/Http/FileDisplayResponseTest.php +++ b/tests/lib/AppFramework/Http/FileDisplayResponseTest.php @@ -1,93 +1,93 @@ -<?php -/** - * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -namespace Test\AppFramework\Http; - -use OCP\AppFramework\Http; -use OCP\AppFramework\Http\FileDisplayResponse; -use OCP\Files\File; - -class FileDisplayResponseTest extends \Test\TestCase { - /** @var File|\PHPUnit\Framework\MockObject\MockObject */ - private $file; - - /** @var FileDisplayResponse */ - private $response; - - protected function setUp(): void { - $this->file = $this->getMockBuilder('OCP\Files\File') - ->getMock(); - - $this->file->expects($this->once()) - ->method('getETag') - ->willReturn('myETag'); - $this->file->expects($this->once()) - ->method('getName') - ->willReturn('myFileName'); - $this->file->expects($this->once()) - ->method('getMTime') - ->willReturn(1464825600); - - $this->response = new FileDisplayResponse($this->file); - } - - public function testHeader(): void { - $headers = $this->response->getHeaders(); - $this->assertArrayHasKey('Content-Disposition', $headers); - $this->assertSame('inline; filename="myFileName"', $headers['Content-Disposition']); - } - - public function testETag(): void { - $this->assertSame('myETag', $this->response->getETag()); - } - - public function testLastModified(): void { - $lastModified = $this->response->getLastModified(); - $this->assertNotNull($lastModified); - $this->assertSame(1464825600, $lastModified->getTimestamp()); - } - - public function test304(): void { - $output = $this->getMockBuilder('OCP\AppFramework\Http\IOutput') - ->disableOriginalConstructor() - ->getMock(); - - $output->expects($this->any()) - ->method('getHttpResponseCode') - ->willReturn(Http::STATUS_NOT_MODIFIED); - $output->expects($this->never()) - ->method('setOutput'); - $this->file->expects($this->never()) - ->method('getContent'); - - $this->response->callback($output); - } - - - public function testNon304(): void { - $output = $this->getMockBuilder('OCP\AppFramework\Http\IOutput') - ->disableOriginalConstructor() - ->getMock(); - - $output->expects($this->any()) - ->method('getHttpResponseCode') - ->willReturn(Http::STATUS_OK); - $output->expects($this->once()) - ->method('setOutput') - ->with($this->equalTo('my data')); - $output->expects($this->once()) - ->method('setHeader') - ->with($this->equalTo('Content-Length: 42')); - $this->file->expects($this->once()) - ->method('getContent') - ->willReturn('my data'); - $this->file->expects($this->any()) - ->method('getSize') - ->willReturn(42); - - $this->response->callback($output); - } -} +<?php +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\AppFramework\Http; + +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\FileDisplayResponse; +use OCP\Files\File; + +class FileDisplayResponseTest extends \Test\TestCase { + /** @var File|\PHPUnit\Framework\MockObject\MockObject */ + private $file; + + /** @var FileDisplayResponse */ + private $response; + + protected function setUp(): void { + $this->file = $this->getMockBuilder(\OCP\Files\File::class) + ->getMock(); + + $this->file->expects($this->once()) + ->method('getETag') + ->willReturn('myETag'); + $this->file->expects($this->once()) + ->method('getName') + ->willReturn('myFileName'); + $this->file->expects($this->once()) + ->method('getMTime') + ->willReturn(1464825600); + + $this->response = new FileDisplayResponse($this->file); + } + + public function testHeader(): void { + $headers = $this->response->getHeaders(); + $this->assertArrayHasKey('Content-Disposition', $headers); + $this->assertSame('inline; filename="myFileName"', $headers['Content-Disposition']); + } + + public function testETag(): void { + $this->assertSame('myETag', $this->response->getETag()); + } + + public function testLastModified(): void { + $lastModified = $this->response->getLastModified(); + $this->assertNotNull($lastModified); + $this->assertSame(1464825600, $lastModified->getTimestamp()); + } + + public function test304(): void { + $output = $this->getMockBuilder(\OCP\AppFramework\Http\IOutput::class) + ->disableOriginalConstructor() + ->getMock(); + + $output->expects($this->any()) + ->method('getHttpResponseCode') + ->willReturn(Http::STATUS_NOT_MODIFIED); + $output->expects($this->never()) + ->method('setOutput'); + $this->file->expects($this->never()) + ->method('getContent'); + + $this->response->callback($output); + } + + + public function testNon304(): void { + $output = $this->getMockBuilder(\OCP\AppFramework\Http\IOutput::class) + ->disableOriginalConstructor() + ->getMock(); + + $output->expects($this->any()) + ->method('getHttpResponseCode') + ->willReturn(Http::STATUS_OK); + $output->expects($this->once()) + ->method('setOutput') + ->with($this->equalTo('my data')); + $output->expects($this->once()) + ->method('setHeader') + ->with($this->equalTo('Content-Length: 42')); + $this->file->expects($this->once()) + ->method('getContent') + ->willReturn('my data'); + $this->file->expects($this->any()) + ->method('getSize') + ->willReturn(42); + + $this->response->callback($output); + } +} diff --git a/tests/lib/AppFramework/Http/RequestTest.php b/tests/lib/AppFramework/Http/RequestTest.php index 1c7f07580cc..2286a6da0e5 100644 --- a/tests/lib/AppFramework/Http/RequestTest.php +++ b/tests/lib/AppFramework/Http/RequestTest.php @@ -33,7 +33,7 @@ class RequestTest extends \Test\TestCase { if (in_array('fakeinput', stream_get_wrappers())) { stream_wrapper_unregister('fakeinput'); } - stream_wrapper_register('fakeinput', 'Test\AppFramework\Http\RequestStream'); + stream_wrapper_register('fakeinput', \Test\AppFramework\Http\RequestStream::class); $this->requestId = $this->createMock(IRequestId::class); $this->config = $this->createMock(IConfig::class); @@ -1690,7 +1690,7 @@ class RequestTest extends \Test\TestCase { public function testPassesCSRFCheckWithGet(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -1720,7 +1720,7 @@ class RequestTest extends \Test\TestCase { public function testPassesCSRFCheckWithPost(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -1750,7 +1750,7 @@ class RequestTest extends \Test\TestCase { public function testPassesCSRFCheckWithHeader(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -1780,7 +1780,7 @@ class RequestTest extends \Test\TestCase { public function testPassesCSRFCheckWithGetAndWithoutCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -1804,7 +1804,7 @@ class RequestTest extends \Test\TestCase { public function testPassesCSRFCheckWithPostAndWithoutCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -1828,7 +1828,7 @@ class RequestTest extends \Test\TestCase { public function testPassesCSRFCheckWithHeaderAndWithoutCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -1852,7 +1852,7 @@ class RequestTest extends \Test\TestCase { public function testFailsCSRFCheckWithHeaderAndNotAllChecksPassing(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -1879,7 +1879,7 @@ class RequestTest extends \Test\TestCase { public function testPassesStrictCookieCheckWithAllCookiesAndStrict(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName', 'getCookieParams']) ->setConstructorArgs([ [ @@ -1911,7 +1911,7 @@ class RequestTest extends \Test\TestCase { public function testFailsStrictCookieCheckWithAllCookiesAndMissingStrict(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName', 'getCookieParams']) ->setConstructorArgs([ [ @@ -1959,7 +1959,7 @@ class RequestTest extends \Test\TestCase { public function testPassesStrictCookieCheckWithAllCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -1984,7 +1984,7 @@ class RequestTest extends \Test\TestCase { public function testPassesStrictCookieCheckWithRandomCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -2007,7 +2007,7 @@ class RequestTest extends \Test\TestCase { public function testFailsStrictCookieCheckWithSessionCookie(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -2030,7 +2030,7 @@ class RequestTest extends \Test\TestCase { public function testFailsStrictCookieCheckWithRememberMeCookie(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -2053,7 +2053,7 @@ class RequestTest extends \Test\TestCase { public function testFailsCSRFCheckWithPostAndWithCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -2080,7 +2080,7 @@ class RequestTest extends \Test\TestCase { public function testFailStrictCookieCheckWithOnlyLaxCookie(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -2104,7 +2104,7 @@ class RequestTest extends \Test\TestCase { public function testFailStrictCookieCheckWithOnlyStrictCookie(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -2128,7 +2128,7 @@ class RequestTest extends \Test\TestCase { public function testPassesLaxCookieCheck(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -2152,7 +2152,7 @@ class RequestTest extends \Test\TestCase { public function testFailsLaxCookieCheckWithOnlyStrictCookie(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -2176,7 +2176,7 @@ class RequestTest extends \Test\TestCase { public function testSkipCookieCheckForOCSRequests(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -2216,7 +2216,7 @@ class RequestTest extends \Test\TestCase { */ public function testPassesCSRFCheckWithInvalidToken($invalidToken): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ @@ -2243,7 +2243,7 @@ class RequestTest extends \Test\TestCase { public function testPassesCSRFCheckWithoutTokenFail(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [], @@ -2259,7 +2259,7 @@ class RequestTest extends \Test\TestCase { public function testPassesCSRFCheckWithOCSAPIRequestHeader(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') + $request = $this->getMockBuilder(\OC\AppFramework\Http\Request::class) ->setMethods(['getScriptName']) ->setConstructorArgs([ [ diff --git a/tests/lib/AppFramework/Http/StreamResponseTest.php b/tests/lib/AppFramework/Http/StreamResponseTest.php index 87f6097a07a..2148598f041 100644 --- a/tests/lib/AppFramework/Http/StreamResponseTest.php +++ b/tests/lib/AppFramework/Http/StreamResponseTest.php @@ -18,7 +18,7 @@ class StreamResponseTest extends \Test\TestCase { protected function setUp(): void { parent::setUp(); - $this->output = $this->getMockBuilder('OCP\\AppFramework\\Http\\IOutput') + $this->output = $this->getMockBuilder(\OCP\AppFramework\Http\IOutput::class) ->disableOriginalConstructor() ->getMock(); } diff --git a/tests/lib/AppFramework/Middleware/MiddlewareDispatcherTest.php b/tests/lib/AppFramework/Middleware/MiddlewareDispatcherTest.php index fae5f5d9f1c..df3829d39fb 100644 --- a/tests/lib/AppFramework/Middleware/MiddlewareDispatcherTest.php +++ b/tests/lib/AppFramework/Middleware/MiddlewareDispatcherTest.php @@ -110,7 +110,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase { private function getControllerMock() { - return $this->getMockBuilder('OCP\AppFramework\Controller') + return $this->getMockBuilder(\OCP\AppFramework\Controller::class) ->setMethods(['method']) ->setConstructorArgs(['app', new Request( @@ -131,13 +131,13 @@ class MiddlewareDispatcherTest extends \Test\TestCase { public function testAfterExceptionShouldReturnResponseOfMiddleware(): void { $response = new Response(); - $m1 = $this->getMockBuilder('\OCP\AppFramework\Middleware') + $m1 = $this->getMockBuilder(\OCP\AppFramework\Middleware::class) ->setMethods(['afterException', 'beforeController']) ->getMock(); $m1->expects($this->never()) ->method('afterException'); - $m2 = $this->getMockBuilder('OCP\AppFramework\Middleware') + $m2 = $this->getMockBuilder(\OCP\AppFramework\Middleware::class) ->setMethods(['afterException', 'beforeController']) ->getMock(); $m2->expects($this->once()) diff --git a/tests/lib/AppFramework/Utility/ControllerMethodReflectorTest.php b/tests/lib/AppFramework/Utility/ControllerMethodReflectorTest.php index e0748d89f7f..ff0d0972950 100644 --- a/tests/lib/AppFramework/Utility/ControllerMethodReflectorTest.php +++ b/tests/lib/AppFramework/Utility/ControllerMethodReflectorTest.php @@ -59,7 +59,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { public function testReadAnnotation(): void { $reader = new ControllerMethodReflector(); $reader->reflect( - '\Test\AppFramework\Utility\ControllerMethodReflectorTest', + \Test\AppFramework\Utility\ControllerMethodReflectorTest::class, 'testReadAnnotation' ); @@ -101,7 +101,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { public function testReadAnnotationNoLowercase(): void { $reader = new ControllerMethodReflector(); $reader->reflect( - '\Test\AppFramework\Utility\ControllerMethodReflectorTest', + \Test\AppFramework\Utility\ControllerMethodReflectorTest::class, 'testReadAnnotationNoLowercase' ); @@ -117,7 +117,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { public function testReadTypeIntAnnotations(): void { $reader = new ControllerMethodReflector(); $reader->reflect( - '\Test\AppFramework\Utility\ControllerMethodReflectorTest', + \Test\AppFramework\Utility\ControllerMethodReflectorTest::class, 'testReadTypeIntAnnotations' ); @@ -138,7 +138,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { public function testReadTypeIntAnnotationsScalarTypes(): void { $reader = new ControllerMethodReflector(); $reader->reflect( - '\Test\AppFramework\Utility\ControllerMethodReflectorTest', + \Test\AppFramework\Utility\ControllerMethodReflectorTest::class, 'arguments3' ); @@ -156,7 +156,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { public function testReadTypeDoubleAnnotations(): void { $reader = new ControllerMethodReflector(); $reader->reflect( - '\Test\AppFramework\Utility\ControllerMethodReflectorTest', + \Test\AppFramework\Utility\ControllerMethodReflectorTest::class, 'testReadTypeDoubleAnnotations' ); @@ -170,7 +170,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { public function testReadTypeWhitespaceAnnotations(): void { $reader = new ControllerMethodReflector(); $reader->reflect( - '\Test\AppFramework\Utility\ControllerMethodReflectorTest', + \Test\AppFramework\Utility\ControllerMethodReflectorTest::class, 'testReadTypeWhitespaceAnnotations' ); @@ -183,7 +183,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { public function testReflectParameters(): void { $reader = new ControllerMethodReflector(); $reader->reflect( - '\Test\AppFramework\Utility\ControllerMethodReflectorTest', + \Test\AppFramework\Utility\ControllerMethodReflectorTest::class, 'arguments' ); @@ -196,7 +196,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { public function testReflectParameters2(): void { $reader = new ControllerMethodReflector(); $reader->reflect( - '\Test\AppFramework\Utility\ControllerMethodReflectorTest', + \Test\AppFramework\Utility\ControllerMethodReflectorTest::class, 'arguments2' ); @@ -206,7 +206,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { public function testInheritance(): void { $reader = new ControllerMethodReflector(); - $reader->reflect('Test\AppFramework\Utility\EndController', 'test'); + $reader->reflect(\Test\AppFramework\Utility\EndController::class, 'test'); $this->assertTrue($reader->hasAnnotation('Annotation')); } @@ -214,7 +214,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { public function testInheritanceOverride(): void { $reader = new ControllerMethodReflector(); - $reader->reflect('Test\AppFramework\Utility\EndController', 'test2'); + $reader->reflect(\Test\AppFramework\Utility\EndController::class, 'test2'); $this->assertTrue($reader->hasAnnotation('NoAnnotation')); $this->assertFalse($reader->hasAnnotation('Annotation')); @@ -223,14 +223,14 @@ class ControllerMethodReflectorTest extends \Test\TestCase { public function testInheritanceOverrideNoDocblock(): void { $reader = new ControllerMethodReflector(); - $reader->reflect('Test\AppFramework\Utility\EndController', 'test3'); + $reader->reflect(\Test\AppFramework\Utility\EndController::class, 'test3'); $this->assertFalse($reader->hasAnnotation('Annotation')); } public function testRangeDetection(): void { $reader = new ControllerMethodReflector(); - $reader->reflect('Test\AppFramework\Utility\EndController', 'test4'); + $reader->reflect(\Test\AppFramework\Utility\EndController::class, 'test4'); $rangeInfo1 = $reader->getRange('rangedOne'); $this->assertSame(-4, $rangeInfo1['min']); diff --git a/tests/lib/AppFramework/Utility/SimpleContainerTest.php b/tests/lib/AppFramework/Utility/SimpleContainerTest.php index d3e9dec18e0..34fe8755b17 100644 --- a/tests/lib/AppFramework/Utility/SimpleContainerTest.php +++ b/tests/lib/AppFramework/Utility/SimpleContainerTest.php @@ -1,255 +1,255 @@ -<?php - -declare(strict_types=1); - -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -namespace Test\AppFramework\Utility; - -use OC\AppFramework\Utility\SimpleContainer; -use Psr\Container\NotFoundExceptionInterface; - -interface TestInterface { -} - -class ClassEmptyConstructor implements IInterfaceConstructor { -} - -class ClassSimpleConstructor implements IInterfaceConstructor { - public $test; - public function __construct($test) { - $this->test = $test; - } -} - -class ClassComplexConstructor { - public $class; - public $test; - public function __construct(ClassSimpleConstructor $class, $test) { - $this->class = $class; - $this->test = $test; - } -} - -class ClassNullableUntypedConstructorArg { - public function __construct($class) { - } -} -class ClassNullableTypedConstructorArg { - public $class; - public function __construct(?\Some\Class $class) { - $this->class = $class; - } -} - -interface IInterfaceConstructor { -} -class ClassInterfaceConstructor { - public $class; - public $test; - public function __construct(IInterfaceConstructor $class, $test) { - $this->class = $class; - $this->test = $test; - } -} - - -class SimpleContainerTest extends \Test\TestCase { - private $container; - - protected function setUp(): void { - $this->container = new SimpleContainer(); - } - - - - public function testRegister(): void { - $this->container->registerParameter('test', 'abc'); - $this->assertEquals('abc', $this->container->query('test')); - } - - - /** - * Test querying a class that is not registered without autoload enabled - */ - public function testNothingRegistered(): void { - try { - $this->container->query('something really hard', false); - $this->fail('Expected `QueryException` exception was not thrown'); - } catch (\Throwable $exception) { - $this->assertInstanceOf(\OCP\AppFramework\QueryException::class, $exception); - $this->assertInstanceOf(NotFoundExceptionInterface::class, $exception); - } - } - - - /** - * Test querying a class that is not registered with autoload enabled - */ - public function testNothingRegistered_autoload(): void { - try { - $this->container->query('something really hard'); - $this->fail('Expected `QueryException` exception was not thrown'); - } catch (\Throwable $exception) { - $this->assertInstanceOf(\OCP\AppFramework\QueryException::class, $exception); - $this->assertInstanceOf(NotFoundExceptionInterface::class, $exception); - } - } - - - - public function testNotAClass(): void { - $this->expectException(\OCP\AppFramework\QueryException::class); - - $this->container->query('Test\AppFramework\Utility\TestInterface'); - } - - - public function testNoConstructorClass(): void { - $object = $this->container->query('Test\AppFramework\Utility\ClassEmptyConstructor'); - $this->assertTrue($object instanceof ClassEmptyConstructor); - } - - - public function testInstancesOnlyOnce(): void { - $object = $this->container->query('Test\AppFramework\Utility\ClassEmptyConstructor'); - $object2 = $this->container->query('Test\AppFramework\Utility\ClassEmptyConstructor'); - $this->assertSame($object, $object2); - } - - public function testConstructorSimple(): void { - $this->container->registerParameter('test', 'abc'); - $object = $this->container->query( - 'Test\AppFramework\Utility\ClassSimpleConstructor' - ); - $this->assertTrue($object instanceof ClassSimpleConstructor); - $this->assertEquals('abc', $object->test); - } - - - public function testConstructorComplex(): void { - $this->container->registerParameter('test', 'abc'); - $object = $this->container->query( - 'Test\AppFramework\Utility\ClassComplexConstructor' - ); - $this->assertTrue($object instanceof ClassComplexConstructor); - $this->assertEquals('abc', $object->class->test); - $this->assertEquals('abc', $object->test); - } - - - public function testConstructorComplexInterface(): void { - $this->container->registerParameter('test', 'abc'); - $this->container->registerService( - 'Test\AppFramework\Utility\IInterfaceConstructor', function ($c) { - return $c->query('Test\AppFramework\Utility\ClassSimpleConstructor'); - }); - $object = $this->container->query( - 'Test\AppFramework\Utility\ClassInterfaceConstructor' - ); - $this->assertTrue($object instanceof ClassInterfaceConstructor); - $this->assertEquals('abc', $object->class->test); - $this->assertEquals('abc', $object->test); - } - - - public function testOverrideService(): void { - $this->container->registerService( - 'Test\AppFramework\Utility\IInterfaceConstructor', function ($c) { - return $c->query('Test\AppFramework\Utility\ClassSimpleConstructor'); - }); - $this->container->registerService( - 'Test\AppFramework\Utility\IInterfaceConstructor', function ($c) { - return $c->query('Test\AppFramework\Utility\ClassEmptyConstructor'); - }); - $object = $this->container->query( - 'Test\AppFramework\Utility\IInterfaceConstructor' - ); - $this->assertTrue($object instanceof ClassEmptyConstructor); - } - - public function testRegisterAliasParamter(): void { - $this->container->registerParameter('test', 'abc'); - $this->container->registerAlias('test1', 'test'); - $this->assertEquals('abc', $this->container->query('test1')); - } - - public function testRegisterAliasService(): void { - $this->container->registerService('test', function () { - return new \StdClass; - }, true); - $this->container->registerAlias('test1', 'test'); - $this->assertSame( - $this->container->query('test'), $this->container->query('test')); - $this->assertSame( - $this->container->query('test1'), $this->container->query('test1')); - $this->assertSame( - $this->container->query('test'), $this->container->query('test1')); - } - - public function sanitizeNameProvider() { - return [ - ['ABC\\Foo', 'ABC\\Foo'], - ['\\ABC\\Foo', '\\ABC\\Foo'], - ['\\ABC\\Foo', 'ABC\\Foo'], - ['ABC\\Foo', '\\ABC\\Foo'], - ]; - } - - /** - * @dataProvider sanitizeNameProvider - */ - public function testSanitizeName($register, $query): void { - $this->container->registerService($register, function () { - return 'abc'; - }); - $this->assertEquals('abc', $this->container->query($query)); - } - - - public function testConstructorComplexNoTestParameterFound(): void { - $this->expectException(\OCP\AppFramework\QueryException::class); - - $object = $this->container->query( - 'Test\AppFramework\Utility\ClassComplexConstructor' - ); - } - - public function testRegisterFactory(): void { - $this->container->registerService('test', function () { - return new \StdClass(); - }, false); - $this->assertNotSame( - $this->container->query('test'), $this->container->query('test')); - } - - public function testRegisterAliasFactory(): void { - $this->container->registerService('test', function () { - return new \StdClass(); - }, false); - $this->container->registerAlias('test1', 'test'); - $this->assertNotSame( - $this->container->query('test'), $this->container->query('test')); - $this->assertNotSame( - $this->container->query('test1'), $this->container->query('test1')); - $this->assertNotSame( - $this->container->query('test'), $this->container->query('test1')); - } - - public function testQueryUntypedNullable(): void { - $this->expectException(\OCP\AppFramework\QueryException::class); - - $this->container->query(ClassNullableUntypedConstructorArg::class); - } - - public function testQueryTypedNullable(): void { - /** @var ClassNullableTypedConstructorArg $service */ - $service = $this->container->query(ClassNullableTypedConstructorArg::class); - - self::assertNull($service->class); - } -} +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\AppFramework\Utility; + +use OC\AppFramework\Utility\SimpleContainer; +use Psr\Container\NotFoundExceptionInterface; + +interface TestInterface { +} + +class ClassEmptyConstructor implements IInterfaceConstructor { +} + +class ClassSimpleConstructor implements IInterfaceConstructor { + public $test; + public function __construct($test) { + $this->test = $test; + } +} + +class ClassComplexConstructor { + public $class; + public $test; + public function __construct(ClassSimpleConstructor $class, $test) { + $this->class = $class; + $this->test = $test; + } +} + +class ClassNullableUntypedConstructorArg { + public function __construct($class) { + } +} +class ClassNullableTypedConstructorArg { + public $class; + public function __construct(?\Some\Class $class) { + $this->class = $class; + } +} + +interface IInterfaceConstructor { +} +class ClassInterfaceConstructor { + public $class; + public $test; + public function __construct(IInterfaceConstructor $class, $test) { + $this->class = $class; + $this->test = $test; + } +} + + +class SimpleContainerTest extends \Test\TestCase { + private $container; + + protected function setUp(): void { + $this->container = new SimpleContainer(); + } + + + + public function testRegister(): void { + $this->container->registerParameter('test', 'abc'); + $this->assertEquals('abc', $this->container->query('test')); + } + + + /** + * Test querying a class that is not registered without autoload enabled + */ + public function testNothingRegistered(): void { + try { + $this->container->query('something really hard', false); + $this->fail('Expected `QueryException` exception was not thrown'); + } catch (\Throwable $exception) { + $this->assertInstanceOf(\OCP\AppFramework\QueryException::class, $exception); + $this->assertInstanceOf(NotFoundExceptionInterface::class, $exception); + } + } + + + /** + * Test querying a class that is not registered with autoload enabled + */ + public function testNothingRegistered_autoload(): void { + try { + $this->container->query('something really hard'); + $this->fail('Expected `QueryException` exception was not thrown'); + } catch (\Throwable $exception) { + $this->assertInstanceOf(\OCP\AppFramework\QueryException::class, $exception); + $this->assertInstanceOf(NotFoundExceptionInterface::class, $exception); + } + } + + + + public function testNotAClass(): void { + $this->expectException(\OCP\AppFramework\QueryException::class); + + $this->container->query(\Test\AppFramework\Utility\TestInterface::class); + } + + + public function testNoConstructorClass(): void { + $object = $this->container->query(\Test\AppFramework\Utility\ClassEmptyConstructor::class); + $this->assertTrue($object instanceof ClassEmptyConstructor); + } + + + public function testInstancesOnlyOnce(): void { + $object = $this->container->query(\Test\AppFramework\Utility\ClassEmptyConstructor::class); + $object2 = $this->container->query(\Test\AppFramework\Utility\ClassEmptyConstructor::class); + $this->assertSame($object, $object2); + } + + public function testConstructorSimple(): void { + $this->container->registerParameter('test', 'abc'); + $object = $this->container->query( + \Test\AppFramework\Utility\ClassSimpleConstructor::class + ); + $this->assertTrue($object instanceof ClassSimpleConstructor); + $this->assertEquals('abc', $object->test); + } + + + public function testConstructorComplex(): void { + $this->container->registerParameter('test', 'abc'); + $object = $this->container->query( + \Test\AppFramework\Utility\ClassComplexConstructor::class + ); + $this->assertTrue($object instanceof ClassComplexConstructor); + $this->assertEquals('abc', $object->class->test); + $this->assertEquals('abc', $object->test); + } + + + public function testConstructorComplexInterface(): void { + $this->container->registerParameter('test', 'abc'); + $this->container->registerService( + \Test\AppFramework\Utility\IInterfaceConstructor::class, function ($c) { + return $c->query(\Test\AppFramework\Utility\ClassSimpleConstructor::class); + }); + $object = $this->container->query( + \Test\AppFramework\Utility\ClassInterfaceConstructor::class + ); + $this->assertTrue($object instanceof ClassInterfaceConstructor); + $this->assertEquals('abc', $object->class->test); + $this->assertEquals('abc', $object->test); + } + + + public function testOverrideService(): void { + $this->container->registerService( + \Test\AppFramework\Utility\IInterfaceConstructor::class, function ($c) { + return $c->query(\Test\AppFramework\Utility\ClassSimpleConstructor::class); + }); + $this->container->registerService( + \Test\AppFramework\Utility\IInterfaceConstructor::class, function ($c) { + return $c->query(\Test\AppFramework\Utility\ClassEmptyConstructor::class); + }); + $object = $this->container->query( + \Test\AppFramework\Utility\IInterfaceConstructor::class + ); + $this->assertTrue($object instanceof ClassEmptyConstructor); + } + + public function testRegisterAliasParamter(): void { + $this->container->registerParameter('test', 'abc'); + $this->container->registerAlias('test1', 'test'); + $this->assertEquals('abc', $this->container->query('test1')); + } + + public function testRegisterAliasService(): void { + $this->container->registerService('test', function () { + return new \StdClass; + }, true); + $this->container->registerAlias('test1', 'test'); + $this->assertSame( + $this->container->query('test'), $this->container->query('test')); + $this->assertSame( + $this->container->query('test1'), $this->container->query('test1')); + $this->assertSame( + $this->container->query('test'), $this->container->query('test1')); + } + + public function sanitizeNameProvider() { + return [ + ['ABC\\Foo', 'ABC\\Foo'], + ['\\ABC\\Foo', '\\ABC\\Foo'], + ['\\ABC\\Foo', 'ABC\\Foo'], + ['ABC\\Foo', '\\ABC\\Foo'], + ]; + } + + /** + * @dataProvider sanitizeNameProvider + */ + public function testSanitizeName($register, $query): void { + $this->container->registerService($register, function () { + return 'abc'; + }); + $this->assertEquals('abc', $this->container->query($query)); + } + + + public function testConstructorComplexNoTestParameterFound(): void { + $this->expectException(\OCP\AppFramework\QueryException::class); + + $object = $this->container->query( + \Test\AppFramework\Utility\ClassComplexConstructor::class + ); + } + + public function testRegisterFactory(): void { + $this->container->registerService('test', function () { + return new \StdClass(); + }, false); + $this->assertNotSame( + $this->container->query('test'), $this->container->query('test')); + } + + public function testRegisterAliasFactory(): void { + $this->container->registerService('test', function () { + return new \StdClass(); + }, false); + $this->container->registerAlias('test1', 'test'); + $this->assertNotSame( + $this->container->query('test'), $this->container->query('test')); + $this->assertNotSame( + $this->container->query('test1'), $this->container->query('test1')); + $this->assertNotSame( + $this->container->query('test'), $this->container->query('test1')); + } + + public function testQueryUntypedNullable(): void { + $this->expectException(\OCP\AppFramework\QueryException::class); + + $this->container->query(ClassNullableUntypedConstructorArg::class); + } + + public function testQueryTypedNullable(): void { + /** @var ClassNullableTypedConstructorArg $service */ + $service = $this->container->query(ClassNullableTypedConstructorArg::class); + + self::assertNull($service->class); + } +} diff --git a/tests/lib/Authentication/TwoFactorAuth/ManagerTest.php b/tests/lib/Authentication/TwoFactorAuth/ManagerTest.php index 7701cb68302..54ea67d76e4 100644 --- a/tests/lib/Authentication/TwoFactorAuth/ManagerTest.php +++ b/tests/lib/Authentication/TwoFactorAuth/ManagerTest.php @@ -102,7 +102,7 @@ class ManagerTest extends TestCase { $this->fakeProvider = $this->createMock(IProvider::class); $this->fakeProvider->method('getId')->willReturn('email'); - $this->backupProvider = $this->getMockBuilder('\OCP\Authentication\TwoFactorAuth\IProvider')->getMock(); + $this->backupProvider = $this->getMockBuilder(\OCP\Authentication\TwoFactorAuth\IProvider::class)->getMock(); $this->backupProvider->method('getId')->willReturn('backup_codes'); $this->backupProvider->method('isTwoFactorAuthEnabledForUser')->willReturn(true); } diff --git a/tests/lib/AutoLoaderTest.php b/tests/lib/AutoLoaderTest.php index 2aa8bc2a26a..f16fb44cb5a 100644 --- a/tests/lib/AutoLoaderTest.php +++ b/tests/lib/AutoLoaderTest.php @@ -27,7 +27,7 @@ class AutoLoaderTest extends TestCase { public function testLoadTestTestCase(): void { $this->assertEquals([ \OC::$SERVERROOT . '/tests/lib/TestCase.php' - ], $this->loader->findClass('Test\TestCase')); + ], $this->loader->findClass(\Test\TestCase::class)); } public function testLoadCore(): void { diff --git a/tests/lib/BackgroundJob/JobListTest.php b/tests/lib/BackgroundJob/JobListTest.php index a9d7df0e6f4..42ce5c628cd 100644 --- a/tests/lib/BackgroundJob/JobListTest.php +++ b/tests/lib/BackgroundJob/JobListTest.php @@ -96,7 +96,7 @@ class JobListTest extends TestCase { $this->assertCount(count($existingJobs) + 1, $jobs); $addedJob = $jobs[count($jobs) - 1]; - $this->assertInstanceOf('\Test\BackgroundJob\TestJob', $addedJob); + $this->assertInstanceOf(\Test\BackgroundJob\TestJob::class, $addedJob); $this->assertEquals($argument, $addedJob->getArgument()); $this->instance->remove($job, $argument); diff --git a/tests/lib/Collaboration/Collaborators/MailPluginTest.php b/tests/lib/Collaboration/Collaborators/MailPluginTest.php index 568325fd30c..8ec1bcdeec0 100644 --- a/tests/lib/Collaboration/Collaborators/MailPluginTest.php +++ b/tests/lib/Collaboration/Collaborators/MailPluginTest.php @@ -594,7 +594,7 @@ class MailPluginTest extends TestCase { $this->instantiatePlugin(); /** @var \OCP\IUser | \PHPUnit\Framework\MockObject\MockObject */ - $currentUser = $this->createMock('\OCP\IUser'); + $currentUser = $this->createMock(\OCP\IUser::class); $currentUser->expects($this->any()) ->method('getUID') diff --git a/tests/lib/Command/AsyncBusTest.php b/tests/lib/Command/AsyncBusTest.php index e8d7a857129..7c515051609 100644 --- a/tests/lib/Command/AsyncBusTest.php +++ b/tests/lib/Command/AsyncBusTest.php @@ -1,180 +1,180 @@ -<?php - -/** - * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -namespace Test\Command; - -use OC\Command\FileAccess; -use OCP\Command\IBus; -use OCP\Command\ICommand; -use Test\TestCase; - -class SimpleCommand implements ICommand { - public function handle() { - AsyncBusTest::$lastCommand = 'SimpleCommand'; - } -} - -class StateFullCommand implements ICommand { - private $state; - - public function __construct($state) { - $this->state = $state; - } - - public function handle() { - AsyncBusTest::$lastCommand = $this->state; - } -} - -class FilesystemCommand implements ICommand { - use FileAccess; - - public function handle() { - AsyncBusTest::$lastCommand = 'FileAccess'; - } -} - -function basicFunction() { - AsyncBusTest::$lastCommand = 'function'; -} - -// clean class to prevent phpunit putting closure in $this -class ThisClosureTest { - private function privateMethod() { - AsyncBusTest::$lastCommand = 'closure-this'; - } - - public function test(IBus $bus) { - $bus->push(function () { - $this->privateMethod(); - }); - } -} - -abstract class AsyncBusTest extends TestCase { - /** - * Basic way to check output from a command - * - * @var string - */ - public static $lastCommand; - - /** - * @var \OCP\Command\IBus - */ - private $bus; - - public static function DummyCommand() { - self::$lastCommand = 'static'; - } - - /** - * @return IBus - */ - protected function getBus() { - if (!$this->bus instanceof IBus) { - $this->bus = $this->createBus(); - } - return $this->bus; - } - - /** - * @return IBus - */ - abstract protected function createBus(); - - protected function setUp(): void { - self::$lastCommand = ''; - } - - public function testSimpleCommand(): void { - $command = new SimpleCommand(); - $this->getBus()->push($command); - $this->runJobs(); - $this->assertEquals('SimpleCommand', self::$lastCommand); - } - - public function testStateFullCommand(): void { - $command = new StateFullCommand('foo'); - $this->getBus()->push($command); - $this->runJobs(); - $this->assertEquals('foo', self::$lastCommand); - } - - public function testStaticCallable(): void { - $this->getBus()->push(['\Test\Command\AsyncBusTest', 'DummyCommand']); - $this->runJobs(); - $this->assertEquals('static', self::$lastCommand); - } - - public function testMemberCallable(): void { - $command = new StateFullCommand('bar'); - $this->getBus()->push([$command, 'handle']); - $this->runJobs(); - $this->assertEquals('bar', self::$lastCommand); - } - - public function testFunctionCallable(): void { - $this->getBus()->push('\Test\Command\BasicFunction'); - $this->runJobs(); - $this->assertEquals('function', self::$lastCommand); - } - - public function testClosure(): void { - $this->getBus()->push(function () { - AsyncBusTest::$lastCommand = 'closure'; - }); - $this->runJobs(); - $this->assertEquals('closure', self::$lastCommand); - } - - public function testClosureSelf(): void { - $this->getBus()->push(function () { - AsyncBusTest::$lastCommand = 'closure-self'; - }); - $this->runJobs(); - $this->assertEquals('closure-self', self::$lastCommand); - } - - - public function testClosureThis(): void { - // clean class to prevent phpunit putting closure in $this - $test = new ThisClosureTest(); - $test->test($this->getBus()); - $this->runJobs(); - $this->assertEquals('closure-this', self::$lastCommand); - } - - public function testClosureBind(): void { - $state = 'bar'; - $this->getBus()->push(function () use ($state) { - AsyncBusTest::$lastCommand = 'closure-' . $state; - }); - $this->runJobs(); - $this->assertEquals('closure-bar', self::$lastCommand); - } - - public function testFileFileAccessCommand(): void { - $this->getBus()->push(new FilesystemCommand()); - $this->assertEquals('', self::$lastCommand); - $this->runJobs(); - $this->assertEquals('FileAccess', self::$lastCommand); - } - - public function testFileFileAccessCommandSync(): void { - $this->getBus()->requireSync('\OC\Command\FileAccess'); - $this->getBus()->push(new FilesystemCommand()); - $this->assertEquals('FileAccess', self::$lastCommand); - self::$lastCommand = ''; - $this->runJobs(); - $this->assertEquals('', self::$lastCommand); - } - - - abstract protected function runJobs(); -} +<?php + +/** + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\Command; + +use OC\Command\FileAccess; +use OCP\Command\IBus; +use OCP\Command\ICommand; +use Test\TestCase; + +class SimpleCommand implements ICommand { + public function handle() { + AsyncBusTest::$lastCommand = 'SimpleCommand'; + } +} + +class StateFullCommand implements ICommand { + private $state; + + public function __construct($state) { + $this->state = $state; + } + + public function handle() { + AsyncBusTest::$lastCommand = $this->state; + } +} + +class FilesystemCommand implements ICommand { + use FileAccess; + + public function handle() { + AsyncBusTest::$lastCommand = 'FileAccess'; + } +} + +function basicFunction() { + AsyncBusTest::$lastCommand = 'function'; +} + +// clean class to prevent phpunit putting closure in $this +class ThisClosureTest { + private function privateMethod() { + AsyncBusTest::$lastCommand = 'closure-this'; + } + + public function test(IBus $bus) { + $bus->push(function () { + $this->privateMethod(); + }); + } +} + +abstract class AsyncBusTest extends TestCase { + /** + * Basic way to check output from a command + * + * @var string + */ + public static $lastCommand; + + /** + * @var \OCP\Command\IBus + */ + private $bus; + + public static function DummyCommand() { + self::$lastCommand = 'static'; + } + + /** + * @return IBus + */ + protected function getBus() { + if (!$this->bus instanceof IBus) { + $this->bus = $this->createBus(); + } + return $this->bus; + } + + /** + * @return IBus + */ + abstract protected function createBus(); + + protected function setUp(): void { + self::$lastCommand = ''; + } + + public function testSimpleCommand(): void { + $command = new SimpleCommand(); + $this->getBus()->push($command); + $this->runJobs(); + $this->assertEquals('SimpleCommand', self::$lastCommand); + } + + public function testStateFullCommand(): void { + $command = new StateFullCommand('foo'); + $this->getBus()->push($command); + $this->runJobs(); + $this->assertEquals('foo', self::$lastCommand); + } + + public function testStaticCallable(): void { + $this->getBus()->push([\Test\Command\AsyncBusTest::class, 'DummyCommand']); + $this->runJobs(); + $this->assertEquals('static', self::$lastCommand); + } + + public function testMemberCallable(): void { + $command = new StateFullCommand('bar'); + $this->getBus()->push([$command, 'handle']); + $this->runJobs(); + $this->assertEquals('bar', self::$lastCommand); + } + + public function testFunctionCallable(): void { + $this->getBus()->push('\Test\Command\BasicFunction'); + $this->runJobs(); + $this->assertEquals('function', self::$lastCommand); + } + + public function testClosure(): void { + $this->getBus()->push(function () { + AsyncBusTest::$lastCommand = 'closure'; + }); + $this->runJobs(); + $this->assertEquals('closure', self::$lastCommand); + } + + public function testClosureSelf(): void { + $this->getBus()->push(function () { + AsyncBusTest::$lastCommand = 'closure-self'; + }); + $this->runJobs(); + $this->assertEquals('closure-self', self::$lastCommand); + } + + + public function testClosureThis(): void { + // clean class to prevent phpunit putting closure in $this + $test = new ThisClosureTest(); + $test->test($this->getBus()); + $this->runJobs(); + $this->assertEquals('closure-this', self::$lastCommand); + } + + public function testClosureBind(): void { + $state = 'bar'; + $this->getBus()->push(function () use ($state) { + AsyncBusTest::$lastCommand = 'closure-' . $state; + }); + $this->runJobs(); + $this->assertEquals('closure-bar', self::$lastCommand); + } + + public function testFileFileAccessCommand(): void { + $this->getBus()->push(new FilesystemCommand()); + $this->assertEquals('', self::$lastCommand); + $this->runJobs(); + $this->assertEquals('FileAccess', self::$lastCommand); + } + + public function testFileFileAccessCommandSync(): void { + $this->getBus()->requireSync(\OC\Command\FileAccess::class); + $this->getBus()->push(new FilesystemCommand()); + $this->assertEquals('FileAccess', self::$lastCommand); + self::$lastCommand = ''; + $this->runJobs(); + $this->assertEquals('', self::$lastCommand); + } + + + abstract protected function runJobs(); +} diff --git a/tests/lib/ContactsManagerTest.php b/tests/lib/ContactsManagerTest.php index 6a6cd5f421a..a726715c1bd 100644 --- a/tests/lib/ContactsManagerTest.php +++ b/tests/lib/ContactsManagerTest.php @@ -67,7 +67,7 @@ class ContactsManagerTest extends \Test\TestCase { */ public function testSearch($search1, $search2, $expectedResult): void { /** @var \PHPUnit\Framework\MockObject\MockObject|IAddressBook $addressbook */ - $addressbook1 = $this->getMockBuilder('\OCP\IAddressBook') + $addressbook1 = $this->getMockBuilder(\OCP\IAddressBook::class) ->disableOriginalConstructor() ->getMock(); @@ -79,7 +79,7 @@ class ContactsManagerTest extends \Test\TestCase { ->method('getKey') ->willReturn('simple:1'); - $addressbook2 = $this->getMockBuilder('\OCP\IAddressBook') + $addressbook2 = $this->getMockBuilder(\OCP\IAddressBook::class) ->disableOriginalConstructor() ->getMock(); @@ -101,7 +101,7 @@ class ContactsManagerTest extends \Test\TestCase { public function testDeleteHavePermission(): void { /** @var \PHPUnit\Framework\MockObject\MockObject|IAddressBook $addressbook */ - $addressbook = $this->getMockBuilder('\OCP\IAddressBook') + $addressbook = $this->getMockBuilder(\OCP\IAddressBook::class) ->disableOriginalConstructor() ->getMock(); @@ -124,7 +124,7 @@ class ContactsManagerTest extends \Test\TestCase { public function testDeleteNoPermission(): void { /** @var \PHPUnit\Framework\MockObject\MockObject|IAddressBook $addressbook */ - $addressbook = $this->getMockBuilder('\OCP\IAddressBook') + $addressbook = $this->getMockBuilder(\OCP\IAddressBook::class) ->disableOriginalConstructor() ->getMock(); @@ -146,7 +146,7 @@ class ContactsManagerTest extends \Test\TestCase { public function testDeleteNoAddressbook(): void { /** @var \PHPUnit\Framework\MockObject\MockObject|IAddressBook $addressbook */ - $addressbook = $this->getMockBuilder('\OCP\IAddressBook') + $addressbook = $this->getMockBuilder(\OCP\IAddressBook::class) ->disableOriginalConstructor() ->getMock(); @@ -164,7 +164,7 @@ class ContactsManagerTest extends \Test\TestCase { public function testCreateOrUpdateHavePermission(): void { /** @var \PHPUnit\Framework\MockObject\MockObject|IAddressBook $addressbook */ - $addressbook = $this->getMockBuilder('\OCP\IAddressBook') + $addressbook = $this->getMockBuilder(\OCP\IAddressBook::class) ->disableOriginalConstructor() ->getMock(); @@ -187,7 +187,7 @@ class ContactsManagerTest extends \Test\TestCase { public function testCreateOrUpdateNoPermission(): void { /** @var \PHPUnit\Framework\MockObject\MockObject|IAddressBook $addressbook */ - $addressbook = $this->getMockBuilder('\OCP\IAddressBook') + $addressbook = $this->getMockBuilder(\OCP\IAddressBook::class) ->disableOriginalConstructor() ->getMock(); @@ -209,7 +209,7 @@ class ContactsManagerTest extends \Test\TestCase { public function testCreateOrUpdateNOAdressbook(): void { /** @var \PHPUnit\Framework\MockObject\MockObject|IAddressBook $addressbook */ - $addressbook = $this->getMockBuilder('\OCP\IAddressBook') + $addressbook = $this->getMockBuilder(\OCP\IAddressBook::class) ->disableOriginalConstructor() ->getMock(); @@ -232,7 +232,7 @@ class ContactsManagerTest extends \Test\TestCase { public function testIsEnabledIfSo(): void { /** @var \PHPUnit\Framework\MockObject\MockObject|IAddressBook $addressbook */ - $addressbook = $this->getMockBuilder('\OCP\IAddressBook') + $addressbook = $this->getMockBuilder(\OCP\IAddressBook::class) ->disableOriginalConstructor() ->getMock(); @@ -248,7 +248,7 @@ class ContactsManagerTest extends \Test\TestCase { public function testAddressBookEnumeration(): void { // create mock for the addressbook /** @var \PHPUnit\Framework\MockObject\MockObject|IAddressBook $addressbook */ - $addressbook = $this->getMockBuilder('\OCP\IAddressBook') + $addressbook = $this->getMockBuilder(\OCP\IAddressBook::class) ->disableOriginalConstructor() ->getMock(); diff --git a/tests/lib/DB/MigrationsTest.php b/tests/lib/DB/MigrationsTest.php index 531e0a3805a..2be82a34ea8 100644 --- a/tests/lib/DB/MigrationsTest.php +++ b/tests/lib/DB/MigrationsTest.php @@ -823,14 +823,14 @@ class MigrationsTest extends \Test\TestCase { return [ '30000Date20240102030405' => [ [ - 'class' => 'OCP\\Migration\\Attributes\\DropTable', + 'class' => \OCP\Migration\Attributes\DropTable::class, 'table' => 'old_table', 'description' => '', 'notes' => [], 'columns' => [] ], [ - 'class' => 'OCP\\Migration\\Attributes\\CreateTable', + 'class' => \OCP\Migration\Attributes\CreateTable::class, 'table' => 'new_table', 'description' => 'Table is used to store things, but also to get more things', 'notes' => @@ -841,7 +841,7 @@ class MigrationsTest extends \Test\TestCase { 'columns' => [] ], [ - 'class' => 'OCP\\Migration\\Attributes\\AddColumn', + 'class' => \OCP\Migration\Attributes\AddColumn::class, 'table' => 'my_table', 'description' => '', 'notes' => [], @@ -849,7 +849,7 @@ class MigrationsTest extends \Test\TestCase { 'type' => '' ], [ - 'class' => 'OCP\\Migration\\Attributes\\AddColumn', + 'class' => \OCP\Migration\Attributes\AddColumn::class, 'table' => 'my_table', 'description' => '', 'notes' => [], @@ -857,7 +857,7 @@ class MigrationsTest extends \Test\TestCase { 'type' => '' ], [ - 'class' => 'OCP\\Migration\\Attributes\\AddColumn', + 'class' => \OCP\Migration\Attributes\AddColumn::class, 'table' => 'other_table', 'description' => '', 'notes' => [], @@ -865,21 +865,21 @@ class MigrationsTest extends \Test\TestCase { 'type' => 'date' ], [ - 'class' => 'OCP\\Migration\\Attributes\\AddIndex', + 'class' => \OCP\Migration\Attributes\AddIndex::class, 'table' => 'my_table', 'description' => '', 'notes' => [], 'type' => '' ], [ - 'class' => 'OCP\\Migration\\Attributes\\AddIndex', + 'class' => \OCP\Migration\Attributes\AddIndex::class, 'table' => 'my_table', 'description' => '', 'notes' => [], 'type' => 'primary' ], [ - 'class' => 'OCP\\Migration\\Attributes\\DropColumn', + 'class' => \OCP\Migration\Attributes\DropColumn::class, 'table' => 'other_table', 'description' => '', 'notes' => [], @@ -887,7 +887,7 @@ class MigrationsTest extends \Test\TestCase { 'type' => '' ], [ - 'class' => 'OCP\\Migration\\Attributes\\DropColumn', + 'class' => \OCP\Migration\Attributes\DropColumn::class, 'table' => 'other_table', 'description' => 'field is not used anymore and replaced by \'last_one\'', 'notes' => [], @@ -895,14 +895,14 @@ class MigrationsTest extends \Test\TestCase { 'type' => '' ], [ - 'class' => 'OCP\\Migration\\Attributes\\DropIndex', + 'class' => \OCP\Migration\Attributes\DropIndex::class, 'table' => 'other_table', 'description' => '', 'notes' => [], 'type' => '' ], [ - 'class' => 'OCP\\Migration\\Attributes\\ModifyColumn', + 'class' => \OCP\Migration\Attributes\ModifyColumn::class, 'table' => 'other_table', 'description' => '', 'notes' => [], @@ -910,7 +910,7 @@ class MigrationsTest extends \Test\TestCase { 'type' => '' ], [ - 'class' => 'OCP\\Migration\\Attributes\\ModifyColumn', + 'class' => \OCP\Migration\Attributes\ModifyColumn::class, 'table' => 'other_table', 'description' => '', 'notes' => [], @@ -918,7 +918,7 @@ class MigrationsTest extends \Test\TestCase { 'type' => '' ], [ - 'class' => 'OCP\\Migration\\Attributes\\ModifyColumn', + 'class' => \OCP\Migration\Attributes\ModifyColumn::class, 'table' => 'other_table', 'description' => '', 'notes' => [], diff --git a/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php b/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php index c14c55e6d02..48f88df14f2 100644 --- a/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php +++ b/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php @@ -338,7 +338,7 @@ class ExpressionBuilderTest extends TestCase { /** @var \OC\DB\QueryBuilder\Literal $actual */ $actual = $this->expressionBuilder->literal($input, $type); - $this->assertInstanceOf('\OC\DB\QueryBuilder\Literal', $actual); + $this->assertInstanceOf(\OC\DB\QueryBuilder\Literal::class, $actual); $this->assertEquals( $this->doctrineExpressionBuilder->literal($input, $type), $actual->__toString() diff --git a/tests/lib/Encryption/DecryptAllTest.php b/tests/lib/Encryption/DecryptAllTest.php index d073efc8235..1138d8c2e80 100644 --- a/tests/lib/Encryption/DecryptAllTest.php +++ b/tests/lib/Encryption/DecryptAllTest.php @@ -55,7 +55,7 @@ class DecryptAllTest extends TestCase { $this->userManager = $this->getMockBuilder(IUserManager::class) ->disableOriginalConstructor()->getMock(); - $this->encryptionManager = $this->getMockBuilder('OC\Encryption\Manager') + $this->encryptionManager = $this->getMockBuilder(\OC\Encryption\Manager::class) ->disableOriginalConstructor()->getMock(); $this->view = $this->getMockBuilder(View::class) ->disableOriginalConstructor()->getMock(); @@ -105,7 +105,7 @@ class DecryptAllTest extends TestCase { $this->userManager->expects($this->never())->method('userExists'); } /** @var DecryptAll | \PHPUnit\Framework\MockObject\MockObject | $instance */ - $instance = $this->getMockBuilder('OC\Encryption\DecryptAll') + $instance = $this->getMockBuilder(\OC\Encryption\DecryptAll::class) ->setConstructorArgs( [ $this->encryptionManager, @@ -159,7 +159,7 @@ class DecryptAllTest extends TestCase { public function testPrepareEncryptionModules($success): void { $user = 'user1'; - $dummyEncryptionModule = $this->getMockBuilder('OCP\Encryption\IEncryptionModule') + $dummyEncryptionModule = $this->getMockBuilder(\OCP\Encryption\IEncryptionModule::class) ->disableOriginalConstructor()->getMock(); $dummyEncryptionModule->expects($this->once()) @@ -190,7 +190,7 @@ class DecryptAllTest extends TestCase { */ public function testDecryptAllUsersFiles($user): void { /** @var DecryptAll | \PHPUnit\Framework\MockObject\MockObject | $instance */ - $instance = $this->getMockBuilder('OC\Encryption\DecryptAll') + $instance = $this->getMockBuilder(\OC\Encryption\DecryptAll::class) ->setConstructorArgs( [ $this->encryptionManager, @@ -235,7 +235,7 @@ class DecryptAllTest extends TestCase { public function testDecryptUsersFiles(): void { /** @var DecryptAll | \PHPUnit\Framework\MockObject\MockObject $instance */ - $instance = $this->getMockBuilder('OC\Encryption\DecryptAll') + $instance = $this->getMockBuilder(\OC\Encryption\DecryptAll::class) ->setConstructorArgs( [ $this->encryptionManager, @@ -254,7 +254,7 @@ class DecryptAllTest extends TestCase { ->disableOriginalConstructor()->getMock(); $sharedStorage->expects($this->once())->method('instanceOfStorage') - ->with('OCA\Files_Sharing\SharedStorage')->willReturn(true); + ->with(\OCA\Files_Sharing\SharedStorage::class)->willReturn(true); $this->view->expects($this->exactly(2)) ->method('getDirectoryContent') @@ -312,7 +312,7 @@ class DecryptAllTest extends TestCase { $path = 'test.txt'; /** @var DecryptAll | \PHPUnit\Framework\MockObject\MockObject $instance */ - $instance = $this->getMockBuilder('OC\Encryption\DecryptAll') + $instance = $this->getMockBuilder(\OC\Encryption\DecryptAll::class) ->setConstructorArgs( [ $this->encryptionManager, @@ -352,7 +352,7 @@ class DecryptAllTest extends TestCase { $path = 'test.txt'; /** @var DecryptAll | \PHPUnit\Framework\MockObject\MockObject $instance */ - $instance = $this->getMockBuilder('OC\Encryption\DecryptAll') + $instance = $this->getMockBuilder(\OC\Encryption\DecryptAll::class) ->setConstructorArgs( [ $this->encryptionManager, diff --git a/tests/lib/Encryption/EncryptionWrapperTest.php b/tests/lib/Encryption/EncryptionWrapperTest.php index 1ecb9dc89c7..01fbc0a3a12 100644 --- a/tests/lib/Encryption/EncryptionWrapperTest.php +++ b/tests/lib/Encryption/EncryptionWrapperTest.php @@ -54,7 +54,7 @@ class EncryptionWrapperTest extends TestCase { ]); } - $mount = $this->getMockBuilder('OCP\Files\Mount\IMountPoint') + $mount = $this->getMockBuilder(\OCP\Files\Mount\IMountPoint::class) ->disableOriginalConstructor() ->getMock(); @@ -62,7 +62,7 @@ class EncryptionWrapperTest extends TestCase { $this->assertEquals( $expectedWrapped, - $returnedStorage->instanceOfStorage('OC\Files\Storage\Wrapper\Encryption'), + $returnedStorage->instanceOfStorage(\OC\Files\Storage\Wrapper\Encryption::class), 'Asserted that the storage is (not) wrapped with encryption' ); } @@ -71,7 +71,7 @@ class EncryptionWrapperTest extends TestCase { return [ // Wrap when not wrapped or not wrapped with storage [true, []], - [true, ['OCA\Files_Trashbin\Storage']], + [true, [\OCA\Files_Trashbin\Storage::class]], // Do not wrap shared storages [false, [Storage\IDisableEncryptionStorage::class]], diff --git a/tests/lib/Encryption/Keys/StorageTest.php b/tests/lib/Encryption/Keys/StorageTest.php index 2ce30105293..7c8ff93486e 100644 --- a/tests/lib/Encryption/Keys/StorageTest.php +++ b/tests/lib/Encryption/Keys/StorageTest.php @@ -1,613 +1,613 @@ -<?php - -/** - * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -namespace Test\Encryption\Keys; - -use OC\Encryption\Keys\Storage; -use OC\Files\View; -use OCP\IConfig; -use OCP\Security\ICrypto; -use PHPUnit\Framework\MockObject\MockObject; -use Test\TestCase; - -class StorageTest extends TestCase { - /** @var Storage */ - protected $storage; - - /** @var MockObject|\OC\Encryption\Util */ - protected $util; - - /** @var MockObject|View */ - protected $view; - - /** @var MockObject|IConfig */ - protected $config; - - /** @var MockObject|ICrypto */ - protected $crypto; - - private array $mkdirStack = []; - - protected function setUp(): void { - parent::setUp(); - - $this->util = $this->getMockBuilder('OC\Encryption\Util') - ->disableOriginalConstructor() - ->setMethodsExcept(['getFileKeyDir']) - ->getMock(); - - $this->view = $this->getMockBuilder(View::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->crypto = $this->createMock(ICrypto::class); - $this->crypto->method('encrypt') - ->willReturnCallback(function ($data, $pass) { - return $data; - }); - $this->crypto->method('decrypt') - ->willReturnCallback(function ($data, $pass) { - return $data; - }); - - $this->config = $this->getMockBuilder(IConfig::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->storage = new Storage($this->view, $this->util, $this->crypto, $this->config); - } - - public function testSetFileKey(): void { - $this->config->method('getSystemValueString') - ->with('version') - ->willReturn('20.0.0.2'); - $this->util->expects($this->any()) - ->method('getUidAndFilename') - ->willReturn(['user1', '/files/foo.txt']); - $this->util->expects($this->any()) - ->method('stripPartialFileExtension') - ->willReturnArgument(0); - $this->util->expects($this->any()) - ->method('isSystemWideMountPoint') - ->willReturn(false); - - $data = json_encode(['key' => base64_encode('key')]); - $this->view->expects($this->once()) - ->method('file_put_contents') - ->with($this->equalTo('/user1/files_encryption/keys/files/foo.txt/encModule/fileKey'), - $this->equalTo($data)) - ->willReturn(strlen($data)); - - $this->assertTrue( - $this->storage->setFileKey('user1/files/foo.txt', 'fileKey', 'key', 'encModule') - ); - } - - public function testSetFileOld(): void { - $this->config->method('getSystemValueString') - ->with('version') - ->willReturn('20.0.0.0'); - $this->util->expects($this->any()) - ->method('getUidAndFilename') - ->willReturn(['user1', '/files/foo.txt']); - $this->util->expects($this->any()) - ->method('stripPartialFileExtension') - ->willReturnArgument(0); - $this->util->expects($this->any()) - ->method('isSystemWideMountPoint') - ->willReturn(false); - $this->crypto->expects($this->never()) - ->method('encrypt'); - $this->view->expects($this->once()) - ->method('file_put_contents') - ->with($this->equalTo('/user1/files_encryption/keys/files/foo.txt/encModule/fileKey'), - $this->equalTo('key')) - ->willReturn(strlen('key')); - - $this->assertTrue( - $this->storage->setFileKey('user1/files/foo.txt', 'fileKey', 'key', 'encModule') - ); - } - - public function dataTestGetFileKey() { - return [ - ['/files/foo.txt', '/files/foo.txt', true, 'key'], - ['/files/foo.txt.ocTransferId2111130212.part', '/files/foo.txt', true, 'key'], - ['/files/foo.txt.ocTransferId2111130212.part', '/files/foo.txt', false, 'key2'], - ]; - } - - /** - * @dataProvider dataTestGetFileKey - * - * @param string $path - * @param string $strippedPartialName - * @param bool $originalKeyExists - * @param string $expectedKeyContent - */ - public function testGetFileKey($path, $strippedPartialName, $originalKeyExists, $expectedKeyContent): void { - $this->config->method('getSystemValueString') - ->with('version') - ->willReturn('20.0.0.2'); - $this->util->expects($this->any()) - ->method('getUidAndFilename') - ->willReturnMap([ - ['user1/files/foo.txt', ['user1', '/files/foo.txt']], - ['user1/files/foo.txt.ocTransferId2111130212.part', ['user1', '/files/foo.txt.ocTransferId2111130212.part']], - ]); - // we need to strip away the part file extension in order to reuse a - // existing key if it exists, otherwise versions will break - $this->util->expects($this->once()) - ->method('stripPartialFileExtension') - ->willReturn('user1' . $strippedPartialName); - $this->util->expects($this->any()) - ->method('isSystemWideMountPoint') - ->willReturn(false); - - $this->crypto->method('decrypt') - ->willReturnCallback(function ($data, $pass) { - return $data; - }); - - if (!$originalKeyExists) { - $this->view->expects($this->exactly(2)) - ->method('file_exists') - ->withConsecutive( - [$this->equalTo('/user1/files_encryption/keys' . $strippedPartialName . '/encModule/fileKey')], - [$this->equalTo('/user1/files_encryption/keys' . $path . '/encModule/fileKey')], - )->willReturnOnConsecutiveCalls( - $originalKeyExists, - true, - ); - - $this->view->expects($this->once()) - ->method('file_get_contents') - ->with($this->equalTo('/user1/files_encryption/keys' . $path . '/encModule/fileKey')) - ->willReturn(json_encode(['key' => base64_encode('key2')])); - } else { - $this->view->expects($this->once()) - ->method('file_exists') - ->with($this->equalTo('/user1/files_encryption/keys' . $strippedPartialName . '/encModule/fileKey')) - ->willReturn($originalKeyExists); - - $this->view->expects($this->once()) - ->method('file_get_contents') - ->with($this->equalTo('/user1/files_encryption/keys' . $strippedPartialName . '/encModule/fileKey')) - ->willReturn(json_encode(['key' => base64_encode('key')])); - } - - $this->assertSame($expectedKeyContent, - $this->storage->getFileKey('user1' . $path, 'fileKey', 'encModule') - ); - } - - public function testSetFileKeySystemWide(): void { - $this->config->method('getSystemValueString') - ->with('version') - ->willReturn('20.0.0.2'); - - $this->util->expects($this->any()) - ->method('getUidAndFilename') - ->willReturn(['user1', '/files/foo.txt']); - $this->util->expects($this->any()) - ->method('isSystemWideMountPoint') - ->willReturn(true); - $this->util->expects($this->any()) - ->method('stripPartialFileExtension') - ->willReturnArgument(0); - - $this->crypto->method('encrypt') - ->willReturnCallback(function ($data, $pass) { - return $data; - }); - - $data = json_encode(['key' => base64_encode('key')]); - $this->view->expects($this->once()) - ->method('file_put_contents') - ->with($this->equalTo('/files_encryption/keys/files/foo.txt/encModule/fileKey'), - $this->equalTo($data)) - ->willReturn(strlen($data)); - - $this->assertTrue( - $this->storage->setFileKey('user1/files/foo.txt', 'fileKey', 'key', 'encModule') - ); - } - - public function testGetFileKeySystemWide(): void { - $this->config->method('getSystemValueString') - ->with('version') - ->willReturn('20.0.0.2'); - - $this->util->expects($this->any()) - ->method('getUidAndFilename') - ->willReturn(['user1', '/files/foo.txt']); - $this->util->expects($this->any()) - ->method('stripPartialFileExtension') - ->willReturnArgument(0); - $this->util->expects($this->any()) - ->method('isSystemWideMountPoint') - ->willReturn(true); - $this->view->expects($this->once()) - ->method('file_get_contents') - ->with($this->equalTo('/files_encryption/keys/files/foo.txt/encModule/fileKey')) - ->willReturn(json_encode(['key' => base64_encode('key')])); - $this->view->expects($this->once()) - ->method('file_exists') - ->with($this->equalTo('/files_encryption/keys/files/foo.txt/encModule/fileKey')) - ->willReturn(true); - - $this->assertSame('key', - $this->storage->getFileKey('user1/files/foo.txt', 'fileKey', 'encModule') - ); - } - - public function testSetSystemUserKey(): void { - $this->config->method('getSystemValueString') - ->with('version') - ->willReturn('20.0.0.2'); - - $data = json_encode([ - 'key' => base64_encode('key'), - 'uid' => null] - ); - $this->view->expects($this->once()) - ->method('file_put_contents') - ->with($this->equalTo('/files_encryption/encModule/shareKey_56884'), - $this->equalTo($data)) - ->willReturn(strlen($data)); - - $this->assertTrue( - $this->storage->setSystemUserKey('shareKey_56884', 'key', 'encModule') - ); - } - - public function testSetUserKey(): void { - $this->config->method('getSystemValueString') - ->with('version') - ->willReturn('20.0.0.2'); - - $data = json_encode([ - 'key' => base64_encode('key'), - 'uid' => 'user1'] - ); - $this->view->expects($this->once()) - ->method('file_put_contents') - ->with($this->equalTo('/user1/files_encryption/encModule/user1.publicKey'), - $this->equalTo($data)) - ->willReturn(strlen($data)); - - $this->assertTrue( - $this->storage->setUserKey('user1', 'publicKey', 'key', 'encModule') - ); - } - - public function testGetSystemUserKey(): void { - $this->config->method('getSystemValueString') - ->with('version') - ->willReturn('20.0.0.2'); - - $data = json_encode([ - 'key' => base64_encode('key'), - 'uid' => null] - ); - $this->view->expects($this->once()) - ->method('file_get_contents') - ->with($this->equalTo('/files_encryption/encModule/shareKey_56884')) - ->willReturn($data); - $this->view->expects($this->once()) - ->method('file_exists') - ->with($this->equalTo('/files_encryption/encModule/shareKey_56884')) - ->willReturn(true); - - $this->assertSame('key', - $this->storage->getSystemUserKey('shareKey_56884', 'encModule') - ); - } - - public function testGetUserKey(): void { - $this->config->method('getSystemValueString') - ->with('version') - ->willReturn('20.0.0.2'); - - $data = json_encode([ - 'key' => base64_encode('key'), - 'uid' => 'user1'] - ); - $this->view->expects($this->once()) - ->method('file_get_contents') - ->with($this->equalTo('/user1/files_encryption/encModule/user1.publicKey')) - ->willReturn($data); - $this->view->expects($this->once()) - ->method('file_exists') - ->with($this->equalTo('/user1/files_encryption/encModule/user1.publicKey')) - ->willReturn(true); - - $this->assertSame('key', - $this->storage->getUserKey('user1', 'publicKey', 'encModule') - ); - } - - public function testDeleteUserKey(): void { - $this->view->expects($this->once()) - ->method('file_exists') - ->with($this->equalTo('/user1/files_encryption/encModule/user1.publicKey')) - ->willReturn(true); - $this->view->expects($this->once()) - ->method('unlink') - ->with($this->equalTo('/user1/files_encryption/encModule/user1.publicKey')) - ->willReturn(true); - - $this->assertTrue( - $this->storage->deleteUserKey('user1', 'publicKey', 'encModule') - ); - } - - public function testDeleteSystemUserKey(): void { - $this->view->expects($this->once()) - ->method('file_exists') - ->with($this->equalTo('/files_encryption/encModule/shareKey_56884')) - ->willReturn(true); - $this->view->expects($this->once()) - ->method('unlink') - ->with($this->equalTo('/files_encryption/encModule/shareKey_56884')) - ->willReturn(true); - - $this->assertTrue( - $this->storage->deleteSystemUserKey('shareKey_56884', 'encModule') - ); - } - - public function testDeleteFileKeySystemWide(): void { - $this->util->expects($this->any()) - ->method('getUidAndFilename') - ->willReturn(['user1', '/files/foo.txt']); - $this->util->expects($this->any()) - ->method('stripPartialFileExtension') - ->willReturnArgument(0); - $this->util->expects($this->any()) - ->method('isSystemWideMountPoint') - ->willReturn(true); - $this->view->expects($this->once()) - ->method('file_exists') - ->with($this->equalTo('/files_encryption/keys/files/foo.txt/encModule/fileKey')) - ->willReturn(true); - $this->view->expects($this->once()) - ->method('unlink') - ->with($this->equalTo('/files_encryption/keys/files/foo.txt/encModule/fileKey')) - ->willReturn(true); - - $this->assertTrue( - $this->storage->deleteFileKey('user1/files/foo.txt', 'fileKey', 'encModule') - ); - } - - public function testDeleteFileKey(): void { - $this->util->expects($this->any()) - ->method('getUidAndFilename') - ->willReturn(['user1', '/files/foo.txt']); - $this->util->expects($this->any()) - ->method('stripPartialFileExtension') - ->willReturnArgument(0); - $this->util->expects($this->any()) - ->method('isSystemWideMountPoint') - ->willReturn(false); - $this->view->expects($this->once()) - ->method('file_exists') - ->with($this->equalTo('/user1/files_encryption/keys/files/foo.txt/encModule/fileKey')) - ->willReturn(true); - $this->view->expects($this->once()) - ->method('unlink') - ->with($this->equalTo('/user1/files_encryption/keys/files/foo.txt/encModule/fileKey')) - ->willReturn(true); - - $this->assertTrue( - $this->storage->deleteFileKey('user1/files/foo.txt', 'fileKey', 'encModule') - ); - } - - /** - * @dataProvider dataProviderCopyRename - */ - public function testRenameKeys($source, $target, $systemWideMountSource, $systemWideMountTarget, $expectedSource, $expectedTarget): void { - $this->view->expects($this->any()) - ->method('file_exists') - ->willReturn(true); - $this->view->expects($this->any()) - ->method('is_dir') - ->willReturn(true); - $this->view->expects($this->once()) - ->method('rename') - ->with( - $this->equalTo($expectedSource), - $this->equalTo($expectedTarget)) - ->willReturn(true); - $this->util->expects($this->any()) - ->method('getUidAndFilename') - ->willReturnCallback([$this, 'getUidAndFilenameCallback']); - $this->util->expects($this->any()) - ->method('isSystemWideMountPoint') - ->willReturnCallback(function ($path, $owner) use ($systemWideMountSource, $systemWideMountTarget) { - if (strpos($path, 'source.txt') !== false) { - return $systemWideMountSource; - } - return $systemWideMountTarget; - }); - - $this->storage->renameKeys($source, $target); - } - - /** - * @dataProvider dataProviderCopyRename - */ - public function testCopyKeys($source, $target, $systemWideMountSource, $systemWideMountTarget, $expectedSource, $expectedTarget): void { - $this->view->expects($this->any()) - ->method('file_exists') - ->willReturn(true); - $this->view->expects($this->any()) - ->method('is_dir') - ->willReturn(true); - $this->view->expects($this->once()) - ->method('copy') - ->with( - $this->equalTo($expectedSource), - $this->equalTo($expectedTarget)) - ->willReturn(true); - $this->util->expects($this->any()) - ->method('getUidAndFilename') - ->willReturnCallback([$this, 'getUidAndFilenameCallback']); - $this->util->expects($this->any()) - ->method('isSystemWideMountPoint') - ->willReturnCallback(function ($path, $owner) use ($systemWideMountSource, $systemWideMountTarget) { - if (strpos($path, 'source.txt') !== false) { - return $systemWideMountSource; - } - return $systemWideMountTarget; - }); - - $this->storage->copyKeys($source, $target); - } - - public function getUidAndFilenameCallback() { - $args = func_get_args(); - - $path = $args[0]; - $parts = explode('/', $path); - - return [$parts[1], '/' . implode('/', array_slice($parts, 2))]; - } - - public function dataProviderCopyRename() { - return [ - ['/user1/files/source.txt', '/user1/files/target.txt', false, false, - '/user1/files_encryption/keys/files/source.txt/', '/user1/files_encryption/keys/files/target.txt/'], - ['/user1/files/foo/source.txt', '/user1/files/target.txt', false, false, - '/user1/files_encryption/keys/files/foo/source.txt/', '/user1/files_encryption/keys/files/target.txt/'], - ['/user1/files/source.txt', '/user1/files/foo/target.txt', false, false, - '/user1/files_encryption/keys/files/source.txt/', '/user1/files_encryption/keys/files/foo/target.txt/'], - ['/user1/files/source.txt', '/user1/files/foo/target.txt', true, true, - '/files_encryption/keys/files/source.txt/', '/files_encryption/keys/files/foo/target.txt/'], - ['/user1/files/source.txt', '/user1/files/target.txt', false, true, - '/user1/files_encryption/keys/files/source.txt/', '/files_encryption/keys/files/target.txt/'], - ['/user1/files/source.txt', '/user1/files/target.txt', true, false, - '/files_encryption/keys/files/source.txt/', '/user1/files_encryption/keys/files/target.txt/'], - - ['/user2/files/source.txt', '/user1/files/target.txt', false, false, - '/user2/files_encryption/keys/files/source.txt/', '/user1/files_encryption/keys/files/target.txt/'], - ['/user2/files/foo/source.txt', '/user1/files/target.txt', false, false, - '/user2/files_encryption/keys/files/foo/source.txt/', '/user1/files_encryption/keys/files/target.txt/'], - ['/user2/files/source.txt', '/user1/files/foo/target.txt', false, false, - '/user2/files_encryption/keys/files/source.txt/', '/user1/files_encryption/keys/files/foo/target.txt/'], - ['/user2/files/source.txt', '/user1/files/foo/target.txt', true, true, - '/files_encryption/keys/files/source.txt/', '/files_encryption/keys/files/foo/target.txt/'], - ['/user2/files/source.txt', '/user1/files/target.txt', false, true, - '/user2/files_encryption/keys/files/source.txt/', '/files_encryption/keys/files/target.txt/'], - ['/user2/files/source.txt', '/user1/files/target.txt', true, false, - '/files_encryption/keys/files/source.txt/', '/user1/files_encryption/keys/files/target.txt/'], - ]; - } - - /** - * @dataProvider dataTestGetPathToKeys - * - * @param string $path - * @param boolean $systemWideMountPoint - * @param string $storageRoot - * @param string $expected - */ - public function testGetPathToKeys($path, $systemWideMountPoint, $storageRoot, $expected): void { - $this->invokePrivate($this->storage, 'root_dir', [$storageRoot]); - - $this->util->expects($this->any()) - ->method('getUidAndFilename') - ->willReturnCallback([$this, 'getUidAndFilenameCallback']); - $this->util->expects($this->any()) - ->method('isSystemWideMountPoint') - ->willReturn($systemWideMountPoint); - - $this->assertSame($expected, - self::invokePrivate($this->storage, 'getPathToKeys', [$path]) - ); - } - - public function dataTestGetPathToKeys() { - return [ - ['/user1/files/source.txt', false, '', '/user1/files_encryption/keys/files/source.txt/'], - ['/user1/files/source.txt', true, '', '/files_encryption/keys/files/source.txt/'], - ['/user1/files/source.txt', false, 'storageRoot', '/storageRoot/user1/files_encryption/keys/files/source.txt/'], - ['/user1/files/source.txt', true, 'storageRoot', '/storageRoot/files_encryption/keys/files/source.txt/'], - ]; - } - - public function testKeySetPreparation(): void { - $this->view->expects($this->any()) - ->method('file_exists') - ->willReturn(false); - $this->view->expects($this->any()) - ->method('is_dir') - ->willReturn(false); - $this->view->expects($this->any()) - ->method('mkdir') - ->willReturnCallback([$this, 'mkdirCallback']); - - $this->mkdirStack = [ - '/user1/files_encryption/keys/foo', - '/user1/files_encryption/keys', - '/user1/files_encryption', - '/user1']; - - self::invokePrivate($this->storage, 'keySetPreparation', ['/user1/files_encryption/keys/foo']); - } - - public function mkdirCallback() { - $args = func_get_args(); - $expected = array_pop($this->mkdirStack); - $this->assertSame($expected, $args[0]); - } - - - /** - * @dataProvider dataTestBackupUserKeys - * @param bool $createBackupDir - */ - public function testBackupUserKeys($createBackupDir): void { - $storage = $this->getMockBuilder('OC\Encryption\Keys\Storage') - ->setConstructorArgs([$this->view, $this->util, $this->crypto, $this->config]) - ->setMethods(['getTimestamp']) - ->getMock(); - - $storage->expects($this->any())->method('getTimestamp')->willReturn('1234567'); - - $this->view->expects($this->once())->method('file_exists') - ->with('user1/files_encryption/backup')->willReturn(!$createBackupDir); - - if ($createBackupDir) { - $this->view->expects($this->exactly(2))->method('mkdir') - ->withConsecutive( - ['user1/files_encryption/backup'], - ['user1/files_encryption/backup/test.encryptionModule.1234567'], - ); - } else { - $this->view->expects($this->once())->method('mkdir') - ->with('user1/files_encryption/backup/test.encryptionModule.1234567'); - } - - $this->view->expects($this->once())->method('copy') - ->with( - 'user1/files_encryption/encryptionModule', - 'user1/files_encryption/backup/test.encryptionModule.1234567' - )->willReturn(true); - - $this->assertTrue($storage->backupUserKeys('encryptionModule', 'test', 'user1')); - } - - public function dataTestBackupUserKeys() { - return [ - [true], [false] - ]; - } -} +<?php + +/** + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\Encryption\Keys; + +use OC\Encryption\Keys\Storage; +use OC\Files\View; +use OCP\IConfig; +use OCP\Security\ICrypto; +use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; + +class StorageTest extends TestCase { + /** @var Storage */ + protected $storage; + + /** @var MockObject|\OC\Encryption\Util */ + protected $util; + + /** @var MockObject|View */ + protected $view; + + /** @var MockObject|IConfig */ + protected $config; + + /** @var MockObject|ICrypto */ + protected $crypto; + + private array $mkdirStack = []; + + protected function setUp(): void { + parent::setUp(); + + $this->util = $this->getMockBuilder(\OC\Encryption\Util::class) + ->disableOriginalConstructor() + ->setMethodsExcept(['getFileKeyDir']) + ->getMock(); + + $this->view = $this->getMockBuilder(View::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->crypto = $this->createMock(ICrypto::class); + $this->crypto->method('encrypt') + ->willReturnCallback(function ($data, $pass) { + return $data; + }); + $this->crypto->method('decrypt') + ->willReturnCallback(function ($data, $pass) { + return $data; + }); + + $this->config = $this->getMockBuilder(IConfig::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->storage = new Storage($this->view, $this->util, $this->crypto, $this->config); + } + + public function testSetFileKey(): void { + $this->config->method('getSystemValueString') + ->with('version') + ->willReturn('20.0.0.2'); + $this->util->expects($this->any()) + ->method('getUidAndFilename') + ->willReturn(['user1', '/files/foo.txt']); + $this->util->expects($this->any()) + ->method('stripPartialFileExtension') + ->willReturnArgument(0); + $this->util->expects($this->any()) + ->method('isSystemWideMountPoint') + ->willReturn(false); + + $data = json_encode(['key' => base64_encode('key')]); + $this->view->expects($this->once()) + ->method('file_put_contents') + ->with($this->equalTo('/user1/files_encryption/keys/files/foo.txt/encModule/fileKey'), + $this->equalTo($data)) + ->willReturn(strlen($data)); + + $this->assertTrue( + $this->storage->setFileKey('user1/files/foo.txt', 'fileKey', 'key', 'encModule') + ); + } + + public function testSetFileOld(): void { + $this->config->method('getSystemValueString') + ->with('version') + ->willReturn('20.0.0.0'); + $this->util->expects($this->any()) + ->method('getUidAndFilename') + ->willReturn(['user1', '/files/foo.txt']); + $this->util->expects($this->any()) + ->method('stripPartialFileExtension') + ->willReturnArgument(0); + $this->util->expects($this->any()) + ->method('isSystemWideMountPoint') + ->willReturn(false); + $this->crypto->expects($this->never()) + ->method('encrypt'); + $this->view->expects($this->once()) + ->method('file_put_contents') + ->with($this->equalTo('/user1/files_encryption/keys/files/foo.txt/encModule/fileKey'), + $this->equalTo('key')) + ->willReturn(strlen('key')); + + $this->assertTrue( + $this->storage->setFileKey('user1/files/foo.txt', 'fileKey', 'key', 'encModule') + ); + } + + public function dataTestGetFileKey() { + return [ + ['/files/foo.txt', '/files/foo.txt', true, 'key'], + ['/files/foo.txt.ocTransferId2111130212.part', '/files/foo.txt', true, 'key'], + ['/files/foo.txt.ocTransferId2111130212.part', '/files/foo.txt', false, 'key2'], + ]; + } + + /** + * @dataProvider dataTestGetFileKey + * + * @param string $path + * @param string $strippedPartialName + * @param bool $originalKeyExists + * @param string $expectedKeyContent + */ + public function testGetFileKey($path, $strippedPartialName, $originalKeyExists, $expectedKeyContent): void { + $this->config->method('getSystemValueString') + ->with('version') + ->willReturn('20.0.0.2'); + $this->util->expects($this->any()) + ->method('getUidAndFilename') + ->willReturnMap([ + ['user1/files/foo.txt', ['user1', '/files/foo.txt']], + ['user1/files/foo.txt.ocTransferId2111130212.part', ['user1', '/files/foo.txt.ocTransferId2111130212.part']], + ]); + // we need to strip away the part file extension in order to reuse a + // existing key if it exists, otherwise versions will break + $this->util->expects($this->once()) + ->method('stripPartialFileExtension') + ->willReturn('user1' . $strippedPartialName); + $this->util->expects($this->any()) + ->method('isSystemWideMountPoint') + ->willReturn(false); + + $this->crypto->method('decrypt') + ->willReturnCallback(function ($data, $pass) { + return $data; + }); + + if (!$originalKeyExists) { + $this->view->expects($this->exactly(2)) + ->method('file_exists') + ->withConsecutive( + [$this->equalTo('/user1/files_encryption/keys' . $strippedPartialName . '/encModule/fileKey')], + [$this->equalTo('/user1/files_encryption/keys' . $path . '/encModule/fileKey')], + )->willReturnOnConsecutiveCalls( + $originalKeyExists, + true, + ); + + $this->view->expects($this->once()) + ->method('file_get_contents') + ->with($this->equalTo('/user1/files_encryption/keys' . $path . '/encModule/fileKey')) + ->willReturn(json_encode(['key' => base64_encode('key2')])); + } else { + $this->view->expects($this->once()) + ->method('file_exists') + ->with($this->equalTo('/user1/files_encryption/keys' . $strippedPartialName . '/encModule/fileKey')) + ->willReturn($originalKeyExists); + + $this->view->expects($this->once()) + ->method('file_get_contents') + ->with($this->equalTo('/user1/files_encryption/keys' . $strippedPartialName . '/encModule/fileKey')) + ->willReturn(json_encode(['key' => base64_encode('key')])); + } + + $this->assertSame($expectedKeyContent, + $this->storage->getFileKey('user1' . $path, 'fileKey', 'encModule') + ); + } + + public function testSetFileKeySystemWide(): void { + $this->config->method('getSystemValueString') + ->with('version') + ->willReturn('20.0.0.2'); + + $this->util->expects($this->any()) + ->method('getUidAndFilename') + ->willReturn(['user1', '/files/foo.txt']); + $this->util->expects($this->any()) + ->method('isSystemWideMountPoint') + ->willReturn(true); + $this->util->expects($this->any()) + ->method('stripPartialFileExtension') + ->willReturnArgument(0); + + $this->crypto->method('encrypt') + ->willReturnCallback(function ($data, $pass) { + return $data; + }); + + $data = json_encode(['key' => base64_encode('key')]); + $this->view->expects($this->once()) + ->method('file_put_contents') + ->with($this->equalTo('/files_encryption/keys/files/foo.txt/encModule/fileKey'), + $this->equalTo($data)) + ->willReturn(strlen($data)); + + $this->assertTrue( + $this->storage->setFileKey('user1/files/foo.txt', 'fileKey', 'key', 'encModule') + ); + } + + public function testGetFileKeySystemWide(): void { + $this->config->method('getSystemValueString') + ->with('version') + ->willReturn('20.0.0.2'); + + $this->util->expects($this->any()) + ->method('getUidAndFilename') + ->willReturn(['user1', '/files/foo.txt']); + $this->util->expects($this->any()) + ->method('stripPartialFileExtension') + ->willReturnArgument(0); + $this->util->expects($this->any()) + ->method('isSystemWideMountPoint') + ->willReturn(true); + $this->view->expects($this->once()) + ->method('file_get_contents') + ->with($this->equalTo('/files_encryption/keys/files/foo.txt/encModule/fileKey')) + ->willReturn(json_encode(['key' => base64_encode('key')])); + $this->view->expects($this->once()) + ->method('file_exists') + ->with($this->equalTo('/files_encryption/keys/files/foo.txt/encModule/fileKey')) + ->willReturn(true); + + $this->assertSame('key', + $this->storage->getFileKey('user1/files/foo.txt', 'fileKey', 'encModule') + ); + } + + public function testSetSystemUserKey(): void { + $this->config->method('getSystemValueString') + ->with('version') + ->willReturn('20.0.0.2'); + + $data = json_encode([ + 'key' => base64_encode('key'), + 'uid' => null] + ); + $this->view->expects($this->once()) + ->method('file_put_contents') + ->with($this->equalTo('/files_encryption/encModule/shareKey_56884'), + $this->equalTo($data)) + ->willReturn(strlen($data)); + + $this->assertTrue( + $this->storage->setSystemUserKey('shareKey_56884', 'key', 'encModule') + ); + } + + public function testSetUserKey(): void { + $this->config->method('getSystemValueString') + ->with('version') + ->willReturn('20.0.0.2'); + + $data = json_encode([ + 'key' => base64_encode('key'), + 'uid' => 'user1'] + ); + $this->view->expects($this->once()) + ->method('file_put_contents') + ->with($this->equalTo('/user1/files_encryption/encModule/user1.publicKey'), + $this->equalTo($data)) + ->willReturn(strlen($data)); + + $this->assertTrue( + $this->storage->setUserKey('user1', 'publicKey', 'key', 'encModule') + ); + } + + public function testGetSystemUserKey(): void { + $this->config->method('getSystemValueString') + ->with('version') + ->willReturn('20.0.0.2'); + + $data = json_encode([ + 'key' => base64_encode('key'), + 'uid' => null] + ); + $this->view->expects($this->once()) + ->method('file_get_contents') + ->with($this->equalTo('/files_encryption/encModule/shareKey_56884')) + ->willReturn($data); + $this->view->expects($this->once()) + ->method('file_exists') + ->with($this->equalTo('/files_encryption/encModule/shareKey_56884')) + ->willReturn(true); + + $this->assertSame('key', + $this->storage->getSystemUserKey('shareKey_56884', 'encModule') + ); + } + + public function testGetUserKey(): void { + $this->config->method('getSystemValueString') + ->with('version') + ->willReturn('20.0.0.2'); + + $data = json_encode([ + 'key' => base64_encode('key'), + 'uid' => 'user1'] + ); + $this->view->expects($this->once()) + ->method('file_get_contents') + ->with($this->equalTo('/user1/files_encryption/encModule/user1.publicKey')) + ->willReturn($data); + $this->view->expects($this->once()) + ->method('file_exists') + ->with($this->equalTo('/user1/files_encryption/encModule/user1.publicKey')) + ->willReturn(true); + + $this->assertSame('key', + $this->storage->getUserKey('user1', 'publicKey', 'encModule') + ); + } + + public function testDeleteUserKey(): void { + $this->view->expects($this->once()) + ->method('file_exists') + ->with($this->equalTo('/user1/files_encryption/encModule/user1.publicKey')) + ->willReturn(true); + $this->view->expects($this->once()) + ->method('unlink') + ->with($this->equalTo('/user1/files_encryption/encModule/user1.publicKey')) + ->willReturn(true); + + $this->assertTrue( + $this->storage->deleteUserKey('user1', 'publicKey', 'encModule') + ); + } + + public function testDeleteSystemUserKey(): void { + $this->view->expects($this->once()) + ->method('file_exists') + ->with($this->equalTo('/files_encryption/encModule/shareKey_56884')) + ->willReturn(true); + $this->view->expects($this->once()) + ->method('unlink') + ->with($this->equalTo('/files_encryption/encModule/shareKey_56884')) + ->willReturn(true); + + $this->assertTrue( + $this->storage->deleteSystemUserKey('shareKey_56884', 'encModule') + ); + } + + public function testDeleteFileKeySystemWide(): void { + $this->util->expects($this->any()) + ->method('getUidAndFilename') + ->willReturn(['user1', '/files/foo.txt']); + $this->util->expects($this->any()) + ->method('stripPartialFileExtension') + ->willReturnArgument(0); + $this->util->expects($this->any()) + ->method('isSystemWideMountPoint') + ->willReturn(true); + $this->view->expects($this->once()) + ->method('file_exists') + ->with($this->equalTo('/files_encryption/keys/files/foo.txt/encModule/fileKey')) + ->willReturn(true); + $this->view->expects($this->once()) + ->method('unlink') + ->with($this->equalTo('/files_encryption/keys/files/foo.txt/encModule/fileKey')) + ->willReturn(true); + + $this->assertTrue( + $this->storage->deleteFileKey('user1/files/foo.txt', 'fileKey', 'encModule') + ); + } + + public function testDeleteFileKey(): void { + $this->util->expects($this->any()) + ->method('getUidAndFilename') + ->willReturn(['user1', '/files/foo.txt']); + $this->util->expects($this->any()) + ->method('stripPartialFileExtension') + ->willReturnArgument(0); + $this->util->expects($this->any()) + ->method('isSystemWideMountPoint') + ->willReturn(false); + $this->view->expects($this->once()) + ->method('file_exists') + ->with($this->equalTo('/user1/files_encryption/keys/files/foo.txt/encModule/fileKey')) + ->willReturn(true); + $this->view->expects($this->once()) + ->method('unlink') + ->with($this->equalTo('/user1/files_encryption/keys/files/foo.txt/encModule/fileKey')) + ->willReturn(true); + + $this->assertTrue( + $this->storage->deleteFileKey('user1/files/foo.txt', 'fileKey', 'encModule') + ); + } + + /** + * @dataProvider dataProviderCopyRename + */ + public function testRenameKeys($source, $target, $systemWideMountSource, $systemWideMountTarget, $expectedSource, $expectedTarget): void { + $this->view->expects($this->any()) + ->method('file_exists') + ->willReturn(true); + $this->view->expects($this->any()) + ->method('is_dir') + ->willReturn(true); + $this->view->expects($this->once()) + ->method('rename') + ->with( + $this->equalTo($expectedSource), + $this->equalTo($expectedTarget)) + ->willReturn(true); + $this->util->expects($this->any()) + ->method('getUidAndFilename') + ->willReturnCallback([$this, 'getUidAndFilenameCallback']); + $this->util->expects($this->any()) + ->method('isSystemWideMountPoint') + ->willReturnCallback(function ($path, $owner) use ($systemWideMountSource, $systemWideMountTarget) { + if (strpos($path, 'source.txt') !== false) { + return $systemWideMountSource; + } + return $systemWideMountTarget; + }); + + $this->storage->renameKeys($source, $target); + } + + /** + * @dataProvider dataProviderCopyRename + */ + public function testCopyKeys($source, $target, $systemWideMountSource, $systemWideMountTarget, $expectedSource, $expectedTarget): void { + $this->view->expects($this->any()) + ->method('file_exists') + ->willReturn(true); + $this->view->expects($this->any()) + ->method('is_dir') + ->willReturn(true); + $this->view->expects($this->once()) + ->method('copy') + ->with( + $this->equalTo($expectedSource), + $this->equalTo($expectedTarget)) + ->willReturn(true); + $this->util->expects($this->any()) + ->method('getUidAndFilename') + ->willReturnCallback([$this, 'getUidAndFilenameCallback']); + $this->util->expects($this->any()) + ->method('isSystemWideMountPoint') + ->willReturnCallback(function ($path, $owner) use ($systemWideMountSource, $systemWideMountTarget) { + if (strpos($path, 'source.txt') !== false) { + return $systemWideMountSource; + } + return $systemWideMountTarget; + }); + + $this->storage->copyKeys($source, $target); + } + + public function getUidAndFilenameCallback() { + $args = func_get_args(); + + $path = $args[0]; + $parts = explode('/', $path); + + return [$parts[1], '/' . implode('/', array_slice($parts, 2))]; + } + + public function dataProviderCopyRename() { + return [ + ['/user1/files/source.txt', '/user1/files/target.txt', false, false, + '/user1/files_encryption/keys/files/source.txt/', '/user1/files_encryption/keys/files/target.txt/'], + ['/user1/files/foo/source.txt', '/user1/files/target.txt', false, false, + '/user1/files_encryption/keys/files/foo/source.txt/', '/user1/files_encryption/keys/files/target.txt/'], + ['/user1/files/source.txt', '/user1/files/foo/target.txt', false, false, + '/user1/files_encryption/keys/files/source.txt/', '/user1/files_encryption/keys/files/foo/target.txt/'], + ['/user1/files/source.txt', '/user1/files/foo/target.txt', true, true, + '/files_encryption/keys/files/source.txt/', '/files_encryption/keys/files/foo/target.txt/'], + ['/user1/files/source.txt', '/user1/files/target.txt', false, true, + '/user1/files_encryption/keys/files/source.txt/', '/files_encryption/keys/files/target.txt/'], + ['/user1/files/source.txt', '/user1/files/target.txt', true, false, + '/files_encryption/keys/files/source.txt/', '/user1/files_encryption/keys/files/target.txt/'], + + ['/user2/files/source.txt', '/user1/files/target.txt', false, false, + '/user2/files_encryption/keys/files/source.txt/', '/user1/files_encryption/keys/files/target.txt/'], + ['/user2/files/foo/source.txt', '/user1/files/target.txt', false, false, + '/user2/files_encryption/keys/files/foo/source.txt/', '/user1/files_encryption/keys/files/target.txt/'], + ['/user2/files/source.txt', '/user1/files/foo/target.txt', false, false, + '/user2/files_encryption/keys/files/source.txt/', '/user1/files_encryption/keys/files/foo/target.txt/'], + ['/user2/files/source.txt', '/user1/files/foo/target.txt', true, true, + '/files_encryption/keys/files/source.txt/', '/files_encryption/keys/files/foo/target.txt/'], + ['/user2/files/source.txt', '/user1/files/target.txt', false, true, + '/user2/files_encryption/keys/files/source.txt/', '/files_encryption/keys/files/target.txt/'], + ['/user2/files/source.txt', '/user1/files/target.txt', true, false, + '/files_encryption/keys/files/source.txt/', '/user1/files_encryption/keys/files/target.txt/'], + ]; + } + + /** + * @dataProvider dataTestGetPathToKeys + * + * @param string $path + * @param boolean $systemWideMountPoint + * @param string $storageRoot + * @param string $expected + */ + public function testGetPathToKeys($path, $systemWideMountPoint, $storageRoot, $expected): void { + $this->invokePrivate($this->storage, 'root_dir', [$storageRoot]); + + $this->util->expects($this->any()) + ->method('getUidAndFilename') + ->willReturnCallback([$this, 'getUidAndFilenameCallback']); + $this->util->expects($this->any()) + ->method('isSystemWideMountPoint') + ->willReturn($systemWideMountPoint); + + $this->assertSame($expected, + self::invokePrivate($this->storage, 'getPathToKeys', [$path]) + ); + } + + public function dataTestGetPathToKeys() { + return [ + ['/user1/files/source.txt', false, '', '/user1/files_encryption/keys/files/source.txt/'], + ['/user1/files/source.txt', true, '', '/files_encryption/keys/files/source.txt/'], + ['/user1/files/source.txt', false, 'storageRoot', '/storageRoot/user1/files_encryption/keys/files/source.txt/'], + ['/user1/files/source.txt', true, 'storageRoot', '/storageRoot/files_encryption/keys/files/source.txt/'], + ]; + } + + public function testKeySetPreparation(): void { + $this->view->expects($this->any()) + ->method('file_exists') + ->willReturn(false); + $this->view->expects($this->any()) + ->method('is_dir') + ->willReturn(false); + $this->view->expects($this->any()) + ->method('mkdir') + ->willReturnCallback([$this, 'mkdirCallback']); + + $this->mkdirStack = [ + '/user1/files_encryption/keys/foo', + '/user1/files_encryption/keys', + '/user1/files_encryption', + '/user1']; + + self::invokePrivate($this->storage, 'keySetPreparation', ['/user1/files_encryption/keys/foo']); + } + + public function mkdirCallback() { + $args = func_get_args(); + $expected = array_pop($this->mkdirStack); + $this->assertSame($expected, $args[0]); + } + + + /** + * @dataProvider dataTestBackupUserKeys + * @param bool $createBackupDir + */ + public function testBackupUserKeys($createBackupDir): void { + $storage = $this->getMockBuilder(\OC\Encryption\Keys\Storage::class) + ->setConstructorArgs([$this->view, $this->util, $this->crypto, $this->config]) + ->setMethods(['getTimestamp']) + ->getMock(); + + $storage->expects($this->any())->method('getTimestamp')->willReturn('1234567'); + + $this->view->expects($this->once())->method('file_exists') + ->with('user1/files_encryption/backup')->willReturn(!$createBackupDir); + + if ($createBackupDir) { + $this->view->expects($this->exactly(2))->method('mkdir') + ->withConsecutive( + ['user1/files_encryption/backup'], + ['user1/files_encryption/backup/test.encryptionModule.1234567'], + ); + } else { + $this->view->expects($this->once())->method('mkdir') + ->with('user1/files_encryption/backup/test.encryptionModule.1234567'); + } + + $this->view->expects($this->once())->method('copy') + ->with( + 'user1/files_encryption/encryptionModule', + 'user1/files_encryption/backup/test.encryptionModule.1234567' + )->willReturn(true); + + $this->assertTrue($storage->backupUserKeys('encryptionModule', 'test', 'user1')); + } + + public function dataTestBackupUserKeys() { + return [ + [true], [false] + ]; + } +} diff --git a/tests/lib/Encryption/UpdateTest.php b/tests/lib/Encryption/UpdateTest.php index 2627e18601d..012a6685a91 100644 --- a/tests/lib/Encryption/UpdateTest.php +++ b/tests/lib/Encryption/UpdateTest.php @@ -203,7 +203,7 @@ class UpdateTest extends TestCase { * @return \OC\Encryption\Update | \PHPUnit\Framework\MockObject\MockObject */ protected function getUpdateMock($methods) { - return $this->getMockBuilder('\OC\Encryption\Update') + return $this->getMockBuilder(\OC\Encryption\Update::class) ->setConstructorArgs( [ $this->view, diff --git a/tests/lib/Files/Cache/CacheTest.php b/tests/lib/Files/Cache/CacheTest.php index 9e3460ab6f2..de6f4896aec 100644 --- a/tests/lib/Files/Cache/CacheTest.php +++ b/tests/lib/Files/Cache/CacheTest.php @@ -638,7 +638,7 @@ class CacheTest extends \Test\TestCase { $this->assertEquals($folderWith00F6, $unNormalizedFolderName['name']); // put normalized folder - $this->assertInstanceOf('\OCP\Files\Cache\ICacheEntry', $this->cache->get('folder/' . $folderWith00F6)); + $this->assertInstanceOf(\OCP\Files\Cache\ICacheEntry::class, $this->cache->get('folder/' . $folderWith00F6)); $this->assertGreaterThan(0, $this->cache->put('folder/' . $folderWith00F6, $data)); // at this point we should have only one folder named "Schön" diff --git a/tests/lib/Files/Config/UserMountCacheTest.php b/tests/lib/Files/Config/UserMountCacheTest.php index a6f25026193..77b2c80d053 100644 --- a/tests/lib/Files/Config/UserMountCacheTest.php +++ b/tests/lib/Files/Config/UserMountCacheTest.php @@ -88,21 +88,21 @@ class UserMountCacheTest extends TestCase { private function getStorage($storageId, $rootInternalPath = '') { $rootId = $this->createCacheEntry($rootInternalPath, $storageId); - $storageCache = $this->getMockBuilder('\OC\Files\Cache\Storage') + $storageCache = $this->getMockBuilder(\OC\Files\Cache\Storage::class) ->disableOriginalConstructor() ->getMock(); $storageCache->expects($this->any()) ->method('getNumericId') ->willReturn($storageId); - $cache = $this->getMockBuilder('\OC\Files\Cache\Cache') + $cache = $this->getMockBuilder(\OC\Files\Cache\Cache::class) ->disableOriginalConstructor() ->getMock(); $cache->expects($this->any()) ->method('getId') ->willReturn($rootId); - $storage = $this->getMockBuilder('\OC\Files\Storage\Storage') + $storage = $this->getMockBuilder(\OC\Files\Storage\Storage::class) ->disableOriginalConstructor() ->getMock(); $storage->expects($this->any()) @@ -425,7 +425,7 @@ class UserMountCacheTest extends TestCase { $fileId = $this->createCacheEntry('/foo/bar', 2); - $mount1 = $this->getMockBuilder('\OC\Files\Mount\MountPoint') + $mount1 = $this->getMockBuilder(\OC\Files\Mount\MountPoint::class) ->setConstructorArgs([$storage1, '/']) ->setMethods(['getStorageRootId']) ->getMock(); @@ -458,7 +458,7 @@ class UserMountCacheTest extends TestCase { $folderId = $this->createCacheEntry('/foo', 2); $fileId = $this->createCacheEntry('/bar/asd', 2); - $mount1 = $this->getMockBuilder('\OC\Files\Mount\MountPoint') + $mount1 = $this->getMockBuilder(\OC\Files\Mount\MountPoint::class) ->setConstructorArgs([$storage1, '/foo/']) ->setMethods(['getStorageRootId']) ->getMock(); diff --git a/tests/lib/Files/EtagTest.php b/tests/lib/Files/EtagTest.php index dbf65eac439..2c8888b2dea 100644 --- a/tests/lib/Files/EtagTest.php +++ b/tests/lib/Files/EtagTest.php @@ -36,8 +36,8 @@ class EtagTest extends \Test\TestCase { // init files sharing new Application(); - \OC\Share\Share::registerBackend('file', 'OCA\Files_Sharing\ShareBackend\File'); - \OC\Share\Share::registerBackend('folder', 'OCA\Files_Sharing\ShareBackend\Folder', 'file'); + \OC\Share\Share::registerBackend('file', \OCA\Files_Sharing\ShareBackend\File::class); + \OC\Share\Share::registerBackend('folder', \OCA\Files_Sharing\ShareBackend\Folder::class, 'file'); $config = \OC::$server->getConfig(); $this->datadir = $config->getSystemValueString('datadirectory'); diff --git a/tests/lib/Files/FilesystemTest.php b/tests/lib/Files/FilesystemTest.php index 91f0bb9b01d..c47d85994c6 100644 --- a/tests/lib/Files/FilesystemTest.php +++ b/tests/lib/Files/FilesystemTest.php @@ -1,476 +1,476 @@ -<?php -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -namespace Test\Files; - -use OC\Files\Mount\MountPoint; -use OC\Files\Storage\Temporary; -use OC\User\NoUserException; -use OCP\Files\Config\IMountProvider; -use OCP\Files\Storage\IStorageFactory; -use OCP\IUser; - -class DummyMountProvider implements IMountProvider { - private $mounts = []; - - /** - * @param array $mounts - */ - public function __construct(array $mounts) { - $this->mounts = $mounts; - } - - /** - * Get the pre-registered mount points - * - * @param IUser $user - * @param IStorageFactory $loader - * @return \OCP\Files\Mount\IMountPoint[] - */ - public function getMountsForUser(IUser $user, IStorageFactory $loader) { - return isset($this->mounts[$user->getUID()]) ? $this->mounts[$user->getUID()] : []; - } -} - -/** - * Class FilesystemTest - * - * @group DB - * - * @package Test\Files - */ -class FilesystemTest extends \Test\TestCase { - public const TEST_FILESYSTEM_USER1 = 'test-filesystem-user1'; - public const TEST_FILESYSTEM_USER2 = 'test-filesystem-user1'; - - /** - * @var array tmpDirs - */ - private $tmpDirs = []; - - /** - * @return array - */ - private function getStorageData() { - $dir = \OC::$server->getTempManager()->getTemporaryFolder(); - $this->tmpDirs[] = $dir; - return ['datadir' => $dir]; - } - - protected function setUp(): void { - parent::setUp(); - $userBackend = new \Test\Util\User\Dummy(); - $userBackend->createUser(self::TEST_FILESYSTEM_USER1, self::TEST_FILESYSTEM_USER1); - $userBackend->createUser(self::TEST_FILESYSTEM_USER2, self::TEST_FILESYSTEM_USER2); - \OC::$server->getUserManager()->registerBackend($userBackend); - $this->loginAsUser(); - } - - protected function tearDown(): void { - foreach ($this->tmpDirs as $dir) { - \OC_Helper::rmdirr($dir); - } - - $this->logout(); - $this->invokePrivate('\OC\Files\Filesystem', 'normalizedPathCache', [null]); - parent::tearDown(); - } - - public function testMount(): void { - \OC\Files\Filesystem::mount('\OC\Files\Storage\Local', self::getStorageData(), '/'); - $this->assertEquals('/', \OC\Files\Filesystem::getMountPoint('/')); - $this->assertEquals('/', \OC\Files\Filesystem::getMountPoint('/some/folder')); - [, $internalPath] = \OC\Files\Filesystem::resolvePath('/'); - $this->assertEquals('', $internalPath); - [, $internalPath] = \OC\Files\Filesystem::resolvePath('/some/folder'); - $this->assertEquals('some/folder', $internalPath); - - \OC\Files\Filesystem::mount('\OC\Files\Storage\Local', self::getStorageData(), '/some'); - $this->assertEquals('/', \OC\Files\Filesystem::getMountPoint('/')); - $this->assertEquals('/some/', \OC\Files\Filesystem::getMountPoint('/some/folder')); - $this->assertEquals('/some/', \OC\Files\Filesystem::getMountPoint('/some/')); - $this->assertEquals('/some/', \OC\Files\Filesystem::getMountPoint('/some')); - [, $internalPath] = \OC\Files\Filesystem::resolvePath('/some/folder'); - $this->assertEquals('folder', $internalPath); - } - - public function normalizePathData() { - return [ - ['/', ''], - ['/', '/'], - ['/', '//'], - ['/', '/', false], - ['/', '//', false], - - ['/path', '/path/'], - ['/path/', '/path/', false], - ['/path', 'path'], - - ['/foo/bar', '/foo//bar/'], - ['/foo/bar/', '/foo//bar/', false], - ['/foo/bar', '/foo////bar'], - ['/foo/bar', '/foo/////bar'], - ['/foo/bar', '/foo/bar/.'], - ['/foo/bar', '/foo/bar/./'], - ['/foo/bar/', '/foo/bar/./', false], - ['/foo/bar', '/foo/bar/./.'], - ['/foo/bar', '/foo/bar/././'], - ['/foo/bar/', '/foo/bar/././', false], - ['/foo/bar', '/foo/./bar/'], - ['/foo/bar/', '/foo/./bar/', false], - ['/foo/.bar', '/foo/.bar/'], - ['/foo/.bar/', '/foo/.bar/', false], - ['/foo/.bar/tee', '/foo/.bar/tee'], - ['/foo/bar.', '/foo/bar./'], - ['/foo/bar./', '/foo/bar./', false], - ['/foo/bar./tee', '/foo/bar./tee'], - ['/foo/.bar.', '/foo/.bar./'], - ['/foo/.bar./', '/foo/.bar./', false], - ['/foo/.bar./tee', '/foo/.bar./tee'], - - ['/foo/bar', '/.////././//./foo/.///././//./bar/././/./.'], - ['/foo/bar/', '/.////././//./foo/.///././//./bar/./././.', false], - ['/foo/bar', '/.////././//./foo/.///././//./bar/././/././'], - ['/foo/bar/', '/.////././//./foo/.///././//./bar/././/././', false], - ['/foo/.bar', '/.////././//./foo/./././/./.bar/././/././'], - ['/foo/.bar/', '/.////././//./foo/./././/./.bar/././/././', false], - ['/foo/.bar/tee./', '/.////././//./foo/./././/./.bar/tee././/././', false], - ['/foo/bar.', '/.////././//./foo/./././/./bar./././/././'], - ['/foo/bar./', '/.////././//./foo/./././/./bar./././/././', false], - ['/foo/bar./tee./', '/.////././//./foo/./././/./bar./tee././/././', false], - ['/foo/.bar.', '/.////././//./foo/./././/./.bar./././/././'], - ['/foo/.bar./', '/.////././//./foo/./././/./.bar./././././', false], - ['/foo/.bar./tee./', '/.////././//./foo/./././/./.bar./tee././././', false], - - // Windows paths - ['/', ''], - ['/', '\\'], - ['/', '\\', false], - ['/', '\\\\'], - ['/', '\\\\', false], - - ['/path', '\\path'], - ['/path', '\\path', false], - ['/path', '\\path\\'], - ['/path/', '\\path\\', false], - - ['/foo/bar', '\\foo\\\\bar\\'], - ['/foo/bar/', '\\foo\\\\bar\\', false], - ['/foo/bar', '\\foo\\\\\\\\bar'], - ['/foo/bar', '\\foo\\\\\\\\\\bar'], - ['/foo/bar', '\\foo\\bar\\.'], - ['/foo/bar', '\\foo\\bar\\.\\'], - ['/foo/bar/', '\\foo\\bar\\.\\', false], - ['/foo/bar', '\\foo\\bar\\.\\.'], - ['/foo/bar', '\\foo\\bar\\.\\.\\'], - ['/foo/bar/', '\\foo\\bar\\.\\.\\', false], - ['/foo/bar', '\\foo\\.\\bar\\'], - ['/foo/bar/', '\\foo\\.\\bar\\', false], - ['/foo/.bar', '\\foo\\.bar\\'], - ['/foo/.bar/', '\\foo\\.bar\\', false], - ['/foo/.bar/tee', '\\foo\\.bar\\tee'], - - // Absolute windows paths NOT marked as absolute - ['/C:', 'C:\\'], - ['/C:/', 'C:\\', false], - ['/C:/tests', 'C:\\tests'], - ['/C:/tests', 'C:\\tests', false], - ['/C:/tests', 'C:\\tests\\'], - ['/C:/tests/', 'C:\\tests\\', false], - ['/C:/tests/bar', 'C:\\tests\\.\\.\\bar'], - ['/C:/tests/bar/', 'C:\\tests\\.\\.\\bar\\.\\', false], - - // normalize does not resolve '..' (by design) - ['/foo/..', '/foo/../'], - ['/foo/../bar', '/foo/../bar/.'], - ['/foo/..', '\\foo\\..\\'], - ['/foo/../bar', '\\foo\\..\\bar'], - ]; - } - - /** - * @dataProvider normalizePathData - */ - public function testNormalizePath($expected, $path, $stripTrailingSlash = true): void { - $this->assertEquals($expected, \OC\Files\Filesystem::normalizePath($path, $stripTrailingSlash)); - } - - public function normalizePathKeepUnicodeData() { - $nfdName = 'ümlaut'; - $nfcName = 'ümlaut'; - return [ - ['/' . $nfcName, $nfcName, true], - ['/' . $nfcName, $nfcName, false], - ['/' . $nfdName, $nfdName, true], - ['/' . $nfcName, $nfdName, false], - ]; - } - - /** - * @dataProvider normalizePathKeepUnicodeData - */ - public function testNormalizePathKeepUnicode($expected, $path, $keepUnicode = false): void { - $this->assertEquals($expected, \OC\Files\Filesystem::normalizePath($path, true, false, $keepUnicode)); - } - - public function testNormalizePathKeepUnicodeCache(): void { - $nfdName = 'ümlaut'; - $nfcName = 'ümlaut'; - // call in succession due to cache - $this->assertEquals('/' . $nfcName, \OC\Files\Filesystem::normalizePath($nfdName, true, false, false)); - $this->assertEquals('/' . $nfdName, \OC\Files\Filesystem::normalizePath($nfdName, true, false, true)); - } - - public function isValidPathData() { - return [ - ['/', true], - ['/path', true], - ['/foo/bar', true], - ['/foo//bar/', true], - ['/foo////bar', true], - ['/foo//\///bar', true], - ['/foo/bar/.', true], - ['/foo/bar/./', true], - ['/foo/bar/./.', true], - ['/foo/bar/././', true], - ['/foo/bar/././..bar', true], - ['/foo/bar/././..bar/a', true], - ['/foo/bar/././..', false], - ['/foo/bar/././../', false], - ['/foo/bar/.././', false], - ['/foo/bar/../../', false], - ['/foo/bar/../..\\', false], - ['..', false], - ['../', false], - ['../foo/bar', false], - ['..\foo/bar', false], - ]; - } - - /** - * @dataProvider isValidPathData - */ - public function testIsValidPath($path, $expected): void { - $this->assertSame($expected, \OC\Files\Filesystem::isValidPath($path)); - } - - public function isFileBlacklistedData() { - return [ - ['/etc/foo/bar/foo.txt', false], - ['\etc\foo/bar\foo.txt', false], - ['.htaccess', true], - ['.htaccess/', true], - ['.htaccess\\', true], - ['/etc/foo\bar/.htaccess\\', true], - ['/etc/foo\bar/.htaccess/', true], - ['/etc/foo\bar/.htaccess/foo', false], - ['//foo//bar/\.htaccess/', true], - ['\foo\bar\.HTAccess', true], - ]; - } - - /** - * @dataProvider isFileBlacklistedData - */ - public function testIsFileBlacklisted($path, $expected): void { - $this->assertSame($expected, \OC\Files\Filesystem::isFileBlacklisted($path)); - } - - public function testNormalizePathUTF8(): void { - if (!class_exists('Patchwork\PHP\Shim\Normalizer')) { - $this->markTestSkipped('UTF8 normalizer Patchwork was not found'); - } - - $this->assertEquals("/foo/bar\xC3\xBC", \OC\Files\Filesystem::normalizePath("/foo/baru\xCC\x88")); - $this->assertEquals("/foo/bar\xC3\xBC", \OC\Files\Filesystem::normalizePath("\\foo\\baru\xCC\x88")); - } - - public function testHooks(): void { - if (\OC\Files\Filesystem::getView()) { - $user = \OC_User::getUser(); - } else { - $user = self::TEST_FILESYSTEM_USER1; - $backend = new \Test\Util\User\Dummy(); - \OC_User::useBackend($backend); - $backend->createUser($user, $user); - $userObj = \OC::$server->getUserManager()->get($user); - \OC::$server->getUserSession()->setUser($userObj); - \OC\Files\Filesystem::init($user, '/' . $user . '/files'); - } - \OC_Hook::clear('OC_Filesystem'); - \OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook'); - - \OC\Files\Filesystem::mount('OC\Files\Storage\Temporary', [], '/'); - - $rootView = new \OC\Files\View(''); - $rootView->mkdir('/' . $user); - $rootView->mkdir('/' . $user . '/files'); - - // \OC\Files\Filesystem::file_put_contents('/foo', 'foo'); - \OC\Files\Filesystem::mkdir('/bar'); - // \OC\Files\Filesystem::file_put_contents('/bar//foo', 'foo'); - - $tmpFile = \OC::$server->getTempManager()->getTemporaryFile(); - file_put_contents($tmpFile, 'foo'); - $fh = fopen($tmpFile, 'r'); - // \OC\Files\Filesystem::file_put_contents('/bar//foo', $fh); - } - - /** - * Tests that an exception is thrown when passed user does not exist. - * - */ - public function testLocalMountWhenUserDoesNotExist(): void { - $this->expectException(\OC\User\NoUserException::class); - - $userId = $this->getUniqueID('user_'); - - \OC\Files\Filesystem::initMountPoints($userId); - } - - - public function testNullUserThrows(): void { - $this->expectException(\OC\User\NoUserException::class); - - \OC\Files\Filesystem::initMountPoints(null); - } - - public function testNullUserThrowsTwice(): void { - $thrown = 0; - try { - \OC\Files\Filesystem::initMountPoints(null); - } catch (NoUserException $e) { - $thrown++; - } - try { - \OC\Files\Filesystem::initMountPoints(null); - } catch (NoUserException $e) { - $thrown++; - } - $this->assertEquals(2, $thrown); - } - - /** - * Tests that an exception is thrown when passed user does not exist. - */ - public function testLocalMountWhenUserDoesNotExistTwice(): void { - $thrown = 0; - $userId = $this->getUniqueID('user_'); - - try { - \OC\Files\Filesystem::initMountPoints($userId); - } catch (NoUserException $e) { - $thrown++; - } - - try { - \OC\Files\Filesystem::initMountPoints($userId); - } catch (NoUserException $e) { - $thrown++; - } - - $this->assertEquals(2, $thrown); - } - - /** - * Tests that the home storage is used for the user's mount point - */ - public function testHomeMount(): void { - $userId = $this->getUniqueID('user_'); - - \OC::$server->getUserManager()->createUser($userId, $userId); - - \OC\Files\Filesystem::initMountPoints($userId); - - $homeMount = \OC\Files\Filesystem::getStorage('/' . $userId . '/'); - - $this->assertTrue($homeMount->instanceOfStorage('\OCP\Files\IHomeStorage')); - if ($homeMount->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')) { - $this->assertEquals('object::user:' . $userId, $homeMount->getId()); - } elseif ($homeMount->instanceOfStorage('\OC\Files\Storage\Home')) { - $this->assertEquals('home::' . $userId, $homeMount->getId()); - } - - $user = \OC::$server->getUserManager()->get($userId); - if ($user !== null) { - $user->delete(); - } - } - - public function dummyHook($arguments) { - $path = $arguments['path']; - $this->assertEquals($path, \OC\Files\Filesystem::normalizePath($path)); //the path passed to the hook should already be normalized - } - - /** - * Test that the default cache dir is part of the user's home - */ - public function testMountDefaultCacheDir(): void { - $userId = $this->getUniqueID('user_'); - $config = \OC::$server->getConfig(); - $oldCachePath = $config->getSystemValueString('cache_path', ''); - // no cache path configured - $config->setSystemValue('cache_path', ''); - - \OC::$server->getUserManager()->createUser($userId, $userId); - \OC\Files\Filesystem::initMountPoints($userId); - - $this->assertEquals( - '/' . $userId . '/', - \OC\Files\Filesystem::getMountPoint('/' . $userId . '/cache') - ); - [$storage, $internalPath] = \OC\Files\Filesystem::resolvePath('/' . $userId . '/cache'); - $this->assertTrue($storage->instanceOfStorage('\OCP\Files\IHomeStorage')); - $this->assertEquals('cache', $internalPath); - $user = \OC::$server->getUserManager()->get($userId); - if ($user !== null) { - $user->delete(); - } - - $config->setSystemValue('cache_path', $oldCachePath); - } - - /** - * Test that an external cache is mounted into - * the user's home - */ - public function testMountExternalCacheDir(): void { - $userId = $this->getUniqueID('user_'); - - $config = \OC::$server->getConfig(); - $oldCachePath = $config->getSystemValueString('cache_path', ''); - // set cache path to temp dir - $cachePath = \OC::$server->getTempManager()->getTemporaryFolder() . '/extcache'; - $config->setSystemValue('cache_path', $cachePath); - - \OC::$server->getUserManager()->createUser($userId, $userId); - \OC\Files\Filesystem::initMountPoints($userId); - - $this->assertEquals( - '/' . $userId . '/cache/', - \OC\Files\Filesystem::getMountPoint('/' . $userId . '/cache') - ); - [$storage, $internalPath] = \OC\Files\Filesystem::resolvePath('/' . $userId . '/cache'); - $this->assertTrue($storage->instanceOfStorage('\OC\Files\Storage\Local')); - $this->assertEquals('', $internalPath); - $user = \OC::$server->getUserManager()->get($userId); - if ($user !== null) { - $user->delete(); - } - - $config->setSystemValue('cache_path', $oldCachePath); - } - - public function testRegisterMountProviderAfterSetup(): void { - \OC\Files\Filesystem::initMountPoints(self::TEST_FILESYSTEM_USER2); - $this->assertEquals('/', \OC\Files\Filesystem::getMountPoint('/foo/bar')); - $mount = new MountPoint(new Temporary([]), '/foo/bar'); - $mountProvider = new DummyMountProvider([self::TEST_FILESYSTEM_USER2 => [$mount]]); - \OC::$server->getMountProviderCollection()->registerProvider($mountProvider); - $this->assertEquals('/foo/bar/', \OC\Files\Filesystem::getMountPoint('/foo/bar')); - } -} +<?php +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\Files; + +use OC\Files\Mount\MountPoint; +use OC\Files\Storage\Temporary; +use OC\User\NoUserException; +use OCP\Files\Config\IMountProvider; +use OCP\Files\Storage\IStorageFactory; +use OCP\IUser; + +class DummyMountProvider implements IMountProvider { + private $mounts = []; + + /** + * @param array $mounts + */ + public function __construct(array $mounts) { + $this->mounts = $mounts; + } + + /** + * Get the pre-registered mount points + * + * @param IUser $user + * @param IStorageFactory $loader + * @return \OCP\Files\Mount\IMountPoint[] + */ + public function getMountsForUser(IUser $user, IStorageFactory $loader) { + return isset($this->mounts[$user->getUID()]) ? $this->mounts[$user->getUID()] : []; + } +} + +/** + * Class FilesystemTest + * + * @group DB + * + * @package Test\Files + */ +class FilesystemTest extends \Test\TestCase { + public const TEST_FILESYSTEM_USER1 = 'test-filesystem-user1'; + public const TEST_FILESYSTEM_USER2 = 'test-filesystem-user1'; + + /** + * @var array tmpDirs + */ + private $tmpDirs = []; + + /** + * @return array + */ + private function getStorageData() { + $dir = \OC::$server->getTempManager()->getTemporaryFolder(); + $this->tmpDirs[] = $dir; + return ['datadir' => $dir]; + } + + protected function setUp(): void { + parent::setUp(); + $userBackend = new \Test\Util\User\Dummy(); + $userBackend->createUser(self::TEST_FILESYSTEM_USER1, self::TEST_FILESYSTEM_USER1); + $userBackend->createUser(self::TEST_FILESYSTEM_USER2, self::TEST_FILESYSTEM_USER2); + \OC::$server->getUserManager()->registerBackend($userBackend); + $this->loginAsUser(); + } + + protected function tearDown(): void { + foreach ($this->tmpDirs as $dir) { + \OC_Helper::rmdirr($dir); + } + + $this->logout(); + $this->invokePrivate(\OC\Files\Filesystem::class, 'normalizedPathCache', [null]); + parent::tearDown(); + } + + public function testMount(): void { + \OC\Files\Filesystem::mount(\OC\Files\Storage\Local::class, self::getStorageData(), '/'); + $this->assertEquals('/', \OC\Files\Filesystem::getMountPoint('/')); + $this->assertEquals('/', \OC\Files\Filesystem::getMountPoint('/some/folder')); + [, $internalPath] = \OC\Files\Filesystem::resolvePath('/'); + $this->assertEquals('', $internalPath); + [, $internalPath] = \OC\Files\Filesystem::resolvePath('/some/folder'); + $this->assertEquals('some/folder', $internalPath); + + \OC\Files\Filesystem::mount(\OC\Files\Storage\Local::class, self::getStorageData(), '/some'); + $this->assertEquals('/', \OC\Files\Filesystem::getMountPoint('/')); + $this->assertEquals('/some/', \OC\Files\Filesystem::getMountPoint('/some/folder')); + $this->assertEquals('/some/', \OC\Files\Filesystem::getMountPoint('/some/')); + $this->assertEquals('/some/', \OC\Files\Filesystem::getMountPoint('/some')); + [, $internalPath] = \OC\Files\Filesystem::resolvePath('/some/folder'); + $this->assertEquals('folder', $internalPath); + } + + public function normalizePathData() { + return [ + ['/', ''], + ['/', '/'], + ['/', '//'], + ['/', '/', false], + ['/', '//', false], + + ['/path', '/path/'], + ['/path/', '/path/', false], + ['/path', 'path'], + + ['/foo/bar', '/foo//bar/'], + ['/foo/bar/', '/foo//bar/', false], + ['/foo/bar', '/foo////bar'], + ['/foo/bar', '/foo/////bar'], + ['/foo/bar', '/foo/bar/.'], + ['/foo/bar', '/foo/bar/./'], + ['/foo/bar/', '/foo/bar/./', false], + ['/foo/bar', '/foo/bar/./.'], + ['/foo/bar', '/foo/bar/././'], + ['/foo/bar/', '/foo/bar/././', false], + ['/foo/bar', '/foo/./bar/'], + ['/foo/bar/', '/foo/./bar/', false], + ['/foo/.bar', '/foo/.bar/'], + ['/foo/.bar/', '/foo/.bar/', false], + ['/foo/.bar/tee', '/foo/.bar/tee'], + ['/foo/bar.', '/foo/bar./'], + ['/foo/bar./', '/foo/bar./', false], + ['/foo/bar./tee', '/foo/bar./tee'], + ['/foo/.bar.', '/foo/.bar./'], + ['/foo/.bar./', '/foo/.bar./', false], + ['/foo/.bar./tee', '/foo/.bar./tee'], + + ['/foo/bar', '/.////././//./foo/.///././//./bar/././/./.'], + ['/foo/bar/', '/.////././//./foo/.///././//./bar/./././.', false], + ['/foo/bar', '/.////././//./foo/.///././//./bar/././/././'], + ['/foo/bar/', '/.////././//./foo/.///././//./bar/././/././', false], + ['/foo/.bar', '/.////././//./foo/./././/./.bar/././/././'], + ['/foo/.bar/', '/.////././//./foo/./././/./.bar/././/././', false], + ['/foo/.bar/tee./', '/.////././//./foo/./././/./.bar/tee././/././', false], + ['/foo/bar.', '/.////././//./foo/./././/./bar./././/././'], + ['/foo/bar./', '/.////././//./foo/./././/./bar./././/././', false], + ['/foo/bar./tee./', '/.////././//./foo/./././/./bar./tee././/././', false], + ['/foo/.bar.', '/.////././//./foo/./././/./.bar./././/././'], + ['/foo/.bar./', '/.////././//./foo/./././/./.bar./././././', false], + ['/foo/.bar./tee./', '/.////././//./foo/./././/./.bar./tee././././', false], + + // Windows paths + ['/', ''], + ['/', '\\'], + ['/', '\\', false], + ['/', '\\\\'], + ['/', '\\\\', false], + + ['/path', '\\path'], + ['/path', '\\path', false], + ['/path', '\\path\\'], + ['/path/', '\\path\\', false], + + ['/foo/bar', '\\foo\\\\bar\\'], + ['/foo/bar/', '\\foo\\\\bar\\', false], + ['/foo/bar', '\\foo\\\\\\\\bar'], + ['/foo/bar', '\\foo\\\\\\\\\\bar'], + ['/foo/bar', '\\foo\\bar\\.'], + ['/foo/bar', '\\foo\\bar\\.\\'], + ['/foo/bar/', '\\foo\\bar\\.\\', false], + ['/foo/bar', '\\foo\\bar\\.\\.'], + ['/foo/bar', '\\foo\\bar\\.\\.\\'], + ['/foo/bar/', '\\foo\\bar\\.\\.\\', false], + ['/foo/bar', '\\foo\\.\\bar\\'], + ['/foo/bar/', '\\foo\\.\\bar\\', false], + ['/foo/.bar', '\\foo\\.bar\\'], + ['/foo/.bar/', '\\foo\\.bar\\', false], + ['/foo/.bar/tee', '\\foo\\.bar\\tee'], + + // Absolute windows paths NOT marked as absolute + ['/C:', 'C:\\'], + ['/C:/', 'C:\\', false], + ['/C:/tests', 'C:\\tests'], + ['/C:/tests', 'C:\\tests', false], + ['/C:/tests', 'C:\\tests\\'], + ['/C:/tests/', 'C:\\tests\\', false], + ['/C:/tests/bar', 'C:\\tests\\.\\.\\bar'], + ['/C:/tests/bar/', 'C:\\tests\\.\\.\\bar\\.\\', false], + + // normalize does not resolve '..' (by design) + ['/foo/..', '/foo/../'], + ['/foo/../bar', '/foo/../bar/.'], + ['/foo/..', '\\foo\\..\\'], + ['/foo/../bar', '\\foo\\..\\bar'], + ]; + } + + /** + * @dataProvider normalizePathData + */ + public function testNormalizePath($expected, $path, $stripTrailingSlash = true): void { + $this->assertEquals($expected, \OC\Files\Filesystem::normalizePath($path, $stripTrailingSlash)); + } + + public function normalizePathKeepUnicodeData() { + $nfdName = 'ümlaut'; + $nfcName = 'ümlaut'; + return [ + ['/' . $nfcName, $nfcName, true], + ['/' . $nfcName, $nfcName, false], + ['/' . $nfdName, $nfdName, true], + ['/' . $nfcName, $nfdName, false], + ]; + } + + /** + * @dataProvider normalizePathKeepUnicodeData + */ + public function testNormalizePathKeepUnicode($expected, $path, $keepUnicode = false): void { + $this->assertEquals($expected, \OC\Files\Filesystem::normalizePath($path, true, false, $keepUnicode)); + } + + public function testNormalizePathKeepUnicodeCache(): void { + $nfdName = 'ümlaut'; + $nfcName = 'ümlaut'; + // call in succession due to cache + $this->assertEquals('/' . $nfcName, \OC\Files\Filesystem::normalizePath($nfdName, true, false, false)); + $this->assertEquals('/' . $nfdName, \OC\Files\Filesystem::normalizePath($nfdName, true, false, true)); + } + + public function isValidPathData() { + return [ + ['/', true], + ['/path', true], + ['/foo/bar', true], + ['/foo//bar/', true], + ['/foo////bar', true], + ['/foo//\///bar', true], + ['/foo/bar/.', true], + ['/foo/bar/./', true], + ['/foo/bar/./.', true], + ['/foo/bar/././', true], + ['/foo/bar/././..bar', true], + ['/foo/bar/././..bar/a', true], + ['/foo/bar/././..', false], + ['/foo/bar/././../', false], + ['/foo/bar/.././', false], + ['/foo/bar/../../', false], + ['/foo/bar/../..\\', false], + ['..', false], + ['../', false], + ['../foo/bar', false], + ['..\foo/bar', false], + ]; + } + + /** + * @dataProvider isValidPathData + */ + public function testIsValidPath($path, $expected): void { + $this->assertSame($expected, \OC\Files\Filesystem::isValidPath($path)); + } + + public function isFileBlacklistedData() { + return [ + ['/etc/foo/bar/foo.txt', false], + ['\etc\foo/bar\foo.txt', false], + ['.htaccess', true], + ['.htaccess/', true], + ['.htaccess\\', true], + ['/etc/foo\bar/.htaccess\\', true], + ['/etc/foo\bar/.htaccess/', true], + ['/etc/foo\bar/.htaccess/foo', false], + ['//foo//bar/\.htaccess/', true], + ['\foo\bar\.HTAccess', true], + ]; + } + + /** + * @dataProvider isFileBlacklistedData + */ + public function testIsFileBlacklisted($path, $expected): void { + $this->assertSame($expected, \OC\Files\Filesystem::isFileBlacklisted($path)); + } + + public function testNormalizePathUTF8(): void { + if (!class_exists('Patchwork\PHP\Shim\Normalizer')) { + $this->markTestSkipped('UTF8 normalizer Patchwork was not found'); + } + + $this->assertEquals("/foo/bar\xC3\xBC", \OC\Files\Filesystem::normalizePath("/foo/baru\xCC\x88")); + $this->assertEquals("/foo/bar\xC3\xBC", \OC\Files\Filesystem::normalizePath("\\foo\\baru\xCC\x88")); + } + + public function testHooks(): void { + if (\OC\Files\Filesystem::getView()) { + $user = \OC_User::getUser(); + } else { + $user = self::TEST_FILESYSTEM_USER1; + $backend = new \Test\Util\User\Dummy(); + \OC_User::useBackend($backend); + $backend->createUser($user, $user); + $userObj = \OC::$server->getUserManager()->get($user); + \OC::$server->getUserSession()->setUser($userObj); + \OC\Files\Filesystem::init($user, '/' . $user . '/files'); + } + \OC_Hook::clear('OC_Filesystem'); + \OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook'); + + \OC\Files\Filesystem::mount(\OC\Files\Storage\Temporary::class, [], '/'); + + $rootView = new \OC\Files\View(''); + $rootView->mkdir('/' . $user); + $rootView->mkdir('/' . $user . '/files'); + + // \OC\Files\Filesystem::file_put_contents('/foo', 'foo'); + \OC\Files\Filesystem::mkdir('/bar'); + // \OC\Files\Filesystem::file_put_contents('/bar//foo', 'foo'); + + $tmpFile = \OC::$server->getTempManager()->getTemporaryFile(); + file_put_contents($tmpFile, 'foo'); + $fh = fopen($tmpFile, 'r'); + // \OC\Files\Filesystem::file_put_contents('/bar//foo', $fh); + } + + /** + * Tests that an exception is thrown when passed user does not exist. + * + */ + public function testLocalMountWhenUserDoesNotExist(): void { + $this->expectException(\OC\User\NoUserException::class); + + $userId = $this->getUniqueID('user_'); + + \OC\Files\Filesystem::initMountPoints($userId); + } + + + public function testNullUserThrows(): void { + $this->expectException(\OC\User\NoUserException::class); + + \OC\Files\Filesystem::initMountPoints(null); + } + + public function testNullUserThrowsTwice(): void { + $thrown = 0; + try { + \OC\Files\Filesystem::initMountPoints(null); + } catch (NoUserException $e) { + $thrown++; + } + try { + \OC\Files\Filesystem::initMountPoints(null); + } catch (NoUserException $e) { + $thrown++; + } + $this->assertEquals(2, $thrown); + } + + /** + * Tests that an exception is thrown when passed user does not exist. + */ + public function testLocalMountWhenUserDoesNotExistTwice(): void { + $thrown = 0; + $userId = $this->getUniqueID('user_'); + + try { + \OC\Files\Filesystem::initMountPoints($userId); + } catch (NoUserException $e) { + $thrown++; + } + + try { + \OC\Files\Filesystem::initMountPoints($userId); + } catch (NoUserException $e) { + $thrown++; + } + + $this->assertEquals(2, $thrown); + } + + /** + * Tests that the home storage is used for the user's mount point + */ + public function testHomeMount(): void { + $userId = $this->getUniqueID('user_'); + + \OC::$server->getUserManager()->createUser($userId, $userId); + + \OC\Files\Filesystem::initMountPoints($userId); + + $homeMount = \OC\Files\Filesystem::getStorage('/' . $userId . '/'); + + $this->assertTrue($homeMount->instanceOfStorage(\OCP\Files\IHomeStorage::class)); + if ($homeMount->instanceOfStorage(\OC\Files\ObjectStore\HomeObjectStoreStorage::class)) { + $this->assertEquals('object::user:' . $userId, $homeMount->getId()); + } elseif ($homeMount->instanceOfStorage(\OC\Files\Storage\Home::class)) { + $this->assertEquals('home::' . $userId, $homeMount->getId()); + } + + $user = \OC::$server->getUserManager()->get($userId); + if ($user !== null) { + $user->delete(); + } + } + + public function dummyHook($arguments) { + $path = $arguments['path']; + $this->assertEquals($path, \OC\Files\Filesystem::normalizePath($path)); //the path passed to the hook should already be normalized + } + + /** + * Test that the default cache dir is part of the user's home + */ + public function testMountDefaultCacheDir(): void { + $userId = $this->getUniqueID('user_'); + $config = \OC::$server->getConfig(); + $oldCachePath = $config->getSystemValueString('cache_path', ''); + // no cache path configured + $config->setSystemValue('cache_path', ''); + + \OC::$server->getUserManager()->createUser($userId, $userId); + \OC\Files\Filesystem::initMountPoints($userId); + + $this->assertEquals( + '/' . $userId . '/', + \OC\Files\Filesystem::getMountPoint('/' . $userId . '/cache') + ); + [$storage, $internalPath] = \OC\Files\Filesystem::resolvePath('/' . $userId . '/cache'); + $this->assertTrue($storage->instanceOfStorage(\OCP\Files\IHomeStorage::class)); + $this->assertEquals('cache', $internalPath); + $user = \OC::$server->getUserManager()->get($userId); + if ($user !== null) { + $user->delete(); + } + + $config->setSystemValue('cache_path', $oldCachePath); + } + + /** + * Test that an external cache is mounted into + * the user's home + */ + public function testMountExternalCacheDir(): void { + $userId = $this->getUniqueID('user_'); + + $config = \OC::$server->getConfig(); + $oldCachePath = $config->getSystemValueString('cache_path', ''); + // set cache path to temp dir + $cachePath = \OC::$server->getTempManager()->getTemporaryFolder() . '/extcache'; + $config->setSystemValue('cache_path', $cachePath); + + \OC::$server->getUserManager()->createUser($userId, $userId); + \OC\Files\Filesystem::initMountPoints($userId); + + $this->assertEquals( + '/' . $userId . '/cache/', + \OC\Files\Filesystem::getMountPoint('/' . $userId . '/cache') + ); + [$storage, $internalPath] = \OC\Files\Filesystem::resolvePath('/' . $userId . '/cache'); + $this->assertTrue($storage->instanceOfStorage(\OC\Files\Storage\Local::class)); + $this->assertEquals('', $internalPath); + $user = \OC::$server->getUserManager()->get($userId); + if ($user !== null) { + $user->delete(); + } + + $config->setSystemValue('cache_path', $oldCachePath); + } + + public function testRegisterMountProviderAfterSetup(): void { + \OC\Files\Filesystem::initMountPoints(self::TEST_FILESYSTEM_USER2); + $this->assertEquals('/', \OC\Files\Filesystem::getMountPoint('/foo/bar')); + $mount = new MountPoint(new Temporary([]), '/foo/bar'); + $mountProvider = new DummyMountProvider([self::TEST_FILESYSTEM_USER2 => [$mount]]); + \OC::$server->getMountProviderCollection()->registerProvider($mountProvider); + $this->assertEquals('/foo/bar/', \OC\Files\Filesystem::getMountPoint('/foo/bar')); + } +} diff --git a/tests/lib/Files/Mount/MountPointTest.php b/tests/lib/Files/Mount/MountPointTest.php index eda61feb249..cd088979ef8 100644 --- a/tests/lib/Files/Mount/MountPointTest.php +++ b/tests/lib/Files/Mount/MountPointTest.php @@ -27,7 +27,7 @@ class MountPointTest extends \Test\TestCase { $mountPoint = new \OC\Files\Mount\MountPoint( // just use this because a real class is needed - '\Test\Files\Mount\DummyStorage', + \Test\Files\Mount\DummyStorage::class, '/mountpoint', null, $loader @@ -54,7 +54,7 @@ class MountPointTest extends \Test\TestCase { $mountPoint = new \OC\Files\Mount\MountPoint( // just use this because a real class is needed - '\Test\Files\Mount\DummyStorage', + \Test\Files\Mount\DummyStorage::class, '/mountpoint', null, $loader diff --git a/tests/lib/Files/Mount/MountTest.php b/tests/lib/Files/Mount/MountTest.php index 76d70cdd214..8b6cd25aaaa 100644 --- a/tests/lib/Files/Mount/MountTest.php +++ b/tests/lib/Files/Mount/MountTest.php @@ -1,44 +1,44 @@ -<?php -/** - * SPDX-FileCopyrightText: 2020-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -namespace Test\Files\Mount; - -use OC\Files\Storage\StorageFactory; -use OC\Files\Storage\Wrapper\Wrapper; - -class MountTest extends \Test\TestCase { - public function testFromStorageObject(): void { - $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary') - ->disableOriginalConstructor() - ->getMock(); - $mount = new \OC\Files\Mount\MountPoint($storage, '/foo'); - $this->assertInstanceOf('\OC\Files\Storage\Temporary', $mount->getStorage()); - } - - public function testFromStorageClassname(): void { - $mount = new \OC\Files\Mount\MountPoint('\OC\Files\Storage\Temporary', '/foo'); - $this->assertInstanceOf('\OC\Files\Storage\Temporary', $mount->getStorage()); - } - - public function testWrapper(): void { - $test = $this; - $wrapper = function ($mountPoint, $storage) use (&$test) { - $test->assertEquals('/foo/', $mountPoint); - $test->assertInstanceOf('\OC\Files\Storage\Storage', $storage); - return new Wrapper(['storage' => $storage]); - }; - - $loader = new StorageFactory(); - $loader->addStorageWrapper('test_wrapper', $wrapper); - - $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary') - ->disableOriginalConstructor() - ->getMock(); - $mount = new \OC\Files\Mount\MountPoint($storage, '/foo', [], $loader); - $this->assertInstanceOf('\OC\Files\Storage\Wrapper\Wrapper', $mount->getStorage()); - } -} +<?php +/** + * SPDX-FileCopyrightText: 2020-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\Files\Mount; + +use OC\Files\Storage\StorageFactory; +use OC\Files\Storage\Wrapper\Wrapper; + +class MountTest extends \Test\TestCase { + public function testFromStorageObject(): void { + $storage = $this->getMockBuilder(\OC\Files\Storage\Temporary::class) + ->disableOriginalConstructor() + ->getMock(); + $mount = new \OC\Files\Mount\MountPoint($storage, '/foo'); + $this->assertInstanceOf(\OC\Files\Storage\Temporary::class, $mount->getStorage()); + } + + public function testFromStorageClassname(): void { + $mount = new \OC\Files\Mount\MountPoint(\OC\Files\Storage\Temporary::class, '/foo'); + $this->assertInstanceOf(\OC\Files\Storage\Temporary::class, $mount->getStorage()); + } + + public function testWrapper(): void { + $test = $this; + $wrapper = function ($mountPoint, $storage) use (&$test) { + $test->assertEquals('/foo/', $mountPoint); + $test->assertInstanceOf(\OC\Files\Storage\Storage::class, $storage); + return new Wrapper(['storage' => $storage]); + }; + + $loader = new StorageFactory(); + $loader->addStorageWrapper('test_wrapper', $wrapper); + + $storage = $this->getMockBuilder(\OC\Files\Storage\Temporary::class) + ->disableOriginalConstructor() + ->getMock(); + $mount = new \OC\Files\Mount\MountPoint($storage, '/foo', [], $loader); + $this->assertInstanceOf(\OC\Files\Storage\Wrapper\Wrapper::class, $mount->getStorage()); + } +} diff --git a/tests/lib/Files/Mount/ObjectHomeMountProviderTest.php b/tests/lib/Files/Mount/ObjectHomeMountProviderTest.php index f787c168130..de960ee4cbf 100644 --- a/tests/lib/Files/Mount/ObjectHomeMountProviderTest.php +++ b/tests/lib/Files/Mount/ObjectHomeMountProviderTest.php @@ -39,7 +39,7 @@ class ObjectHomeMountProviderTest extends \Test\TestCase { ->method('getSystemValue') ->with($this->equalTo('objectstore'), '') ->willReturn([ - 'class' => 'Test\Files\Mount\FakeObjectStore', + 'class' => \Test\Files\Mount\FakeObjectStore::class, ]); $this->user->expects($this->never())->method($this->anything()); @@ -48,12 +48,12 @@ class ObjectHomeMountProviderTest extends \Test\TestCase { $config = $this->invokePrivate($this->provider, 'getSingleBucketObjectStoreConfig', [$this->user, $this->loader]); $this->assertArrayHasKey('class', $config); - $this->assertEquals($config['class'], 'Test\Files\Mount\FakeObjectStore'); + $this->assertEquals($config['class'], \Test\Files\Mount\FakeObjectStore::class); $this->assertArrayHasKey('arguments', $config); $this->assertArrayHasKey('user', $config['arguments']); $this->assertSame($this->user, $config['arguments']['user']); $this->assertArrayHasKey('objectstore', $config['arguments']); - $this->assertInstanceOf('Test\Files\Mount\FakeObjectStore', $config['arguments']['objectstore']); + $this->assertInstanceOf(\Test\Files\Mount\FakeObjectStore::class, $config['arguments']['objectstore']); } public function testMultiBucket(): void { @@ -61,7 +61,7 @@ class ObjectHomeMountProviderTest extends \Test\TestCase { ->method('getSystemValue') ->with($this->equalTo('objectstore_multibucket'), '') ->willReturn([ - 'class' => 'Test\Files\Mount\FakeObjectStore', + 'class' => \Test\Files\Mount\FakeObjectStore::class, ]); $this->user->method('getUID') @@ -90,12 +90,12 @@ class ObjectHomeMountProviderTest extends \Test\TestCase { $config = $this->invokePrivate($this->provider, 'getMultiBucketObjectStoreConfig', [$this->user, $this->loader]); $this->assertArrayHasKey('class', $config); - $this->assertEquals($config['class'], 'Test\Files\Mount\FakeObjectStore'); + $this->assertEquals($config['class'], \Test\Files\Mount\FakeObjectStore::class); $this->assertArrayHasKey('arguments', $config); $this->assertArrayHasKey('user', $config['arguments']); $this->assertSame($this->user, $config['arguments']['user']); $this->assertArrayHasKey('objectstore', $config['arguments']); - $this->assertInstanceOf('Test\Files\Mount\FakeObjectStore', $config['arguments']['objectstore']); + $this->assertInstanceOf(\Test\Files\Mount\FakeObjectStore::class, $config['arguments']['objectstore']); $this->assertArrayHasKey('bucket', $config['arguments']); $this->assertEquals('49', $config['arguments']['bucket']); } @@ -105,7 +105,7 @@ class ObjectHomeMountProviderTest extends \Test\TestCase { ->method('getSystemValue') ->with('objectstore_multibucket') ->willReturn([ - 'class' => 'Test\Files\Mount\FakeObjectStore', + 'class' => \Test\Files\Mount\FakeObjectStore::class, 'arguments' => [ 'bucket' => 'myBucketPrefix', ], @@ -137,12 +137,12 @@ class ObjectHomeMountProviderTest extends \Test\TestCase { $config = $this->invokePrivate($this->provider, 'getMultiBucketObjectStoreConfig', [$this->user, $this->loader]); $this->assertArrayHasKey('class', $config); - $this->assertEquals($config['class'], 'Test\Files\Mount\FakeObjectStore'); + $this->assertEquals($config['class'], \Test\Files\Mount\FakeObjectStore::class); $this->assertArrayHasKey('arguments', $config); $this->assertArrayHasKey('user', $config['arguments']); $this->assertSame($this->user, $config['arguments']['user']); $this->assertArrayHasKey('objectstore', $config['arguments']); - $this->assertInstanceOf('Test\Files\Mount\FakeObjectStore', $config['arguments']['objectstore']); + $this->assertInstanceOf(\Test\Files\Mount\FakeObjectStore::class, $config['arguments']['objectstore']); $this->assertArrayHasKey('bucket', $config['arguments']); $this->assertEquals('myBucketPrefix49', $config['arguments']['bucket']); } @@ -152,7 +152,7 @@ class ObjectHomeMountProviderTest extends \Test\TestCase { ->method('getSystemValue') ->with('objectstore_multibucket') ->willReturn([ - 'class' => 'Test\Files\Mount\FakeObjectStore', + 'class' => \Test\Files\Mount\FakeObjectStore::class, 'arguments' => [ 'bucket' => 'myBucketPrefix', ], @@ -177,12 +177,12 @@ class ObjectHomeMountProviderTest extends \Test\TestCase { $config = $this->invokePrivate($this->provider, 'getMultiBucketObjectStoreConfig', [$this->user, $this->loader]); $this->assertArrayHasKey('class', $config); - $this->assertEquals($config['class'], 'Test\Files\Mount\FakeObjectStore'); + $this->assertEquals($config['class'], \Test\Files\Mount\FakeObjectStore::class); $this->assertArrayHasKey('arguments', $config); $this->assertArrayHasKey('user', $config['arguments']); $this->assertSame($this->user, $config['arguments']['user']); $this->assertArrayHasKey('objectstore', $config['arguments']); - $this->assertInstanceOf('Test\Files\Mount\FakeObjectStore', $config['arguments']['objectstore']); + $this->assertInstanceOf(\Test\Files\Mount\FakeObjectStore::class, $config['arguments']['objectstore']); $this->assertArrayHasKey('bucket', $config['arguments']); $this->assertEquals('awesomeBucket1', $config['arguments']['bucket']); } @@ -192,7 +192,7 @@ class ObjectHomeMountProviderTest extends \Test\TestCase { ->method('getSystemValue') ->with('objectstore_multibucket') ->willReturn([ - 'class' => 'Test\Files\Mount\FakeObjectStore', + 'class' => \Test\Files\Mount\FakeObjectStore::class, ]); $this->user->method('getUID') @@ -200,7 +200,7 @@ class ObjectHomeMountProviderTest extends \Test\TestCase { $this->loader->expects($this->never())->method($this->anything()); $mount = $this->provider->getHomeMountForUser($this->user, $this->loader); - $this->assertInstanceOf('OC\Files\Mount\MountPoint', $mount); + $this->assertInstanceOf(\OC\Files\Mount\MountPoint::class, $mount); } public function testMultiBucketConfigFirstFallBackSingle(): void { @@ -212,7 +212,7 @@ class ObjectHomeMountProviderTest extends \Test\TestCase { )->willReturnOnConsecutiveCalls( '', [ - 'class' => 'Test\Files\Mount\FakeObjectStore', + 'class' => \Test\Files\Mount\FakeObjectStore::class, ], ); @@ -221,7 +221,7 @@ class ObjectHomeMountProviderTest extends \Test\TestCase { $this->loader->expects($this->never())->method($this->anything()); $mount = $this->provider->getHomeMountForUser($this->user, $this->loader); - $this->assertInstanceOf('OC\Files\Mount\MountPoint', $mount); + $this->assertInstanceOf(\OC\Files\Mount\MountPoint::class, $mount); } public function testNoObjectStore(): void { diff --git a/tests/lib/Files/Mount/RootMountProviderTest.php b/tests/lib/Files/Mount/RootMountProviderTest.php index 2613cfd4b7b..ebf1e56c622 100644 --- a/tests/lib/Files/Mount/RootMountProviderTest.php +++ b/tests/lib/Files/Mount/RootMountProviderTest.php @@ -61,7 +61,7 @@ class RootMountProviderTest extends TestCase { public function testObjectStore(): void { $provider = $this->getProvider([ 'objectstore' => [ - 'class' => "OC\Files\ObjectStore\S3", + 'class' => \OC\Files\ObjectStore\S3::class, 'arguments' => [ 'bucket' => 'nextcloud', 'autocreate' => true, @@ -94,7 +94,7 @@ class RootMountProviderTest extends TestCase { public function testObjectStoreMultiBucket(): void { $provider = $this->getProvider([ 'objectstore_multibucket' => [ - 'class' => "OC\Files\ObjectStore\S3", + 'class' => \OC\Files\ObjectStore\S3::class, 'arguments' => [ 'bucket' => 'nextcloud', 'autocreate' => true, diff --git a/tests/lib/Files/Node/FileTest.php b/tests/lib/Files/Node/FileTest.php index a67c9433663..4e0e147c062 100644 --- a/tests/lib/Files/Node/FileTest.php +++ b/tests/lib/Files/Node/FileTest.php @@ -24,11 +24,11 @@ class FileTest extends NodeTest { } protected function getNodeClass() { - return '\OC\Files\Node\File'; + return \OC\Files\Node\File::class; } protected function getNonExistingNodeClass() { - return '\OC\Files\Node\NonExistingFile'; + return \OC\Files\Node\NonExistingFile::class; } protected function getViewDeleteMethod() { @@ -37,7 +37,7 @@ class FileTest extends NodeTest { public function testGetContent(): void { /** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */ - $root = $this->getMockBuilder('\OC\Files\Node\Root') + $root = $this->getMockBuilder(\OC\Files\Node\Root::class) ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) ->getMock(); @@ -67,7 +67,7 @@ class FileTest extends NodeTest { $this->expectException(\OCP\Files\NotPermittedException::class); /** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */ - $root = $this->getMockBuilder('\OC\Files\Node\Root') + $root = $this->getMockBuilder(\OC\Files\Node\Root::class) ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) ->getMock(); @@ -86,7 +86,7 @@ class FileTest extends NodeTest { public function testPutContent(): void { /** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */ - $root = $this->getMockBuilder('\OC\Files\Node\Root') + $root = $this->getMockBuilder(\OC\Files\Node\Root::class) ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) ->getMock(); @@ -113,7 +113,7 @@ class FileTest extends NodeTest { $this->expectException(\OCP\Files\NotPermittedException::class); /** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */ - $root = $this->getMockBuilder('\OC\Files\Node\Root') + $root = $this->getMockBuilder(\OC\Files\Node\Root::class) ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) ->getMock(); @@ -128,7 +128,7 @@ class FileTest extends NodeTest { public function testGetMimeType(): void { /** @var \OC\Files\Node\Root|\PHPUnit\Framework\MockObject\MockObject $root */ - $root = $this->getMockBuilder('\OC\Files\Node\Root') + $root = $this->getMockBuilder(\OC\Files\Node\Root::class) ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) ->getMock(); diff --git a/tests/lib/Files/Node/FolderTest.php b/tests/lib/Files/Node/FolderTest.php index 2e3b6e369d3..97b3c357cde 100644 --- a/tests/lib/Files/Node/FolderTest.php +++ b/tests/lib/Files/Node/FolderTest.php @@ -51,11 +51,11 @@ class FolderTest extends NodeTest { } protected function getNodeClass() { - return '\OC\Files\Node\Folder'; + return \OC\Files\Node\Folder::class; } protected function getNonExistingNodeClass() { - return '\OC\Files\Node\NonExistingFolder'; + return \OC\Files\Node\NonExistingFolder::class; } protected function getViewDeleteMethod() { @@ -89,8 +89,8 @@ class FolderTest extends NodeTest { $node = new Folder($root, $this->view, '/bar/foo'); $children = $node->getDirectoryListing(); $this->assertEquals(2, count($children)); - $this->assertInstanceOf('\OC\Files\Node\File', $children[0]); - $this->assertInstanceOf('\OC\Files\Node\Folder', $children[1]); + $this->assertInstanceOf(\OC\Files\Node\File::class, $children[0]); + $this->assertInstanceOf(\OC\Files\Node\Folder::class, $children[1]); $this->assertEquals('asd', $children[0]->getName()); $this->assertEquals('qwerty', $children[1]->getName()); $this->assertEquals(2, $children[0]->getId()); diff --git a/tests/lib/Files/Node/IntegrationTest.php b/tests/lib/Files/Node/IntegrationTest.php index c90a6115f2a..32d370c12fc 100644 --- a/tests/lib/Files/Node/IntegrationTest.php +++ b/tests/lib/Files/Node/IntegrationTest.php @@ -93,7 +93,7 @@ class IntegrationTest extends \Test\TestCase { $this->assertCount(2, $this->root->getDirectoryListing()); $this->assertTrue($this->root->nodeExists('/foo.txt')); $id = $file->getId(); - $this->assertInstanceOf('\OC\Files\Node\File', $file); + $this->assertInstanceOf(\OC\Files\Node\File::class, $file); $file->putContent('qwerty'); $this->assertEquals('text/plain', $file->getMimeType()); $this->assertEquals('qwerty', $file->getContent()); @@ -132,7 +132,7 @@ class IntegrationTest extends \Test\TestCase { * @var \OC\Files\Node\File $file */ $file = $folder->get('/bar'); - $this->assertInstanceOf('\OC\Files\Node\File', $file); + $this->assertInstanceOf(\OC\Files\Node\File::class, $file); $this->assertFalse($this->root->nodeExists('/foo/bar')); $this->assertTrue($this->root->nodeExists('/asd/bar')); $this->assertEquals('qwerty', $file->getContent()); @@ -141,7 +141,7 @@ class IntegrationTest extends \Test\TestCase { * @var \OC\Files\Node\File $file */ $file = $folder->get('/bar'); - $this->assertInstanceOf('\OC\Files\Node\File', $file); + $this->assertInstanceOf(\OC\Files\Node\File::class, $file); $this->assertTrue($this->root->nodeExists('/substorage/foo/bar')); $this->assertEquals('qwerty', $file->getContent()); } diff --git a/tests/lib/Files/Node/NodeTest.php b/tests/lib/Files/Node/NodeTest.php index d12448a2481..dd2ddbc2a53 100644 --- a/tests/lib/Files/Node/NodeTest.php +++ b/tests/lib/Files/Node/NodeTest.php @@ -60,7 +60,7 @@ abstract class NodeTest extends \Test\TestCase { $this->view->expects($this->any()) ->method('getRoot') ->willReturn(''); - $this->userMountCache = $this->getMockBuilder('\OCP\Files\Config\IUserMountCache') + $this->userMountCache = $this->getMockBuilder(\OCP\Files\Config\IUserMountCache::class) ->disableOriginalConstructor() ->getMock(); $this->logger = $this->createMock(LoggerInterface::class); @@ -71,7 +71,7 @@ abstract class NodeTest extends \Test\TestCase { ->willReturnCallback(function () { return new ArrayCache(); }); - $this->root = $this->getMockBuilder('\OC\Files\Node\Root') + $this->root = $this->getMockBuilder(\OC\Files\Node\Root::class) ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) ->getMock(); } @@ -336,7 +336,7 @@ abstract class NodeTest extends \Test\TestCase { /** * @var \OC\Files\Storage\Storage | \PHPUnit\Framework\MockObject\MockObject $storage */ - $storage = $this->getMockBuilder('\OC\Files\Storage\Storage') + $storage = $this->getMockBuilder(\OC\Files\Storage\Storage::class) ->disableOriginalConstructor() ->getMock(); @@ -360,7 +360,7 @@ abstract class NodeTest extends \Test\TestCase { /** * @var \OC\Files\Storage\Storage | \PHPUnit\Framework\MockObject\MockObject $storage */ - $storage = $this->getMockBuilder('\OC\Files\Storage\Storage') + $storage = $this->getMockBuilder(\OC\Files\Storage\Storage::class) ->disableOriginalConstructor() ->getMock(); @@ -509,7 +509,7 @@ abstract class NodeTest extends \Test\TestCase { /** * @var \OC\Files\Storage\Storage | \PHPUnit\Framework\MockObject\MockObject $storage */ - $storage = $this->createMock('\OC\Files\Storage\Storage'); + $storage = $this->createMock(\OC\Files\Storage\Storage::class); $this->root->expects($this->never()) ->method('getMount'); @@ -608,7 +608,7 @@ abstract class NodeTest extends \Test\TestCase { */ public function testMoveCopyHooks($operationMethod, $viewMethod, $preHookName, $postHookName): void { /** @var IRootFolder|\PHPUnit\Framework\MockObject\MockObject $root */ - $root = $this->getMockBuilder('\OC\Files\Node\Root') + $root = $this->getMockBuilder(\OC\Files\Node\Root::class) ->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory]) ->setMethods(['get']) ->getMock(); @@ -702,7 +702,7 @@ abstract class NodeTest extends \Test\TestCase { /** * @var \OC\Files\Storage\Storage | \PHPUnit\Framework\MockObject\MockObject $storage */ - $storage = $this->createMock('\OC\Files\Storage\Storage'); + $storage = $this->createMock(\OC\Files\Storage\Storage::class); $storage->expects($this->never()) ->method('rename'); diff --git a/tests/lib/Files/Node/RootTest.php b/tests/lib/Files/Node/RootTest.php index f2ef1a0e3ee..678e882e94e 100644 --- a/tests/lib/Files/Node/RootTest.php +++ b/tests/lib/Files/Node/RootTest.php @@ -47,7 +47,7 @@ class RootTest extends \Test\TestCase { $this->manager = $this->getMockBuilder(Manager::class) ->disableOriginalConstructor() ->getMock(); - $this->userMountCache = $this->getMockBuilder('\OCP\Files\Config\IUserMountCache') + $this->userMountCache = $this->getMockBuilder(\OCP\Files\Config\IUserMountCache::class) ->disableOriginalConstructor() ->getMock(); $this->logger = $this->createMock(LoggerInterface::class); @@ -79,7 +79,7 @@ class RootTest extends \Test\TestCase { /** * @var \OC\Files\Storage\Storage $storage */ - $storage = $this->getMockBuilder('\OC\Files\Storage\Storage') + $storage = $this->getMockBuilder(\OC\Files\Storage\Storage::class) ->disableOriginalConstructor() ->getMock(); $view = $this->getRootViewMock(); @@ -102,7 +102,7 @@ class RootTest extends \Test\TestCase { $root->mount($storage, ''); $node = $root->get('/bar/foo'); $this->assertEquals(10, $node->getId()); - $this->assertInstanceOf('\OC\Files\Node\File', $node); + $this->assertInstanceOf(\OC\Files\Node\File::class, $node); } @@ -112,7 +112,7 @@ class RootTest extends \Test\TestCase { /** * @var \OC\Files\Storage\Storage $storage */ - $storage = $this->getMockBuilder('\OC\Files\Storage\Storage') + $storage = $this->getMockBuilder(\OC\Files\Storage\Storage::class) ->disableOriginalConstructor() ->getMock(); $view = $this->getRootViewMock(); diff --git a/tests/lib/Files/ObjectStore/AzureTest.php b/tests/lib/Files/ObjectStore/AzureTest.php index c82ed988434..f56f7b589e0 100644 --- a/tests/lib/Files/ObjectStore/AzureTest.php +++ b/tests/lib/Files/ObjectStore/AzureTest.php @@ -14,7 +14,7 @@ use OC\Files\ObjectStore\Azure; class AzureTest extends ObjectStoreTest { protected function getInstance() { $config = \OC::$server->getConfig()->getSystemValue('objectstore'); - if (!is_array($config) || $config['class'] !== 'OC\\Files\\ObjectStore\\Azure') { + if (!is_array($config) || $config['class'] !== \OC\Files\ObjectStore\Azure::class) { $this->markTestSkipped('objectstore not configured for azure'); } diff --git a/tests/lib/Files/ObjectStore/SwiftTest.php b/tests/lib/Files/ObjectStore/SwiftTest.php index 8a34d25e57b..01de4da140a 100644 --- a/tests/lib/Files/ObjectStore/SwiftTest.php +++ b/tests/lib/Files/ObjectStore/SwiftTest.php @@ -18,7 +18,7 @@ class SwiftTest extends ObjectStoreTest { */ protected function getInstance() { $config = \OC::$server->getConfig()->getSystemValue('objectstore'); - if (!is_array($config) || $config['class'] !== 'OC\\Files\\ObjectStore\\Swift') { + if (!is_array($config) || $config['class'] !== \OC\Files\ObjectStore\Swift::class) { $this->markTestSkipped('objectstore not configured for swift'); } diff --git a/tests/lib/Files/Storage/HomeTest.php b/tests/lib/Files/Storage/HomeTest.php index b6d0f1aa85a..5026b3087bb 100644 --- a/tests/lib/Files/Storage/HomeTest.php +++ b/tests/lib/Files/Storage/HomeTest.php @@ -1,86 +1,86 @@ -<?php -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -namespace Test\Files\Storage; - -use OC\User\User; - -class DummyUser extends User { - private $home; - - private $uid; - - /** - * @param string $uid - * @param string $home - */ - public function __construct($uid, $home) { - $this->uid = $uid; - $this->home = $home; - } - - public function getHome() { - return $this->home; - } - - public function getUID() { - return $this->uid; - } -} - -/** - * Class Home - * - * @group DB - * - * @package Test\Files\Storage - */ -class HomeTest extends Storage { - /** - * @var string tmpDir - */ - private $tmpDir; - - private $userId; - - /** - * @var \OC\User\User $user - */ - private $user; - - protected function setUp(): void { - parent::setUp(); - - $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder(); - $this->userId = $this->getUniqueID('user_'); - $this->user = new DummyUser($this->userId, $this->tmpDir); - $this->instance = new \OC\Files\Storage\Home(['user' => $this->user]); - } - - protected function tearDown(): void { - \OC_Helper::rmdirr($this->tmpDir); - parent::tearDown(); - } - - /** - * Tests that the home id is in the format home::user1 - */ - public function testId(): void { - $this->assertEquals('home::' . $this->userId, $this->instance->getId()); - } - - /** - * Tests that getCache() returns an instance of HomeCache - */ - public function testGetCacheReturnsHomeCache(): void { - $this->assertInstanceOf('\OC\Files\Cache\HomeCache', $this->instance->getCache()); - } - - public function testGetOwner(): void { - $this->assertEquals($this->userId, $this->instance->getOwner('')); - } -} +<?php +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\Files\Storage; + +use OC\User\User; + +class DummyUser extends User { + private $home; + + private $uid; + + /** + * @param string $uid + * @param string $home + */ + public function __construct($uid, $home) { + $this->uid = $uid; + $this->home = $home; + } + + public function getHome() { + return $this->home; + } + + public function getUID() { + return $this->uid; + } +} + +/** + * Class Home + * + * @group DB + * + * @package Test\Files\Storage + */ +class HomeTest extends Storage { + /** + * @var string tmpDir + */ + private $tmpDir; + + private $userId; + + /** + * @var \OC\User\User $user + */ + private $user; + + protected function setUp(): void { + parent::setUp(); + + $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder(); + $this->userId = $this->getUniqueID('user_'); + $this->user = new DummyUser($this->userId, $this->tmpDir); + $this->instance = new \OC\Files\Storage\Home(['user' => $this->user]); + } + + protected function tearDown(): void { + \OC_Helper::rmdirr($this->tmpDir); + parent::tearDown(); + } + + /** + * Tests that the home id is in the format home::user1 + */ + public function testId(): void { + $this->assertEquals('home::' . $this->userId, $this->instance->getId()); + } + + /** + * Tests that getCache() returns an instance of HomeCache + */ + public function testGetCacheReturnsHomeCache(): void { + $this->assertInstanceOf(\OC\Files\Cache\HomeCache::class, $this->instance->getCache()); + } + + public function testGetOwner(): void { + $this->assertEquals($this->userId, $this->instance->getOwner('')); + } +} diff --git a/tests/lib/Files/Storage/Storage.php b/tests/lib/Files/Storage/Storage.php index 5b0bbf2f95b..18cd34a78cf 100644 --- a/tests/lib/Files/Storage/Storage.php +++ b/tests/lib/Files/Storage/Storage.php @@ -1,667 +1,667 @@ -<?php -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -namespace Test\Files\Storage; - -use OC\Files\Cache\Watcher; -use OCP\Files\Storage\IWriteStreamStorage; - -abstract class Storage extends \Test\TestCase { - /** - * @var \OC\Files\Storage\Storage instance - */ - protected $instance; - protected $waitDelay = 0; - - /** - * Sleep for the number of seconds specified in the - * $waitDelay attribute - */ - protected function wait() { - if ($this->waitDelay > 0) { - sleep($this->waitDelay); - } - } - - /** - * the root folder of the storage should always exist, be readable and be recognized as a directory - */ - public function testRoot(): void { - $this->assertTrue($this->instance->file_exists('/'), 'Root folder does not exist'); - $this->assertTrue($this->instance->isReadable('/'), 'Root folder is not readable'); - $this->assertTrue($this->instance->is_dir('/'), 'Root folder is not a directory'); - $this->assertFalse($this->instance->is_file('/'), 'Root folder is a file'); - $this->assertEquals('dir', $this->instance->filetype('/')); - - //without this, any further testing would be useless, not an actual requirement for filestorage though - $this->assertTrue($this->instance->isUpdatable('/'), 'Root folder is not writable'); - } - - /** - * Check that the test() function works - */ - public function testTestFunction(): void { - $this->assertTrue($this->instance->test()); - } - - /** - * @dataProvider directoryProvider - */ - public function testDirectories($directory): void { - $this->assertFalse($this->instance->file_exists('/' . $directory)); - - $this->assertTrue($this->instance->mkdir('/' . $directory)); - - $this->assertTrue($this->instance->file_exists('/' . $directory)); - $this->assertTrue($this->instance->is_dir('/' . $directory)); - $this->assertFalse($this->instance->is_file('/' . $directory)); - $this->assertEquals('dir', $this->instance->filetype('/' . $directory)); - $this->assertEquals(0, $this->instance->filesize('/' . $directory)); - $this->assertTrue($this->instance->isReadable('/' . $directory)); - $this->assertTrue($this->instance->isUpdatable('/' . $directory)); - - $dh = $this->instance->opendir('/'); - $content = []; - while (($file = readdir($dh)) !== false) { - if ($file != '.' and $file != '..') { - $content[] = $file; - } - } - $this->assertEquals([$directory], $content); - - $content = iterator_to_array($this->instance->getDirectoryContent('/')); - - $this->assertCount(1, $content); - $dirEntry = $content[0]; - unset($dirEntry['scan_permissions']); - unset($dirEntry['etag']); - $this->assertLessThanOrEqual(1, abs($dirEntry['mtime'] - $this->instance->filemtime($directory))); - unset($dirEntry['mtime']); - unset($dirEntry['storage_mtime']); - $this->assertEquals([ - 'name' => $directory, - 'mimetype' => $this->instance->getMimeType($directory), - 'size' => -1, - 'permissions' => $this->instance->getPermissions($directory), - ], $dirEntry); - - $this->assertFalse($this->instance->mkdir('/' . $directory)); //can't create existing folders - $this->assertTrue($this->instance->rmdir('/' . $directory)); - - $this->wait(); - $this->assertFalse($this->instance->file_exists('/' . $directory)); - - $this->assertFalse($this->instance->rmdir('/' . $directory)); //can't remove non existing folders - - $dh = $this->instance->opendir('/'); - $content = []; - while (($file = readdir($dh)) !== false) { - if ($file != '.' and $file != '..') { - $content[] = $file; - } - } - $this->assertEquals([], $content); - } - - public function fileNameProvider() { - return [ - ['file.txt'], - [' file.txt'], - ['folder .txt'], - ['file with space.txt'], - ['spéciäl fäile'], - ['test single\'quote.txt'], - ]; - } - - public function directoryProvider() { - return [ - ['folder'], - [' folder'], - ['folder '], - ['folder with space'], - ['spéciäl földer'], - ['test single\'quote'], - ]; - } - - public function loremFileProvider() { - $root = \OC::$SERVERROOT . '/tests/data/'; - return [ - // small file - [$root . 'lorem.txt'], - // bigger file (> 8 KB which is the standard PHP block size) - [$root . 'lorem-big.txt'] - ]; - } - - /** - * test the various uses of file_get_contents and file_put_contents - * - * @dataProvider loremFileProvider - */ - public function testGetPutContents($sourceFile): void { - $sourceText = file_get_contents($sourceFile); - - //fill a file with string data - $this->instance->file_put_contents('/lorem.txt', $sourceText); - $this->assertFalse($this->instance->is_dir('/lorem.txt')); - $this->assertEquals($sourceText, $this->instance->file_get_contents('/lorem.txt'), 'data returned from file_get_contents is not equal to the source data'); - - //empty the file - $this->instance->file_put_contents('/lorem.txt', ''); - $this->assertEquals('', $this->instance->file_get_contents('/lorem.txt'), 'file not emptied'); - } - - /** - * test various known mimetypes - */ - public function testMimeType(): void { - $this->assertEquals('httpd/unix-directory', $this->instance->getMimeType('/')); - $this->assertEquals(false, $this->instance->getMimeType('/non/existing/file')); - - $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; - $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile, 'r')); - $this->assertEquals('text/plain', $this->instance->getMimeType('/lorem.txt')); - - $pngFile = \OC::$SERVERROOT . '/tests/data/desktopapp.png'; - $this->instance->file_put_contents('/desktopapp.png', file_get_contents($pngFile, 'r')); - $this->assertEquals('image/png', $this->instance->getMimeType('/desktopapp.png')); - - $svgFile = \OC::$SERVERROOT . '/tests/data/desktopapp.svg'; - $this->instance->file_put_contents('/desktopapp.svg', file_get_contents($svgFile, 'r')); - $this->assertEquals('image/svg+xml', $this->instance->getMimeType('/desktopapp.svg')); - } - - - public function copyAndMoveProvider() { - return [ - ['/source.txt', '/target.txt'], - ['/source.txt', '/target with space.txt'], - ['/source with space.txt', '/target.txt'], - ['/source with space.txt', '/target with space.txt'], - ['/source.txt', '/tärgét.txt'], - ['/sòurcē.txt', '/target.txt'], - ['/sòurcē.txt', '/tärgét.txt'], - ['/single \' quote.txt', '/tar\'get.txt'], - ]; - } - - public function initSourceAndTarget($source, $target = null) { - $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; - $this->instance->file_put_contents($source, file_get_contents($textFile)); - if ($target) { - $testContents = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - $this->instance->file_put_contents($target, $testContents); - } - } - - public function assertSameAsLorem($file) { - $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; - $this->assertEquals( - file_get_contents($textFile), - $this->instance->file_get_contents($file), - 'Expected ' . $file . ' to be a copy of ' . $textFile - ); - } - - /** - * @dataProvider copyAndMoveProvider - */ - public function testCopy($source, $target): void { - $this->initSourceAndTarget($source); - - $this->instance->copy($source, $target); - - $this->assertTrue($this->instance->file_exists($target), $target . ' was not created'); - $this->assertSameAsLorem($target); - $this->assertTrue($this->instance->file_exists($source), $source . ' was deleted'); - } - - /** - * @dataProvider copyAndMoveProvider - */ - public function testMove($source, $target): void { - $this->initSourceAndTarget($source); - - $this->instance->rename($source, $target); - - $this->wait(); - $this->assertTrue($this->instance->file_exists($target), $target . ' was not created'); - $this->assertFalse($this->instance->file_exists($source), $source . ' still exists'); - $this->assertSameAsLorem($target); - } - - /** - * @dataProvider copyAndMoveProvider - */ - public function testCopyOverwrite($source, $target): void { - $this->initSourceAndTarget($source, $target); - - $this->instance->copy($source, $target); - - $this->assertTrue($this->instance->file_exists($target), $target . ' was not created'); - $this->assertTrue($this->instance->file_exists($source), $source . ' was deleted'); - $this->assertSameAsLorem($target); - $this->assertSameAsLorem($source); - } - - /** - * @dataProvider copyAndMoveProvider - */ - public function testMoveOverwrite($source, $target): void { - $this->initSourceAndTarget($source, $target); - - $this->instance->rename($source, $target); - - $this->assertTrue($this->instance->file_exists($target), $target . ' was not created'); - $this->assertFalse($this->instance->file_exists($source), $source . ' still exists'); - $this->assertSameAsLorem($target); - } - - public function testLocal(): void { - $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; - $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile)); - $localFile = $this->instance->getLocalFile('/lorem.txt'); - $this->assertTrue(file_exists($localFile)); - $this->assertEquals(file_get_contents($textFile), file_get_contents($localFile)); - - $this->instance->mkdir('/folder'); - $this->instance->file_put_contents('/folder/lorem.txt', file_get_contents($textFile)); - $this->instance->file_put_contents('/folder/bar.txt', 'asd'); - $this->instance->mkdir('/folder/recursive'); - $this->instance->file_put_contents('/folder/recursive/file.txt', 'foo'); - - // test below require to use instance->getLocalFile because the physical storage might be different - $localFile = $this->instance->getLocalFile('/folder/lorem.txt'); - $this->assertTrue(file_exists($localFile)); - $this->assertEquals(file_get_contents($localFile), file_get_contents($textFile)); - - $localFile = $this->instance->getLocalFile('/folder/bar.txt'); - $this->assertTrue(file_exists($localFile)); - $this->assertEquals(file_get_contents($localFile), 'asd'); - - $localFile = $this->instance->getLocalFile('/folder/recursive/file.txt'); - $this->assertTrue(file_exists($localFile)); - $this->assertEquals(file_get_contents($localFile), 'foo'); - } - - public function testStat(): void { - $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; - $ctimeStart = time(); - $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile)); - $this->assertTrue($this->instance->isReadable('/lorem.txt')); - $ctimeEnd = time(); - $mTime = $this->instance->filemtime('/lorem.txt'); - $this->assertTrue($this->instance->hasUpdated('/lorem.txt', $ctimeStart - 5)); - $this->assertTrue($this->instance->hasUpdated('/', $ctimeStart - 5)); - - // check that ($ctimeStart - 5) <= $mTime <= ($ctimeEnd + 1) - $this->assertGreaterThanOrEqual(($ctimeStart - 5), $mTime); - $this->assertLessThanOrEqual(($ctimeEnd + 1), $mTime); - $this->assertEquals(filesize($textFile), $this->instance->filesize('/lorem.txt')); - - $stat = $this->instance->stat('/lorem.txt'); - //only size and mtime are required in the result - $this->assertEquals($stat['size'], $this->instance->filesize('/lorem.txt')); - $this->assertEquals($stat['mtime'], $mTime); - - if ($this->instance->touch('/lorem.txt', 100) !== false) { - $mTime = $this->instance->filemtime('/lorem.txt'); - $this->assertEquals($mTime, 100); - } - - $mtimeStart = time(); - - $this->instance->unlink('/lorem.txt'); - $this->assertTrue($this->instance->hasUpdated('/', $mtimeStart - 5)); - } - - /** - * Test whether checkUpdate properly returns false when there was - * no change. - */ - public function testCheckUpdate(): void { - if ($this->instance instanceof \OC\Files\Storage\Wrapper\Wrapper) { - $this->markTestSkipped('Cannot test update check on wrappers'); - } - $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; - $watcher = $this->instance->getWatcher(); - $watcher->setPolicy(Watcher::CHECK_ALWAYS); - $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile)); - $this->assertTrue($watcher->checkUpdate('/lorem.txt'), 'Update detected'); - $this->assertFalse($watcher->checkUpdate('/lorem.txt'), 'No update'); - } - - public function testUnlink(): void { - $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; - $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile)); - - $this->assertTrue($this->instance->file_exists('/lorem.txt')); - - $this->assertTrue($this->instance->unlink('/lorem.txt')); - $this->wait(); - - $this->assertFalse($this->instance->file_exists('/lorem.txt')); - } - - /** - * @dataProvider fileNameProvider - */ - public function testFOpen($fileName): void { - $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; - - $fh = @$this->instance->fopen($fileName, 'r'); - if ($fh) { - fclose($fh); - } - $this->assertFalse($fh); - $this->assertFalse($this->instance->file_exists($fileName)); - - $fh = $this->instance->fopen($fileName, 'w'); - fwrite($fh, file_get_contents($textFile)); - fclose($fh); - $this->assertTrue($this->instance->file_exists($fileName)); - - $fh = $this->instance->fopen($fileName, 'r'); - $content = stream_get_contents($fh); - $this->assertEquals(file_get_contents($textFile), $content); - } - - public function testTouchCreateFile(): void { - $this->assertFalse($this->instance->file_exists('touch')); - // returns true on success - $this->assertTrue($this->instance->touch('touch')); - $this->assertTrue($this->instance->file_exists('touch')); - } - - public function testRecursiveRmdir(): void { - $this->instance->mkdir('folder'); - $this->instance->mkdir('folder/bar'); - $this->wait(); - $this->instance->file_put_contents('folder/asd.txt', 'foobar'); - $this->instance->file_put_contents('folder/bar/foo.txt', 'asd'); - $this->assertTrue($this->instance->rmdir('folder')); - $this->wait(); - $this->assertFalse($this->instance->file_exists('folder/asd.txt')); - $this->assertFalse($this->instance->file_exists('folder/bar/foo.txt')); - $this->assertFalse($this->instance->file_exists('folder/bar')); - $this->assertFalse($this->instance->file_exists('folder')); - } - - public function testRmdirEmptyFolder(): void { - $this->assertTrue($this->instance->mkdir('empty')); - $this->wait(); - $this->assertTrue($this->instance->rmdir('empty')); - $this->assertFalse($this->instance->file_exists('empty')); - } - - public function testRecursiveUnlink(): void { - $this->instance->mkdir('folder'); - $this->instance->mkdir('folder/bar'); - $this->instance->file_put_contents('folder/asd.txt', 'foobar'); - $this->instance->file_put_contents('folder/bar/foo.txt', 'asd'); - $this->assertTrue($this->instance->unlink('folder')); - $this->wait(); - $this->assertFalse($this->instance->file_exists('folder/asd.txt')); - $this->assertFalse($this->instance->file_exists('folder/bar/foo.txt')); - $this->assertFalse($this->instance->file_exists('folder/bar')); - $this->assertFalse($this->instance->file_exists('folder')); - } - - public function hashProvider() { - return [ - ['Foobar', 'md5'], - ['Foobar', 'sha1'], - ['Foobar', 'sha256'], - ]; - } - - /** - * @dataProvider hashProvider - */ - public function testHash($data, $type): void { - $this->instance->file_put_contents('hash.txt', $data); - $this->assertEquals(hash($type, $data), $this->instance->hash($type, 'hash.txt')); - $this->assertEquals(hash($type, $data, true), $this->instance->hash($type, 'hash.txt', true)); - } - - public function testHashInFileName(): void { - $this->instance->file_put_contents('#test.txt', 'data'); - $this->assertEquals('data', $this->instance->file_get_contents('#test.txt')); - - $this->instance->mkdir('#foo'); - $this->instance->file_put_contents('#foo/test.txt', 'data'); - $this->assertEquals('data', $this->instance->file_get_contents('#foo/test.txt')); - - $dh = $this->instance->opendir('#foo'); - $content = []; - while ($file = readdir($dh)) { - if ($file != '.' and $file != '..') { - $content[] = $file; - } - } - - $this->assertEquals(['test.txt'], $content); - } - - public function testCopyOverWriteFile(): void { - $this->instance->file_put_contents('target.txt', 'foo'); - $this->instance->file_put_contents('source.txt', 'bar'); - $this->instance->copy('source.txt', 'target.txt'); - $this->assertEquals('bar', $this->instance->file_get_contents('target.txt')); - } - - public function testRenameOverWriteFile(): void { - $this->instance->file_put_contents('target.txt', 'foo'); - $this->instance->file_put_contents('source.txt', 'bar'); - $this->instance->rename('source.txt', 'target.txt'); - $this->assertEquals('bar', $this->instance->file_get_contents('target.txt')); - $this->assertFalse($this->instance->file_exists('source.txt')); - } - - public function testRenameDirectory(): void { - $this->instance->mkdir('source'); - $this->instance->file_put_contents('source/test1.txt', 'foo'); - $this->instance->file_put_contents('source/test2.txt', 'qwerty'); - $this->instance->mkdir('source/subfolder'); - $this->instance->file_put_contents('source/subfolder/test.txt', 'bar'); - $this->instance->rename('source', 'target'); - - $this->assertFalse($this->instance->file_exists('source')); - $this->assertFalse($this->instance->file_exists('source/test1.txt')); - $this->assertFalse($this->instance->file_exists('source/test2.txt')); - $this->assertFalse($this->instance->file_exists('source/subfolder')); - $this->assertFalse($this->instance->file_exists('source/subfolder/test.txt')); - - $this->assertTrue($this->instance->file_exists('target')); - $this->assertTrue($this->instance->file_exists('target/test1.txt')); - $this->assertTrue($this->instance->file_exists('target/test2.txt')); - $this->assertTrue($this->instance->file_exists('target/subfolder')); - $this->assertTrue($this->instance->file_exists('target/subfolder/test.txt')); - - $contents = iterator_to_array($this->instance->getDirectoryContent('')); - $this->assertCount(1, $contents); - - $this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); - $this->assertEquals('qwerty', $this->instance->file_get_contents('target/test2.txt')); - $this->assertEquals('bar', $this->instance->file_get_contents('target/subfolder/test.txt')); - } - - public function testRenameOverWriteDirectory(): void { - $this->instance->mkdir('source'); - $this->instance->file_put_contents('source/test1.txt', 'foo'); - - $this->instance->mkdir('target'); - $this->instance->file_put_contents('target/test1.txt', 'bar'); - $this->instance->file_put_contents('target/test2.txt', 'bar'); - - $this->assertTrue($this->instance->rename('source', 'target'), 'rename must return true on success'); - - $this->assertFalse($this->instance->file_exists('source'), 'source has not been removed'); - $this->assertFalse($this->instance->file_exists('source/test1.txt'), 'source/test1.txt has not been removed'); - $this->assertFalse($this->instance->file_exists('target/test2.txt'), 'target/test2.txt has not been removed'); - $this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt'), 'target/test1.txt has not been overwritten'); - } - - public function testRenameOverWriteDirectoryOverFile(): void { - $this->instance->mkdir('source'); - $this->instance->file_put_contents('source/test1.txt', 'foo'); - - $this->instance->file_put_contents('target', 'bar'); - - $this->assertTrue($this->instance->rename('source', 'target'), 'rename must return true on success'); - - $this->assertFalse($this->instance->file_exists('source')); - $this->assertFalse($this->instance->file_exists('source/test1.txt')); - $this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); - } - - public function testCopyDirectory(): void { - $this->instance->mkdir('source'); - $this->instance->file_put_contents('source/test1.txt', 'foo'); - $this->instance->file_put_contents('source/test2.txt', 'qwerty'); - $this->instance->mkdir('source/subfolder'); - $this->instance->file_put_contents('source/subfolder/test.txt', 'bar'); - $this->instance->copy('source', 'target'); - - $this->assertTrue($this->instance->file_exists('source')); - $this->assertTrue($this->instance->file_exists('source/test1.txt')); - $this->assertTrue($this->instance->file_exists('source/test2.txt')); - $this->assertTrue($this->instance->file_exists('source/subfolder')); - $this->assertTrue($this->instance->file_exists('source/subfolder/test.txt')); - - $this->assertTrue($this->instance->file_exists('target')); - $this->assertTrue($this->instance->file_exists('target/test1.txt')); - $this->assertTrue($this->instance->file_exists('target/test2.txt')); - $this->assertTrue($this->instance->file_exists('target/subfolder')); - $this->assertTrue($this->instance->file_exists('target/subfolder/test.txt')); - - $this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); - $this->assertEquals('qwerty', $this->instance->file_get_contents('target/test2.txt')); - $this->assertEquals('bar', $this->instance->file_get_contents('target/subfolder/test.txt')); - } - - public function testCopyOverWriteDirectory(): void { - $this->instance->mkdir('source'); - $this->instance->file_put_contents('source/test1.txt', 'foo'); - - $this->instance->mkdir('target'); - $this->instance->file_put_contents('target/test1.txt', 'bar'); - $this->instance->file_put_contents('target/test2.txt', 'bar'); - - $this->instance->copy('source', 'target'); - - $this->assertFalse($this->instance->file_exists('target/test2.txt')); - $this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); - } - - public function testCopyOverWriteDirectoryOverFile(): void { - $this->instance->mkdir('source'); - $this->instance->file_put_contents('source/test1.txt', 'foo'); - - $this->instance->file_put_contents('target', 'bar'); - - $this->instance->copy('source', 'target'); - - $this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); - } - - public function testInstanceOfStorage(): void { - $this->assertTrue($this->instance->instanceOfStorage('\OCP\Files\Storage')); - $this->assertTrue($this->instance->instanceOfStorage(get_class($this->instance))); - $this->assertFalse($this->instance->instanceOfStorage('\OC')); - } - - /** - * @dataProvider copyAndMoveProvider - */ - public function testCopyFromSameStorage($source, $target): void { - $this->initSourceAndTarget($source); - - $this->instance->copyFromStorage($this->instance, $source, $target); - - $this->assertTrue($this->instance->file_exists($target), $target . ' was not created'); - $this->assertSameAsLorem($target); - $this->assertTrue($this->instance->file_exists($source), $source . ' was deleted'); - } - - public function testIsCreatable(): void { - $this->instance->mkdir('source'); - $this->assertTrue($this->instance->isCreatable('source')); - } - - public function testIsReadable(): void { - $this->instance->mkdir('source'); - $this->assertTrue($this->instance->isReadable('source')); - } - - public function testIsUpdatable(): void { - $this->instance->mkdir('source'); - $this->assertTrue($this->instance->isUpdatable('source')); - } - - public function testIsDeletable(): void { - $this->instance->mkdir('source'); - $this->assertTrue($this->instance->isDeletable('source')); - } - - public function testIsShareable(): void { - $this->instance->mkdir('source'); - $this->assertTrue($this->instance->isSharable('source')); - } - - public function testStatAfterWrite(): void { - $this->instance->file_put_contents('foo.txt', 'bar'); - $stat = $this->instance->stat('foo.txt'); - $this->assertEquals(3, $stat['size']); - - $fh = $this->instance->fopen('foo.txt', 'w'); - fwrite($fh, 'qwerty'); - fclose($fh); - - $stat = $this->instance->stat('foo.txt'); - $this->assertEquals(6, $stat['size']); - } - - public function testPartFile(): void { - $this->instance->file_put_contents('bar.txt.part', 'bar'); - $this->instance->rename('bar.txt.part', 'bar.txt'); - $this->assertEquals('bar', $this->instance->file_get_contents('bar.txt')); - } - - public function testWriteStream(): void { - $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; - - if (!$this->instance->instanceOfStorage(IWriteStreamStorage::class)) { - $this->markTestSkipped('Not a WriteSteamStorage'); - } - /** @var IWriteStreamStorage $storage */ - $storage = $this->instance; - - $source = fopen($textFile, 'r'); - - $storage->writeStream('test.txt', $source); - $this->assertTrue($storage->file_exists('test.txt')); - $this->assertStringEqualsFile($textFile, $storage->file_get_contents('test.txt')); - $this->assertEquals('resource (closed)', gettype($source)); - } - - public function testFseekSize(): void { - $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; - $this->instance->file_put_contents('bar.txt', file_get_contents($textFile)); - - $size = $this->instance->filesize('bar.txt'); - $this->assertEquals(filesize($textFile), $size); - $fh = $this->instance->fopen('bar.txt', 'r'); - - fseek($fh, 0, SEEK_END); - $pos = ftell($fh); - - $this->assertEquals($size, $pos); - } -} +<?php +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\Files\Storage; + +use OC\Files\Cache\Watcher; +use OCP\Files\Storage\IWriteStreamStorage; + +abstract class Storage extends \Test\TestCase { + /** + * @var \OC\Files\Storage\Storage instance + */ + protected $instance; + protected $waitDelay = 0; + + /** + * Sleep for the number of seconds specified in the + * $waitDelay attribute + */ + protected function wait() { + if ($this->waitDelay > 0) { + sleep($this->waitDelay); + } + } + + /** + * the root folder of the storage should always exist, be readable and be recognized as a directory + */ + public function testRoot(): void { + $this->assertTrue($this->instance->file_exists('/'), 'Root folder does not exist'); + $this->assertTrue($this->instance->isReadable('/'), 'Root folder is not readable'); + $this->assertTrue($this->instance->is_dir('/'), 'Root folder is not a directory'); + $this->assertFalse($this->instance->is_file('/'), 'Root folder is a file'); + $this->assertEquals('dir', $this->instance->filetype('/')); + + //without this, any further testing would be useless, not an actual requirement for filestorage though + $this->assertTrue($this->instance->isUpdatable('/'), 'Root folder is not writable'); + } + + /** + * Check that the test() function works + */ + public function testTestFunction(): void { + $this->assertTrue($this->instance->test()); + } + + /** + * @dataProvider directoryProvider + */ + public function testDirectories($directory): void { + $this->assertFalse($this->instance->file_exists('/' . $directory)); + + $this->assertTrue($this->instance->mkdir('/' . $directory)); + + $this->assertTrue($this->instance->file_exists('/' . $directory)); + $this->assertTrue($this->instance->is_dir('/' . $directory)); + $this->assertFalse($this->instance->is_file('/' . $directory)); + $this->assertEquals('dir', $this->instance->filetype('/' . $directory)); + $this->assertEquals(0, $this->instance->filesize('/' . $directory)); + $this->assertTrue($this->instance->isReadable('/' . $directory)); + $this->assertTrue($this->instance->isUpdatable('/' . $directory)); + + $dh = $this->instance->opendir('/'); + $content = []; + while (($file = readdir($dh)) !== false) { + if ($file != '.' and $file != '..') { + $content[] = $file; + } + } + $this->assertEquals([$directory], $content); + + $content = iterator_to_array($this->instance->getDirectoryContent('/')); + + $this->assertCount(1, $content); + $dirEntry = $content[0]; + unset($dirEntry['scan_permissions']); + unset($dirEntry['etag']); + $this->assertLessThanOrEqual(1, abs($dirEntry['mtime'] - $this->instance->filemtime($directory))); + unset($dirEntry['mtime']); + unset($dirEntry['storage_mtime']); + $this->assertEquals([ + 'name' => $directory, + 'mimetype' => $this->instance->getMimeType($directory), + 'size' => -1, + 'permissions' => $this->instance->getPermissions($directory), + ], $dirEntry); + + $this->assertFalse($this->instance->mkdir('/' . $directory)); //can't create existing folders + $this->assertTrue($this->instance->rmdir('/' . $directory)); + + $this->wait(); + $this->assertFalse($this->instance->file_exists('/' . $directory)); + + $this->assertFalse($this->instance->rmdir('/' . $directory)); //can't remove non existing folders + + $dh = $this->instance->opendir('/'); + $content = []; + while (($file = readdir($dh)) !== false) { + if ($file != '.' and $file != '..') { + $content[] = $file; + } + } + $this->assertEquals([], $content); + } + + public function fileNameProvider() { + return [ + ['file.txt'], + [' file.txt'], + ['folder .txt'], + ['file with space.txt'], + ['spéciäl fäile'], + ['test single\'quote.txt'], + ]; + } + + public function directoryProvider() { + return [ + ['folder'], + [' folder'], + ['folder '], + ['folder with space'], + ['spéciäl földer'], + ['test single\'quote'], + ]; + } + + public function loremFileProvider() { + $root = \OC::$SERVERROOT . '/tests/data/'; + return [ + // small file + [$root . 'lorem.txt'], + // bigger file (> 8 KB which is the standard PHP block size) + [$root . 'lorem-big.txt'] + ]; + } + + /** + * test the various uses of file_get_contents and file_put_contents + * + * @dataProvider loremFileProvider + */ + public function testGetPutContents($sourceFile): void { + $sourceText = file_get_contents($sourceFile); + + //fill a file with string data + $this->instance->file_put_contents('/lorem.txt', $sourceText); + $this->assertFalse($this->instance->is_dir('/lorem.txt')); + $this->assertEquals($sourceText, $this->instance->file_get_contents('/lorem.txt'), 'data returned from file_get_contents is not equal to the source data'); + + //empty the file + $this->instance->file_put_contents('/lorem.txt', ''); + $this->assertEquals('', $this->instance->file_get_contents('/lorem.txt'), 'file not emptied'); + } + + /** + * test various known mimetypes + */ + public function testMimeType(): void { + $this->assertEquals('httpd/unix-directory', $this->instance->getMimeType('/')); + $this->assertEquals(false, $this->instance->getMimeType('/non/existing/file')); + + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile, 'r')); + $this->assertEquals('text/plain', $this->instance->getMimeType('/lorem.txt')); + + $pngFile = \OC::$SERVERROOT . '/tests/data/desktopapp.png'; + $this->instance->file_put_contents('/desktopapp.png', file_get_contents($pngFile, 'r')); + $this->assertEquals('image/png', $this->instance->getMimeType('/desktopapp.png')); + + $svgFile = \OC::$SERVERROOT . '/tests/data/desktopapp.svg'; + $this->instance->file_put_contents('/desktopapp.svg', file_get_contents($svgFile, 'r')); + $this->assertEquals('image/svg+xml', $this->instance->getMimeType('/desktopapp.svg')); + } + + + public function copyAndMoveProvider() { + return [ + ['/source.txt', '/target.txt'], + ['/source.txt', '/target with space.txt'], + ['/source with space.txt', '/target.txt'], + ['/source with space.txt', '/target with space.txt'], + ['/source.txt', '/tärgét.txt'], + ['/sòurcē.txt', '/target.txt'], + ['/sòurcē.txt', '/tärgét.txt'], + ['/single \' quote.txt', '/tar\'get.txt'], + ]; + } + + public function initSourceAndTarget($source, $target = null) { + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + $this->instance->file_put_contents($source, file_get_contents($textFile)); + if ($target) { + $testContents = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $this->instance->file_put_contents($target, $testContents); + } + } + + public function assertSameAsLorem($file) { + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + $this->assertEquals( + file_get_contents($textFile), + $this->instance->file_get_contents($file), + 'Expected ' . $file . ' to be a copy of ' . $textFile + ); + } + + /** + * @dataProvider copyAndMoveProvider + */ + public function testCopy($source, $target): void { + $this->initSourceAndTarget($source); + + $this->instance->copy($source, $target); + + $this->assertTrue($this->instance->file_exists($target), $target . ' was not created'); + $this->assertSameAsLorem($target); + $this->assertTrue($this->instance->file_exists($source), $source . ' was deleted'); + } + + /** + * @dataProvider copyAndMoveProvider + */ + public function testMove($source, $target): void { + $this->initSourceAndTarget($source); + + $this->instance->rename($source, $target); + + $this->wait(); + $this->assertTrue($this->instance->file_exists($target), $target . ' was not created'); + $this->assertFalse($this->instance->file_exists($source), $source . ' still exists'); + $this->assertSameAsLorem($target); + } + + /** + * @dataProvider copyAndMoveProvider + */ + public function testCopyOverwrite($source, $target): void { + $this->initSourceAndTarget($source, $target); + + $this->instance->copy($source, $target); + + $this->assertTrue($this->instance->file_exists($target), $target . ' was not created'); + $this->assertTrue($this->instance->file_exists($source), $source . ' was deleted'); + $this->assertSameAsLorem($target); + $this->assertSameAsLorem($source); + } + + /** + * @dataProvider copyAndMoveProvider + */ + public function testMoveOverwrite($source, $target): void { + $this->initSourceAndTarget($source, $target); + + $this->instance->rename($source, $target); + + $this->assertTrue($this->instance->file_exists($target), $target . ' was not created'); + $this->assertFalse($this->instance->file_exists($source), $source . ' still exists'); + $this->assertSameAsLorem($target); + } + + public function testLocal(): void { + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile)); + $localFile = $this->instance->getLocalFile('/lorem.txt'); + $this->assertTrue(file_exists($localFile)); + $this->assertEquals(file_get_contents($textFile), file_get_contents($localFile)); + + $this->instance->mkdir('/folder'); + $this->instance->file_put_contents('/folder/lorem.txt', file_get_contents($textFile)); + $this->instance->file_put_contents('/folder/bar.txt', 'asd'); + $this->instance->mkdir('/folder/recursive'); + $this->instance->file_put_contents('/folder/recursive/file.txt', 'foo'); + + // test below require to use instance->getLocalFile because the physical storage might be different + $localFile = $this->instance->getLocalFile('/folder/lorem.txt'); + $this->assertTrue(file_exists($localFile)); + $this->assertEquals(file_get_contents($localFile), file_get_contents($textFile)); + + $localFile = $this->instance->getLocalFile('/folder/bar.txt'); + $this->assertTrue(file_exists($localFile)); + $this->assertEquals(file_get_contents($localFile), 'asd'); + + $localFile = $this->instance->getLocalFile('/folder/recursive/file.txt'); + $this->assertTrue(file_exists($localFile)); + $this->assertEquals(file_get_contents($localFile), 'foo'); + } + + public function testStat(): void { + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + $ctimeStart = time(); + $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile)); + $this->assertTrue($this->instance->isReadable('/lorem.txt')); + $ctimeEnd = time(); + $mTime = $this->instance->filemtime('/lorem.txt'); + $this->assertTrue($this->instance->hasUpdated('/lorem.txt', $ctimeStart - 5)); + $this->assertTrue($this->instance->hasUpdated('/', $ctimeStart - 5)); + + // check that ($ctimeStart - 5) <= $mTime <= ($ctimeEnd + 1) + $this->assertGreaterThanOrEqual(($ctimeStart - 5), $mTime); + $this->assertLessThanOrEqual(($ctimeEnd + 1), $mTime); + $this->assertEquals(filesize($textFile), $this->instance->filesize('/lorem.txt')); + + $stat = $this->instance->stat('/lorem.txt'); + //only size and mtime are required in the result + $this->assertEquals($stat['size'], $this->instance->filesize('/lorem.txt')); + $this->assertEquals($stat['mtime'], $mTime); + + if ($this->instance->touch('/lorem.txt', 100) !== false) { + $mTime = $this->instance->filemtime('/lorem.txt'); + $this->assertEquals($mTime, 100); + } + + $mtimeStart = time(); + + $this->instance->unlink('/lorem.txt'); + $this->assertTrue($this->instance->hasUpdated('/', $mtimeStart - 5)); + } + + /** + * Test whether checkUpdate properly returns false when there was + * no change. + */ + public function testCheckUpdate(): void { + if ($this->instance instanceof \OC\Files\Storage\Wrapper\Wrapper) { + $this->markTestSkipped('Cannot test update check on wrappers'); + } + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + $watcher = $this->instance->getWatcher(); + $watcher->setPolicy(Watcher::CHECK_ALWAYS); + $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile)); + $this->assertTrue($watcher->checkUpdate('/lorem.txt'), 'Update detected'); + $this->assertFalse($watcher->checkUpdate('/lorem.txt'), 'No update'); + } + + public function testUnlink(): void { + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile)); + + $this->assertTrue($this->instance->file_exists('/lorem.txt')); + + $this->assertTrue($this->instance->unlink('/lorem.txt')); + $this->wait(); + + $this->assertFalse($this->instance->file_exists('/lorem.txt')); + } + + /** + * @dataProvider fileNameProvider + */ + public function testFOpen($fileName): void { + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + + $fh = @$this->instance->fopen($fileName, 'r'); + if ($fh) { + fclose($fh); + } + $this->assertFalse($fh); + $this->assertFalse($this->instance->file_exists($fileName)); + + $fh = $this->instance->fopen($fileName, 'w'); + fwrite($fh, file_get_contents($textFile)); + fclose($fh); + $this->assertTrue($this->instance->file_exists($fileName)); + + $fh = $this->instance->fopen($fileName, 'r'); + $content = stream_get_contents($fh); + $this->assertEquals(file_get_contents($textFile), $content); + } + + public function testTouchCreateFile(): void { + $this->assertFalse($this->instance->file_exists('touch')); + // returns true on success + $this->assertTrue($this->instance->touch('touch')); + $this->assertTrue($this->instance->file_exists('touch')); + } + + public function testRecursiveRmdir(): void { + $this->instance->mkdir('folder'); + $this->instance->mkdir('folder/bar'); + $this->wait(); + $this->instance->file_put_contents('folder/asd.txt', 'foobar'); + $this->instance->file_put_contents('folder/bar/foo.txt', 'asd'); + $this->assertTrue($this->instance->rmdir('folder')); + $this->wait(); + $this->assertFalse($this->instance->file_exists('folder/asd.txt')); + $this->assertFalse($this->instance->file_exists('folder/bar/foo.txt')); + $this->assertFalse($this->instance->file_exists('folder/bar')); + $this->assertFalse($this->instance->file_exists('folder')); + } + + public function testRmdirEmptyFolder(): void { + $this->assertTrue($this->instance->mkdir('empty')); + $this->wait(); + $this->assertTrue($this->instance->rmdir('empty')); + $this->assertFalse($this->instance->file_exists('empty')); + } + + public function testRecursiveUnlink(): void { + $this->instance->mkdir('folder'); + $this->instance->mkdir('folder/bar'); + $this->instance->file_put_contents('folder/asd.txt', 'foobar'); + $this->instance->file_put_contents('folder/bar/foo.txt', 'asd'); + $this->assertTrue($this->instance->unlink('folder')); + $this->wait(); + $this->assertFalse($this->instance->file_exists('folder/asd.txt')); + $this->assertFalse($this->instance->file_exists('folder/bar/foo.txt')); + $this->assertFalse($this->instance->file_exists('folder/bar')); + $this->assertFalse($this->instance->file_exists('folder')); + } + + public function hashProvider() { + return [ + ['Foobar', 'md5'], + ['Foobar', 'sha1'], + ['Foobar', 'sha256'], + ]; + } + + /** + * @dataProvider hashProvider + */ + public function testHash($data, $type): void { + $this->instance->file_put_contents('hash.txt', $data); + $this->assertEquals(hash($type, $data), $this->instance->hash($type, 'hash.txt')); + $this->assertEquals(hash($type, $data, true), $this->instance->hash($type, 'hash.txt', true)); + } + + public function testHashInFileName(): void { + $this->instance->file_put_contents('#test.txt', 'data'); + $this->assertEquals('data', $this->instance->file_get_contents('#test.txt')); + + $this->instance->mkdir('#foo'); + $this->instance->file_put_contents('#foo/test.txt', 'data'); + $this->assertEquals('data', $this->instance->file_get_contents('#foo/test.txt')); + + $dh = $this->instance->opendir('#foo'); + $content = []; + while ($file = readdir($dh)) { + if ($file != '.' and $file != '..') { + $content[] = $file; + } + } + + $this->assertEquals(['test.txt'], $content); + } + + public function testCopyOverWriteFile(): void { + $this->instance->file_put_contents('target.txt', 'foo'); + $this->instance->file_put_contents('source.txt', 'bar'); + $this->instance->copy('source.txt', 'target.txt'); + $this->assertEquals('bar', $this->instance->file_get_contents('target.txt')); + } + + public function testRenameOverWriteFile(): void { + $this->instance->file_put_contents('target.txt', 'foo'); + $this->instance->file_put_contents('source.txt', 'bar'); + $this->instance->rename('source.txt', 'target.txt'); + $this->assertEquals('bar', $this->instance->file_get_contents('target.txt')); + $this->assertFalse($this->instance->file_exists('source.txt')); + } + + public function testRenameDirectory(): void { + $this->instance->mkdir('source'); + $this->instance->file_put_contents('source/test1.txt', 'foo'); + $this->instance->file_put_contents('source/test2.txt', 'qwerty'); + $this->instance->mkdir('source/subfolder'); + $this->instance->file_put_contents('source/subfolder/test.txt', 'bar'); + $this->instance->rename('source', 'target'); + + $this->assertFalse($this->instance->file_exists('source')); + $this->assertFalse($this->instance->file_exists('source/test1.txt')); + $this->assertFalse($this->instance->file_exists('source/test2.txt')); + $this->assertFalse($this->instance->file_exists('source/subfolder')); + $this->assertFalse($this->instance->file_exists('source/subfolder/test.txt')); + + $this->assertTrue($this->instance->file_exists('target')); + $this->assertTrue($this->instance->file_exists('target/test1.txt')); + $this->assertTrue($this->instance->file_exists('target/test2.txt')); + $this->assertTrue($this->instance->file_exists('target/subfolder')); + $this->assertTrue($this->instance->file_exists('target/subfolder/test.txt')); + + $contents = iterator_to_array($this->instance->getDirectoryContent('')); + $this->assertCount(1, $contents); + + $this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); + $this->assertEquals('qwerty', $this->instance->file_get_contents('target/test2.txt')); + $this->assertEquals('bar', $this->instance->file_get_contents('target/subfolder/test.txt')); + } + + public function testRenameOverWriteDirectory(): void { + $this->instance->mkdir('source'); + $this->instance->file_put_contents('source/test1.txt', 'foo'); + + $this->instance->mkdir('target'); + $this->instance->file_put_contents('target/test1.txt', 'bar'); + $this->instance->file_put_contents('target/test2.txt', 'bar'); + + $this->assertTrue($this->instance->rename('source', 'target'), 'rename must return true on success'); + + $this->assertFalse($this->instance->file_exists('source'), 'source has not been removed'); + $this->assertFalse($this->instance->file_exists('source/test1.txt'), 'source/test1.txt has not been removed'); + $this->assertFalse($this->instance->file_exists('target/test2.txt'), 'target/test2.txt has not been removed'); + $this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt'), 'target/test1.txt has not been overwritten'); + } + + public function testRenameOverWriteDirectoryOverFile(): void { + $this->instance->mkdir('source'); + $this->instance->file_put_contents('source/test1.txt', 'foo'); + + $this->instance->file_put_contents('target', 'bar'); + + $this->assertTrue($this->instance->rename('source', 'target'), 'rename must return true on success'); + + $this->assertFalse($this->instance->file_exists('source')); + $this->assertFalse($this->instance->file_exists('source/test1.txt')); + $this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); + } + + public function testCopyDirectory(): void { + $this->instance->mkdir('source'); + $this->instance->file_put_contents('source/test1.txt', 'foo'); + $this->instance->file_put_contents('source/test2.txt', 'qwerty'); + $this->instance->mkdir('source/subfolder'); + $this->instance->file_put_contents('source/subfolder/test.txt', 'bar'); + $this->instance->copy('source', 'target'); + + $this->assertTrue($this->instance->file_exists('source')); + $this->assertTrue($this->instance->file_exists('source/test1.txt')); + $this->assertTrue($this->instance->file_exists('source/test2.txt')); + $this->assertTrue($this->instance->file_exists('source/subfolder')); + $this->assertTrue($this->instance->file_exists('source/subfolder/test.txt')); + + $this->assertTrue($this->instance->file_exists('target')); + $this->assertTrue($this->instance->file_exists('target/test1.txt')); + $this->assertTrue($this->instance->file_exists('target/test2.txt')); + $this->assertTrue($this->instance->file_exists('target/subfolder')); + $this->assertTrue($this->instance->file_exists('target/subfolder/test.txt')); + + $this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); + $this->assertEquals('qwerty', $this->instance->file_get_contents('target/test2.txt')); + $this->assertEquals('bar', $this->instance->file_get_contents('target/subfolder/test.txt')); + } + + public function testCopyOverWriteDirectory(): void { + $this->instance->mkdir('source'); + $this->instance->file_put_contents('source/test1.txt', 'foo'); + + $this->instance->mkdir('target'); + $this->instance->file_put_contents('target/test1.txt', 'bar'); + $this->instance->file_put_contents('target/test2.txt', 'bar'); + + $this->instance->copy('source', 'target'); + + $this->assertFalse($this->instance->file_exists('target/test2.txt')); + $this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); + } + + public function testCopyOverWriteDirectoryOverFile(): void { + $this->instance->mkdir('source'); + $this->instance->file_put_contents('source/test1.txt', 'foo'); + + $this->instance->file_put_contents('target', 'bar'); + + $this->instance->copy('source', 'target'); + + $this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); + } + + public function testInstanceOfStorage(): void { + $this->assertTrue($this->instance->instanceOfStorage(\OCP\Files\Storage::class)); + $this->assertTrue($this->instance->instanceOfStorage(get_class($this->instance))); + $this->assertFalse($this->instance->instanceOfStorage('\OC')); + } + + /** + * @dataProvider copyAndMoveProvider + */ + public function testCopyFromSameStorage($source, $target): void { + $this->initSourceAndTarget($source); + + $this->instance->copyFromStorage($this->instance, $source, $target); + + $this->assertTrue($this->instance->file_exists($target), $target . ' was not created'); + $this->assertSameAsLorem($target); + $this->assertTrue($this->instance->file_exists($source), $source . ' was deleted'); + } + + public function testIsCreatable(): void { + $this->instance->mkdir('source'); + $this->assertTrue($this->instance->isCreatable('source')); + } + + public function testIsReadable(): void { + $this->instance->mkdir('source'); + $this->assertTrue($this->instance->isReadable('source')); + } + + public function testIsUpdatable(): void { + $this->instance->mkdir('source'); + $this->assertTrue($this->instance->isUpdatable('source')); + } + + public function testIsDeletable(): void { + $this->instance->mkdir('source'); + $this->assertTrue($this->instance->isDeletable('source')); + } + + public function testIsShareable(): void { + $this->instance->mkdir('source'); + $this->assertTrue($this->instance->isSharable('source')); + } + + public function testStatAfterWrite(): void { + $this->instance->file_put_contents('foo.txt', 'bar'); + $stat = $this->instance->stat('foo.txt'); + $this->assertEquals(3, $stat['size']); + + $fh = $this->instance->fopen('foo.txt', 'w'); + fwrite($fh, 'qwerty'); + fclose($fh); + + $stat = $this->instance->stat('foo.txt'); + $this->assertEquals(6, $stat['size']); + } + + public function testPartFile(): void { + $this->instance->file_put_contents('bar.txt.part', 'bar'); + $this->instance->rename('bar.txt.part', 'bar.txt'); + $this->assertEquals('bar', $this->instance->file_get_contents('bar.txt')); + } + + public function testWriteStream(): void { + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + + if (!$this->instance->instanceOfStorage(IWriteStreamStorage::class)) { + $this->markTestSkipped('Not a WriteSteamStorage'); + } + /** @var IWriteStreamStorage $storage */ + $storage = $this->instance; + + $source = fopen($textFile, 'r'); + + $storage->writeStream('test.txt', $source); + $this->assertTrue($storage->file_exists('test.txt')); + $this->assertStringEqualsFile($textFile, $storage->file_get_contents('test.txt')); + $this->assertEquals('resource (closed)', gettype($source)); + } + + public function testFseekSize(): void { + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + $this->instance->file_put_contents('bar.txt', file_get_contents($textFile)); + + $size = $this->instance->filesize('bar.txt'); + $this->assertEquals(filesize($textFile), $size); + $fh = $this->instance->fopen('bar.txt', 'r'); + + fseek($fh, 0, SEEK_END); + $pos = ftell($fh); + + $this->assertEquals($size, $pos); + } +} diff --git a/tests/lib/Files/Storage/StorageFactoryTest.php b/tests/lib/Files/Storage/StorageFactoryTest.php index 66f2a2af9a6..2d9e45dfdfc 100644 --- a/tests/lib/Files/Storage/StorageFactoryTest.php +++ b/tests/lib/Files/Storage/StorageFactoryTest.php @@ -27,31 +27,31 @@ class DummyWrapper extends Wrapper { class StorageFactoryTest extends TestCase { public function testSimpleWrapper(): void { $instance = new \OC\Files\Storage\StorageFactory(); - $mount = new MountPoint('\OC\Files\Storage\Temporary', '/foo', [[]], $instance); + $mount = new MountPoint(\OC\Files\Storage\Temporary::class, '/foo', [[]], $instance); $instance->addStorageWrapper('dummy', function ($mountPoint, IStorage $storage, IMountPoint $mount) { - $this->assertInstanceOf('\OC\Files\Storage\Temporary', $storage); + $this->assertInstanceOf(\OC\Files\Storage\Temporary::class, $storage); $this->assertEquals('/foo/', $mount->getMountPoint()); $this->assertEquals('/foo/', $mountPoint); return new DummyWrapper(['storage' => $storage]); }); $wrapped = $mount->getStorage(); - $this->assertInstanceOf('\Test\Files\Storage\DummyWrapper', $wrapped); + $this->assertInstanceOf(\Test\Files\Storage\DummyWrapper::class, $wrapped); } public function testRemoveWrapper(): void { $instance = new \OC\Files\Storage\StorageFactory(); - $mount = new MountPoint('\OC\Files\Storage\Temporary', '/foo', [[]], $instance); + $mount = new MountPoint(\OC\Files\Storage\Temporary::class, '/foo', [[]], $instance); $instance->addStorageWrapper('dummy', function ($mountPoint, IStorage $storage) { return new DummyWrapper(['storage' => $storage]); }); $instance->removeStorageWrapper('dummy'); $wrapped = $mount->getStorage(); - $this->assertInstanceOf('\OC\Files\Storage\Temporary', $wrapped); + $this->assertInstanceOf(\OC\Files\Storage\Temporary::class, $wrapped); } public function testWrapperPriority(): void { $instance = new \OC\Files\Storage\StorageFactory(); - $mount = new MountPoint('\OC\Files\Storage\Temporary', '/foo', [[]], $instance); + $mount = new MountPoint(\OC\Files\Storage\Temporary::class, '/foo', [[]], $instance); $instance->addStorageWrapper('dummy1', function ($mountPoint, IStorage $storage) { return new DummyWrapper(['storage' => $storage, 'data' => 1]); }, 1); @@ -63,7 +63,7 @@ class StorageFactoryTest extends TestCase { }, 50); /** @var \Test\Files\Storage\DummyWrapper $wrapped */ $wrapped = $mount->getStorage(); - $this->assertInstanceOf('\Test\Files\Storage\DummyWrapper', $wrapped); + $this->assertInstanceOf(\Test\Files\Storage\DummyWrapper::class, $wrapped); $this->assertEquals(1, $wrapped->data);// lowest priority is applied last, called first $this->assertEquals(50, $wrapped->getWrapperStorage()->data); $this->assertEquals(100, $wrapped->getWrapperStorage()->getWrapperStorage()->data); diff --git a/tests/lib/Files/Storage/Wrapper/EncryptionTest.php b/tests/lib/Files/Storage/Wrapper/EncryptionTest.php index 2a131a1ea39..3159ded5075 100644 --- a/tests/lib/Files/Storage/Wrapper/EncryptionTest.php +++ b/tests/lib/Files/Storage/Wrapper/EncryptionTest.php @@ -1,1032 +1,1032 @@ -<?php -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-only - */ -namespace Test\Files\Storage\Wrapper; - -use OC\Encryption\Exceptions\ModuleDoesNotExistsException; -use OC\Encryption\Update; -use OC\Encryption\Util; -use OC\Files\Cache\CacheEntry; -use OC\Files\Storage\Temporary; -use OC\Files\Storage\Wrapper\Encryption; -use OC\Files\View; -use OC\Memcache\ArrayCache; -use OC\User\Manager; -use OCP\Encryption\IEncryptionModule; -use OCP\Encryption\IFile; -use OCP\Encryption\Keys\IStorage; -use OCP\EventDispatcher\IEventDispatcher; -use OCP\Files\Cache\ICache; -use OCP\Files\Mount\IMountPoint; -use OCP\ICacheFactory; -use OCP\IConfig; -use Psr\Log\LoggerInterface; -use Test\Files\Storage\Storage; - -class EncryptionTest extends Storage { - /** - * block size will always be 8192 for a PHP stream - * @see https://bugs.php.net/bug.php?id=21641 - * @var integer - */ - protected $headerSize = 8192; - - /** - * @var Temporary - */ - private $sourceStorage; - - /** - * @var \OC\Files\Storage\Wrapper\Encryption | \PHPUnit\Framework\MockObject\MockObject - */ - protected $instance; - - /** - * @var \OC\Encryption\Keys\Storage | \PHPUnit\Framework\MockObject\MockObject - */ - private $keyStore; - - /** - * @var \OC\Encryption\Util | \PHPUnit\Framework\MockObject\MockObject - */ - private $util; - - /** - * @var \OC\Encryption\Manager | \PHPUnit\Framework\MockObject\MockObject - */ - private $encryptionManager; - - /** - * @var \OCP\Encryption\IEncryptionModule | \PHPUnit\Framework\MockObject\MockObject - */ - private $encryptionModule; - - /** - * @var \OC\Encryption\Update | \PHPUnit\Framework\MockObject\MockObject - */ - private $update; - - /** - * @var \OC\Files\Cache\Cache | \PHPUnit\Framework\MockObject\MockObject - */ - private $cache; - - /** - * @var \OC\Log | \PHPUnit\Framework\MockObject\MockObject - */ - private $logger; - - /** - * @var \OC\Encryption\File | \PHPUnit\Framework\MockObject\MockObject - */ - private $file; - - - /** - * @var \OC\Files\Mount\MountPoint | \PHPUnit\Framework\MockObject\MockObject - */ - private $mount; - - /** - * @var \OC\Files\Mount\Manager | \PHPUnit\Framework\MockObject\MockObject - */ - private $mountManager; - - /** - * @var \OC\Group\Manager | \PHPUnit\Framework\MockObject\MockObject - */ - private $groupManager; - - /** - * @var \OCP\IConfig | \PHPUnit\Framework\MockObject\MockObject - */ - private $config; - - /** @var \OC\Memcache\ArrayCache | \PHPUnit\Framework\MockObject\MockObject */ - private $arrayCache; - - - /** @var integer dummy unencrypted size */ - private $dummySize = -1; - - protected function setUp(): void { - parent::setUp(); - - $mockModule = $this->buildMockModule(); - $this->encryptionManager = $this->getMockBuilder('\OC\Encryption\Manager') - ->disableOriginalConstructor() - ->setMethods(['getEncryptionModule', 'isEnabled']) - ->getMock(); - $this->encryptionManager->expects($this->any()) - ->method('getEncryptionModule') - ->willReturn($mockModule); - - $this->arrayCache = $this->createMock(ArrayCache::class); - $this->config = $this->getMockBuilder(IConfig::class) - ->disableOriginalConstructor() - ->getMock(); - $this->groupManager = $this->getMockBuilder('\OC\Group\Manager') - ->disableOriginalConstructor() - ->getMock(); - - $this->util = $this->getMockBuilder('\OC\Encryption\Util') - ->setMethods(['getUidAndFilename', 'isFile', 'isExcluded']) - ->setConstructorArgs([new View(), new Manager( - $this->config, - $this->createMock(ICacheFactory::class), - $this->createMock(IEventDispatcher::class) - ), $this->groupManager, $this->config, $this->arrayCache]) - ->getMock(); - $this->util->expects($this->any()) - ->method('getUidAndFilename') - ->willReturnCallback(function ($path) { - return ['user1', $path]; - }); - - $this->file = $this->getMockBuilder('\OC\Encryption\File') - ->disableOriginalConstructor() - ->setMethods(['getAccessList']) - ->getMock(); - $this->file->expects($this->any())->method('getAccessList')->willReturn([]); - - $this->logger = $this->createMock(LoggerInterface::class); - - $this->sourceStorage = new Temporary([]); - - $this->keyStore = $this->getMockBuilder('\OC\Encryption\Keys\Storage') - ->disableOriginalConstructor()->getMock(); - - $this->update = $this->getMockBuilder('\OC\Encryption\Update') - ->disableOriginalConstructor()->getMock(); - - $this->mount = $this->getMockBuilder('\OC\Files\Mount\MountPoint') - ->disableOriginalConstructor() - ->setMethods(['getOption']) - ->getMock(); - $this->mount->expects($this->any())->method('getOption')->willReturnCallback(function ($option, $default) { - if ($option === 'encrypt' && $default === true) { - global $mockedMountPointEncryptionEnabled; - if ($mockedMountPointEncryptionEnabled !== null) { - return $mockedMountPointEncryptionEnabled; - } - } - return true; - }); - - $this->cache = $this->getMockBuilder('\OC\Files\Cache\Cache') - ->disableOriginalConstructor()->getMock(); - $this->cache->expects($this->any()) - ->method('get') - ->willReturnCallback(function ($path) { - return ['encrypted' => false, 'path' => $path]; - }); - - $this->mountManager = $this->createMock(\OC\Files\Mount\Manager::class); - $this->mountManager->method('findByStorageId') - ->willReturn([]); - - $this->instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption') - ->setConstructorArgs( - [ - [ - 'storage' => $this->sourceStorage, - 'root' => 'foo', - 'mountPoint' => '/', - 'mount' => $this->mount - ], - $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache - ] - ) - ->setMethods(['getMetaData', 'getCache', 'getEncryptionModule']) - ->getMock(); - - $this->instance->expects($this->any()) - ->method('getMetaData') - ->willReturnCallback(function ($path) { - return ['encrypted' => true, 'size' => $this->dummySize, 'path' => $path]; - }); - - $this->instance->expects($this->any()) - ->method('getCache') - ->willReturn($this->cache); - - $this->instance->expects($this->any()) - ->method('getEncryptionModule') - ->willReturn($mockModule); - } - - /** - * @return \PHPUnit\Framework\MockObject\MockObject - */ - protected function buildMockModule() { - $this->encryptionModule = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule') - ->disableOriginalConstructor() - ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll', 'isReadyForUser', 'needDetailedAccessList']) - ->getMock(); - - $this->encryptionModule->expects($this->any())->method('getId')->willReturn('UNIT_TEST_MODULE'); - $this->encryptionModule->expects($this->any())->method('getDisplayName')->willReturn('Unit test module'); - $this->encryptionModule->expects($this->any())->method('begin')->willReturn([]); - $this->encryptionModule->expects($this->any())->method('end')->willReturn(''); - $this->encryptionModule->expects($this->any())->method('encrypt')->willReturnArgument(0); - $this->encryptionModule->expects($this->any())->method('decrypt')->willReturnArgument(0); - $this->encryptionModule->expects($this->any())->method('update')->willReturn(true); - $this->encryptionModule->expects($this->any())->method('shouldEncrypt')->willReturn(true); - $this->encryptionModule->expects($this->any())->method('getUnencryptedBlockSize')->willReturn(8192); - $this->encryptionModule->expects($this->any())->method('isReadable')->willReturn(true); - $this->encryptionModule->expects($this->any())->method('needDetailedAccessList')->willReturn(false); - return $this->encryptionModule; - } - - /** - * @dataProvider dataTestGetMetaData - * - * @param string $path - * @param array $metaData - * @param bool $encrypted - * @param bool $unencryptedSizeSet - * @param int $storedUnencryptedSize - * @param array $expected - */ - public function testGetMetaData($path, $metaData, $encrypted, $unencryptedSizeSet, $storedUnencryptedSize, $expected): void { - $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage') - ->disableOriginalConstructor()->getMock(); - - $cache = $this->getMockBuilder('\OC\Files\Cache\Cache') - ->disableOriginalConstructor()->getMock(); - $cache->expects($this->any()) - ->method('get') - ->willReturnCallback( - function ($path) use ($encrypted) { - return new CacheEntry(['encrypted' => $encrypted, 'path' => $path, 'size' => 0, 'fileid' => 1]); - } - ); - - $this->instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption') - ->setConstructorArgs( - [ - [ - 'storage' => $sourceStorage, - 'root' => 'foo', - 'mountPoint' => '/', - 'mount' => $this->mount - ], - $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache - ] - ) - ->setMethods(['getCache', 'verifyUnencryptedSize']) - ->getMock(); - - if ($unencryptedSizeSet) { - $this->invokePrivate($this->instance, 'unencryptedSize', [[$path => $storedUnencryptedSize]]); - } - - $fileEntry = $this->getMockBuilder('\OC\Files\Cache\Cache') - ->disableOriginalConstructor()->getMock(); - $sourceStorage->expects($this->once())->method('getMetaData')->with($path) - ->willReturn($metaData); - $sourceStorage->expects($this->any()) - ->method('getCache') - ->with($path) - ->willReturn($fileEntry); - if ($metaData !== null) { - $fileEntry->expects($this->any()) - ->method('get') - ->with($metaData['fileid']); - } - - $this->instance->expects($this->any())->method('getCache')->willReturn($cache); - if ($expected !== null) { - $this->instance->expects($this->any())->method('verifyUnencryptedSize') - ->with($path, 0)->willReturn($expected['size']); - } - - $result = $this->instance->getMetaData($path); - if (isset($expected['encrypted'])) { - $this->assertSame($expected['encrypted'], (bool)$result['encrypted']); - - if (isset($expected['encryptedVersion'])) { - $this->assertSame($expected['encryptedVersion'], $result['encryptedVersion']); - } - } - - if ($expected !== null) { - $this->assertSame($expected['size'], $result['size']); - } else { - $this->assertSame(null, $result); - } - } - - public function dataTestGetMetaData() { - return [ - ['/test.txt', ['size' => 42, 'encrypted' => 2, 'encryptedVersion' => 2, 'fileid' => 1], true, true, 12, ['size' => 12, 'encrypted' => true, 'encryptedVersion' => 2]], - ['/test.txt', null, true, true, 12, null], - ['/test.txt', ['size' => 42, 'encrypted' => 0, 'fileid' => 1], false, false, 12, ['size' => 42, 'encrypted' => false]], - ['/test.txt', ['size' => 42, 'encrypted' => false, 'fileid' => 1], true, false, 12, ['size' => 12, 'encrypted' => true]] - ]; - } - - public function testFilesize(): void { - $cache = $this->getMockBuilder('\OC\Files\Cache\Cache') - ->disableOriginalConstructor()->getMock(); - $cache->expects($this->any()) - ->method('get') - ->willReturn(new CacheEntry(['encrypted' => true, 'path' => '/test.txt', 'size' => 0, 'fileid' => 1])); - - $this->instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption') - ->setConstructorArgs( - [ - [ - 'storage' => $this->sourceStorage, - 'root' => 'foo', - 'mountPoint' => '/', - 'mount' => $this->mount - ], - $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache - ] - ) - ->setMethods(['getCache', 'verifyUnencryptedSize']) - ->getMock(); - - $this->instance->expects($this->any())->method('getCache')->willReturn($cache); - $this->instance->expects($this->any())->method('verifyUnencryptedSize') - ->willReturn(42); - - - $this->assertSame(42, - $this->instance->filesize('/test.txt') - ); - } - - /** - * @dataProvider dataTestVerifyUnencryptedSize - * - * @param int $encryptedSize - * @param int $unencryptedSize - * @param bool $failure - * @param int $expected - */ - public function testVerifyUnencryptedSize($encryptedSize, $unencryptedSize, $failure, $expected): void { - $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage') - ->disableOriginalConstructor()->getMock(); - - $this->instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption') - ->setConstructorArgs( - [ - [ - 'storage' => $sourceStorage, - 'root' => 'foo', - 'mountPoint' => '/', - 'mount' => $this->mount - ], - $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache - ] - ) - ->setMethods(['fixUnencryptedSize']) - ->getMock(); - - $sourceStorage->expects($this->once())->method('filesize')->willReturn($encryptedSize); - - $this->instance->expects($this->any())->method('fixUnencryptedSize') - ->with('/test.txt', $encryptedSize, $unencryptedSize) - ->willReturnCallback( - function () use ($failure, $expected) { - if ($failure) { - throw new \Exception(); - } else { - return $expected; - } - } - ); - - $this->assertSame( - $expected, - $this->invokePrivate($this->instance, 'verifyUnencryptedSize', ['/test.txt', $unencryptedSize]) - ); - } - - public function dataTestVerifyUnencryptedSize() { - return [ - [120, 80, false, 80], - [120, 120, false, 80], - [120, -1, false, 80], - [120, -1, true, -1] - ]; - } - - /** - * @dataProvider dataTestCopyAndRename - * - * @param string $source - * @param string $target - * @param $encryptionEnabled - * @param boolean $renameKeysReturn - */ - public function testRename($source, - $target, - $encryptionEnabled, - $renameKeysReturn): void { - if ($encryptionEnabled) { - $this->keyStore - ->expects($this->once()) - ->method('renameKeys') - ->willReturn($renameKeysReturn); - } else { - $this->keyStore - ->expects($this->never())->method('renameKeys'); - } - $this->util->expects($this->any()) - ->method('isFile')->willReturn(true); - $this->encryptionManager->expects($this->once()) - ->method('isEnabled')->willReturn($encryptionEnabled); - - $this->instance->mkdir($source); - $this->instance->mkdir(dirname($target)); - $this->instance->rename($source, $target); - } - - public function testCopyEncryption(): void { - $this->instance->file_put_contents('source.txt', 'bar'); - $this->instance->copy('source.txt', 'target.txt'); - $this->assertSame('bar', $this->instance->file_get_contents('target.txt')); - $targetMeta = $this->instance->getMetaData('target.txt'); - $sourceMeta = $this->instance->getMetaData('source.txt'); - $this->assertSame($sourceMeta['encrypted'], $targetMeta['encrypted']); - $this->assertSame($sourceMeta['size'], $targetMeta['size']); - } - - /** - * data provider for testCopyTesting() and dataTestCopyAndRename() - * - * @return array - */ - public function dataTestCopyAndRename() { - return [ - ['source', 'target', true, false, false], - ['source', 'target', true, true, false], - ['source', '/subFolder/target', true, false, false], - ['source', '/subFolder/target', true, true, true], - ['source', '/subFolder/target', false, true, false], - ]; - } - - public function testIsLocal(): void { - $this->encryptionManager->expects($this->once()) - ->method('isEnabled')->willReturn(true); - $this->assertFalse($this->instance->isLocal()); - } - - /** - * @dataProvider dataTestRmdir - * - * @param string $path - * @param boolean $rmdirResult - * @param boolean $isExcluded - * @param boolean $encryptionEnabled - */ - public function testRmdir($path, $rmdirResult, $isExcluded, $encryptionEnabled): void { - $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage') - ->disableOriginalConstructor()->getMock(); - - $util = $this->getMockBuilder('\OC\Encryption\Util')->disableOriginalConstructor()->getMock(); - - $sourceStorage->expects($this->once())->method('rmdir')->willReturn($rmdirResult); - $util->expects($this->any())->method('isExcluded')-> willReturn($isExcluded); - $this->encryptionManager->expects($this->any())->method('isEnabled')->willReturn($encryptionEnabled); - - $encryptionStorage = new \OC\Files\Storage\Wrapper\Encryption( - [ - 'storage' => $sourceStorage, - 'root' => 'foo', - 'mountPoint' => '/mountPoint', - 'mount' => $this->mount - ], - $this->encryptionManager, $util, $this->logger, $this->file, null, $this->keyStore, $this->update - ); - - - if ($rmdirResult === true && $isExcluded === false && $encryptionEnabled === true) { - $this->keyStore->expects($this->once())->method('deleteAllFileKeys')->with('/mountPoint' . $path); - } else { - $this->keyStore->expects($this->never())->method('deleteAllFileKeys'); - } - - $encryptionStorage->rmdir($path); - } - - public function dataTestRmdir() { - return [ - ['/file.txt', true, true, true], - ['/file.txt', false, true, true], - ['/file.txt', true, false, true], - ['/file.txt', false, false, true], - ['/file.txt', true, true, false], - ['/file.txt', false, true, false], - ['/file.txt', true, false, false], - ['/file.txt', false, false, false], - ]; - } - - /** - * @dataProvider dataTestCopyKeys - * - * @param boolean $excluded - * @param boolean $expected - */ - public function testCopyKeys($excluded, $expected): void { - $this->util->expects($this->once()) - ->method('isExcluded') - ->willReturn($excluded); - - if ($excluded) { - $this->keyStore->expects($this->never())->method('copyKeys'); - } else { - $this->keyStore->expects($this->once())->method('copyKeys')->willReturn(true); - } - - $this->assertSame($expected, - self::invokePrivate($this->instance, 'copyKeys', ['/source', '/target']) - ); - } - - public function dataTestCopyKeys() { - return [ - [true, false], - [false, true], - ]; - } - - /** - * @dataProvider dataTestGetHeader - * - * @param string $path - * @param bool $strippedPathExists - * @param string $strippedPath - */ - public function testGetHeader($path, $strippedPathExists, $strippedPath): void { - $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage') - ->disableOriginalConstructor()->getMock(); - - $util = $this->getMockBuilder('\OC\Encryption\Util') - ->setConstructorArgs( - [ - new View(), - new Manager( - $this->config, - $this->createMock(ICacheFactory::class), - $this->createMock(IEventDispatcher::class) - ), - $this->groupManager, - $this->config, - $this->arrayCache - ] - )->getMock(); - - $cache = $this->getMockBuilder('\OC\Files\Cache\Cache') - ->disableOriginalConstructor()->getMock(); - $cache->expects($this->any()) - ->method('get') - ->willReturnCallback(function ($path) { - return ['encrypted' => true, 'path' => $path]; - }); - - $instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption') - ->setConstructorArgs( - [ - [ - 'storage' => $sourceStorage, - 'root' => 'foo', - 'mountPoint' => '/', - 'mount' => $this->mount - ], - $this->encryptionManager, $util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache - ] - ) - ->setMethods(['getCache', 'readFirstBlock']) - ->getMock(); - - $instance->method('getCache')->willReturn($cache); - - $util->method('parseRawHeader') - ->willReturn([Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']); - - if ($strippedPathExists) { - $instance->method('readFirstBlock') - ->with($strippedPath)->willReturn(''); - } else { - $instance->method('readFirstBlock') - ->with($path)->willReturn(''); - } - - $util->expects($this->once())->method('stripPartialFileExtension') - ->with($path)->willReturn($strippedPath); - $sourceStorage->expects($this->once()) - ->method('is_file') - ->with($strippedPath) - ->willReturn($strippedPathExists); - - $this->invokePrivate($instance, 'getHeader', [$path]); - } - - public function dataTestGetHeader() { - return [ - ['/foo/bar.txt', false, '/foo/bar.txt'], - ['/foo/bar.txt.part', false, '/foo/bar.txt'], - ['/foo/bar.txt.ocTransferId7437493.part', false, '/foo/bar.txt'], - ['/foo/bar.txt.part', true, '/foo/bar.txt'], - ['/foo/bar.txt.ocTransferId7437493.part', true, '/foo/bar.txt'], - ]; - } - - /** - * test if getHeader adds the default module correctly to the header for - * legacy files - * - * @dataProvider dataTestGetHeaderAddLegacyModule - */ - public function testGetHeaderAddLegacyModule($header, $isEncrypted, $exists, $expected): void { - $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage') - ->disableOriginalConstructor()->getMock(); - - $sourceStorage->expects($this->once()) - ->method('is_file') - ->willReturn($exists); - - $util = $this->getMockBuilder('\OC\Encryption\Util') - ->setConstructorArgs([new View(), new Manager( - $this->config, - $this->createMock(ICacheFactory::class), - $this->createMock(IEventDispatcher::class) - ), $this->groupManager, $this->config, $this->arrayCache]) - ->getMock(); - - $cache = $this->getMockBuilder('\OC\Files\Cache\Cache') - ->disableOriginalConstructor()->getMock(); - $cache->expects($this->any()) - ->method('get') - ->willReturnCallback(function ($path) use ($isEncrypted) { - return ['encrypted' => $isEncrypted, 'path' => $path]; - }); - - $instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption') - ->setConstructorArgs( - [ - [ - 'storage' => $sourceStorage, - 'root' => 'foo', - 'mountPoint' => '/', - 'mount' => $this->mount - ], - $this->encryptionManager, $util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache - ] - ) - ->setMethods(['readFirstBlock', 'getCache']) - ->getMock(); - - $instance->method('readFirstBlock')->willReturn(''); - - $util->method(('parseRawHeader'))->willReturn($header); - $instance->method('getCache')->willReturn($cache); - - $result = $this->invokePrivate($instance, 'getHeader', ['test.txt']); - $this->assertSameSize($expected, $result); - foreach ($result as $key => $value) { - $this->assertArrayHasKey($key, $expected); - $this->assertSame($expected[$key], $value); - } - } - - public function dataTestGetHeaderAddLegacyModule() { - return [ - [['cipher' => 'AES-128'], true, true, ['cipher' => 'AES-128', Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']], - [[], true, false, []], - [[], true, true, [Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']], - [[], false, true, []], - ]; - } - - public function dataCopyBetweenStorage() { - return [ - [true, true, true], - [true, false, false], - [false, true, false], - [false, false, false], - ]; - } - - public function testCopyBetweenStorageMinimumEncryptedVersion(): void { - $storage2 = $this->createMock(\OC\Files\Storage\Storage::class); - - $sourceInternalPath = $targetInternalPath = 'file.txt'; - $preserveMtime = $isRename = false; - - $storage2->expects($this->any()) - ->method('fopen') - ->willReturnCallback(function ($path, $mode) { - $temp = \OC::$server->getTempManager(); - return fopen($temp->getTemporaryFile(), $mode); - }); - $storage2->method('getId') - ->willReturn('stroage2'); - $cache = $this->createMock(ICache::class); - $cache->expects($this->once()) - ->method('get') - ->with($sourceInternalPath) - ->willReturn(['encryptedVersion' => 0]); - $storage2->expects($this->once()) - ->method('getCache') - ->willReturn($cache); - $this->encryptionManager->expects($this->any()) - ->method('isEnabled') - ->willReturn(true); - global $mockedMountPointEncryptionEnabled; - $mockedMountPointEncryptionEnabled = true; - - $expectedCachePut = [ - 'encrypted' => true, - ]; - $expectedCachePut['encryptedVersion'] = 1; - - $this->cache->expects($this->once()) - ->method('put') - ->with($sourceInternalPath, $expectedCachePut); - - $this->invokePrivate($this->instance, 'copyBetweenStorage', [$storage2, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename]); - - $this->assertFalse(false); - } - - /** - * @dataProvider dataCopyBetweenStorage - * - * @param bool $encryptionEnabled - * @param bool $mountPointEncryptionEnabled - * @param bool $expectedEncrypted - */ - public function testCopyBetweenStorage($encryptionEnabled, $mountPointEncryptionEnabled, $expectedEncrypted): void { - $storage2 = $this->createMock(\OC\Files\Storage\Storage::class); - - $sourceInternalPath = $targetInternalPath = 'file.txt'; - $preserveMtime = $isRename = false; - - $storage2->expects($this->any()) - ->method('fopen') - ->willReturnCallback(function ($path, $mode) { - $temp = \OC::$server->getTempManager(); - return fopen($temp->getTemporaryFile(), $mode); - }); - $storage2->method('getId') - ->willReturn('stroage2'); - if ($expectedEncrypted) { - $cache = $this->createMock(ICache::class); - $cache->expects($this->once()) - ->method('get') - ->with($sourceInternalPath) - ->willReturn(['encryptedVersion' => 12345]); - $storage2->expects($this->once()) - ->method('getCache') - ->willReturn($cache); - } - $this->encryptionManager->expects($this->any()) - ->method('isEnabled') - ->willReturn($encryptionEnabled); - // FIXME can not overwrite the return after definition - // $this->mount->expects($this->at(0)) - // ->method('getOption') - // ->with('encrypt', true) - // ->willReturn($mountPointEncryptionEnabled); - global $mockedMountPointEncryptionEnabled; - $mockedMountPointEncryptionEnabled = $mountPointEncryptionEnabled; - - $expectedCachePut = [ - 'encrypted' => $expectedEncrypted, - ]; - if ($expectedEncrypted === true) { - $expectedCachePut['encryptedVersion'] = 1; - } - - $this->arrayCache->expects($this->never())->method('set'); - - $this->cache->expects($this->once()) - ->method('put') - ->with($sourceInternalPath, $expectedCachePut); - - $this->invokePrivate($this->instance, 'copyBetweenStorage', [$storage2, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename]); - - $this->assertFalse(false); - } - - /** - * @dataProvider dataTestCopyBetweenStorageVersions - * - * @param string $sourceInternalPath - * @param string $targetInternalPath - * @param bool $copyResult - * @param bool $encrypted - */ - public function testCopyBetweenStorageVersions($sourceInternalPath, $targetInternalPath, $copyResult, $encrypted): void { - $sourceStorage = $this->createMock(\OC\Files\Storage\Storage::class); - - $targetStorage = $this->createMock(\OC\Files\Storage\Storage::class); - - $cache = $this->getMockBuilder('\OC\Files\Cache\Cache') - ->disableOriginalConstructor()->getMock(); - - $mountPoint = '/mountPoint'; - - /** @var \OC\Files\Storage\Wrapper\Encryption |\PHPUnit\Framework\MockObject\MockObject $instance */ - $instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption') - ->setConstructorArgs( - [ - [ - 'storage' => $targetStorage, - 'root' => 'foo', - 'mountPoint' => $mountPoint, - 'mount' => $this->mount - ], - $this->encryptionManager, - $this->util, - $this->logger, - $this->file, - null, - $this->keyStore, - $this->update, - $this->mountManager, - $this->arrayCache - ] - ) - ->setMethods(['updateUnencryptedSize', 'getCache']) - ->getMock(); - - $targetStorage->expects($this->once())->method('copyFromStorage') - ->with($sourceStorage, $sourceInternalPath, $targetInternalPath) - ->willReturn($copyResult); - - $instance->expects($this->any())->method('getCache') - ->willReturn($cache); - - $this->arrayCache->expects($this->once())->method('set') - ->with('encryption_copy_version_' . $sourceInternalPath, true); - - if ($copyResult) { - $cache->expects($this->once())->method('get') - ->with($sourceInternalPath) - ->willReturn(new CacheEntry(['encrypted' => $encrypted, 'size' => 42])); - if ($encrypted) { - $instance->expects($this->once())->method('updateUnencryptedSize') - ->with($mountPoint . $targetInternalPath, 42); - } else { - $instance->expects($this->never())->method('updateUnencryptedSize'); - } - } else { - $instance->expects($this->never())->method('updateUnencryptedSize'); - } - - $result = $this->invokePrivate( - $instance, - 'copyBetweenStorage', - [ - $sourceStorage, - $sourceInternalPath, - $targetInternalPath, - false, - false - ] - ); - - $this->assertSame($copyResult, $result); - } - - public function dataTestCopyBetweenStorageVersions() { - return [ - ['/files/foo.txt', '/files_versions/foo.txt.768743', true, true], - ['/files/foo.txt', '/files_versions/foo.txt.768743', true, false], - ['/files/foo.txt', '/files_versions/foo.txt.768743', false, true], - ['/files/foo.txt', '/files_versions/foo.txt.768743', false, false], - ['/files_versions/foo.txt.6487634', '/files/foo.txt', true, true], - ['/files_versions/foo.txt.6487634', '/files/foo.txt', true, false], - ['/files_versions/foo.txt.6487634', '/files/foo.txt', false, true], - ['/files_versions/foo.txt.6487634', '/files/foo.txt', false, false], - - ]; - } - - /** - * @dataProvider dataTestIsVersion - * @param string $path - * @param bool $expected - */ - public function testIsVersion($path, $expected): void { - $this->assertSame($expected, - $this->invokePrivate($this->instance, 'isVersion', [$path]) - ); - } - - public function dataTestIsVersion() { - return [ - ['files_versions/foo', true], - ['/files_versions/foo', true], - ['//files_versions/foo', true], - ['files/versions/foo', false], - ['files/files_versions/foo', false], - ['files_versions_test/foo', false], - ]; - } - - /** - * @dataProvider dataTestShouldEncrypt - * - * @param bool $encryptMountPoint - * @param mixed $encryptionModule - * @param bool $encryptionModuleShouldEncrypt - * @param bool $expected - */ - public function testShouldEncrypt( - $encryptMountPoint, - $encryptionModule, - $encryptionModuleShouldEncrypt, - $expected - ): void { - $encryptionManager = $this->createMock(\OC\Encryption\Manager::class); - $util = $this->createMock(Util::class); - $fileHelper = $this->createMock(IFile::class); - $uid = null; - $keyStorage = $this->createMock(IStorage::class); - $update = $this->createMock(Update::class); - $mountManager = $this->createMock(\OC\Files\Mount\Manager::class); - $mount = $this->createMock(IMountPoint::class); - $arrayCache = $this->createMock(ArrayCache::class); - $path = '/welcome.txt'; - $fullPath = 'admin/files/welcome.txt'; - $defaultEncryptionModule = $this->createMock(IEncryptionModule::class); - - $wrapper = $this->getMockBuilder(Encryption::class) - ->setConstructorArgs( - [ - ['mountPoint' => '', 'mount' => $mount, 'storage' => ''], - $encryptionManager, - $util, - $this->logger, - $fileHelper, - $uid, - $keyStorage, - $update, - $mountManager, - $arrayCache - ] - ) - ->setMethods(['getFullPath', 'getEncryptionModule']) - ->getMock(); - - if ($encryptionModule === true) { - /** @var IEncryptionModule|\PHPUnit\Framework\MockObject\MockObject $encryptionModule */ - $encryptionModule = $this->createMock(IEncryptionModule::class); - } - - $wrapper->method('getFullPath')->with($path)->willReturn($fullPath); - $wrapper->expects($encryptMountPoint ? $this->once() : $this->never()) - ->method('getEncryptionModule') - ->with($fullPath) - ->willReturnCallback( - function () use ($encryptionModule) { - if ($encryptionModule === false) { - throw new ModuleDoesNotExistsException(); - } - return $encryptionModule; - } - ); - $mount->expects($this->once())->method('getOption')->with('encrypt', true) - ->willReturn($encryptMountPoint); - - if ($encryptionModule !== null && $encryptionModule !== false) { - $encryptionModule - ->method('shouldEncrypt') - ->with($fullPath) - ->willReturn($encryptionModuleShouldEncrypt); - } - - if ($encryptionModule === null) { - $encryptionManager->expects($this->once()) - ->method('getEncryptionModule') - ->willReturn($defaultEncryptionModule); - } - $defaultEncryptionModule->method('shouldEncrypt')->willReturn(true); - - $result = $this->invokePrivate($wrapper, 'shouldEncrypt', [$path]); - - $this->assertSame($expected, $result); - } - - public function dataTestShouldEncrypt() { - return [ - [false, false, false, false], - [true, false, false, false], - [true, true, false, false], - [true, true, true, true], - [true, null, false, true], - ]; - } -} +<?php +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace Test\Files\Storage\Wrapper; + +use OC\Encryption\Exceptions\ModuleDoesNotExistsException; +use OC\Encryption\Update; +use OC\Encryption\Util; +use OC\Files\Cache\CacheEntry; +use OC\Files\Storage\Temporary; +use OC\Files\Storage\Wrapper\Encryption; +use OC\Files\View; +use OC\Memcache\ArrayCache; +use OC\User\Manager; +use OCP\Encryption\IEncryptionModule; +use OCP\Encryption\IFile; +use OCP\Encryption\Keys\IStorage; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Cache\ICache; +use OCP\Files\Mount\IMountPoint; +use OCP\ICacheFactory; +use OCP\IConfig; +use Psr\Log\LoggerInterface; +use Test\Files\Storage\Storage; + +class EncryptionTest extends Storage { + /** + * block size will always be 8192 for a PHP stream + * @see https://bugs.php.net/bug.php?id=21641 + * @var integer + */ + protected $headerSize = 8192; + + /** + * @var Temporary + */ + private $sourceStorage; + + /** + * @var \OC\Files\Storage\Wrapper\Encryption | \PHPUnit\Framework\MockObject\MockObject + */ + protected $instance; + + /** + * @var \OC\Encryption\Keys\Storage | \PHPUnit\Framework\MockObject\MockObject + */ + private $keyStore; + + /** + * @var \OC\Encryption\Util | \PHPUnit\Framework\MockObject\MockObject + */ + private $util; + + /** + * @var \OC\Encryption\Manager | \PHPUnit\Framework\MockObject\MockObject + */ + private $encryptionManager; + + /** + * @var \OCP\Encryption\IEncryptionModule | \PHPUnit\Framework\MockObject\MockObject + */ + private $encryptionModule; + + /** + * @var \OC\Encryption\Update | \PHPUnit\Framework\MockObject\MockObject + */ + private $update; + + /** + * @var \OC\Files\Cache\Cache | \PHPUnit\Framework\MockObject\MockObject + */ + private $cache; + + /** + * @var \OC\Log | \PHPUnit\Framework\MockObject\MockObject + */ + private $logger; + + /** + * @var \OC\Encryption\File | \PHPUnit\Framework\MockObject\MockObject + */ + private $file; + + + /** + * @var \OC\Files\Mount\MountPoint | \PHPUnit\Framework\MockObject\MockObject + */ + private $mount; + + /** + * @var \OC\Files\Mount\Manager | \PHPUnit\Framework\MockObject\MockObject + */ + private $mountManager; + + /** + * @var \OC\Group\Manager | \PHPUnit\Framework\MockObject\MockObject + */ + private $groupManager; + + /** + * @var \OCP\IConfig | \PHPUnit\Framework\MockObject\MockObject + */ + private $config; + + /** @var \OC\Memcache\ArrayCache | \PHPUnit\Framework\MockObject\MockObject */ + private $arrayCache; + + + /** @var integer dummy unencrypted size */ + private $dummySize = -1; + + protected function setUp(): void { + parent::setUp(); + + $mockModule = $this->buildMockModule(); + $this->encryptionManager = $this->getMockBuilder(\OC\Encryption\Manager::class) + ->disableOriginalConstructor() + ->setMethods(['getEncryptionModule', 'isEnabled']) + ->getMock(); + $this->encryptionManager->expects($this->any()) + ->method('getEncryptionModule') + ->willReturn($mockModule); + + $this->arrayCache = $this->createMock(ArrayCache::class); + $this->config = $this->getMockBuilder(IConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $this->groupManager = $this->getMockBuilder(\OC\Group\Manager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->util = $this->getMockBuilder(\OC\Encryption\Util::class) + ->setMethods(['getUidAndFilename', 'isFile', 'isExcluded']) + ->setConstructorArgs([new View(), new Manager( + $this->config, + $this->createMock(ICacheFactory::class), + $this->createMock(IEventDispatcher::class) + ), $this->groupManager, $this->config, $this->arrayCache]) + ->getMock(); + $this->util->expects($this->any()) + ->method('getUidAndFilename') + ->willReturnCallback(function ($path) { + return ['user1', $path]; + }); + + $this->file = $this->getMockBuilder(\OC\Encryption\File::class) + ->disableOriginalConstructor() + ->setMethods(['getAccessList']) + ->getMock(); + $this->file->expects($this->any())->method('getAccessList')->willReturn([]); + + $this->logger = $this->createMock(LoggerInterface::class); + + $this->sourceStorage = new Temporary([]); + + $this->keyStore = $this->getMockBuilder(\OC\Encryption\Keys\Storage::class) + ->disableOriginalConstructor()->getMock(); + + $this->update = $this->getMockBuilder(\OC\Encryption\Update::class) + ->disableOriginalConstructor()->getMock(); + + $this->mount = $this->getMockBuilder(\OC\Files\Mount\MountPoint::class) + ->disableOriginalConstructor() + ->setMethods(['getOption']) + ->getMock(); + $this->mount->expects($this->any())->method('getOption')->willReturnCallback(function ($option, $default) { + if ($option === 'encrypt' && $default === true) { + global $mockedMountPointEncryptionEnabled; + if ($mockedMountPointEncryptionEnabled !== null) { + return $mockedMountPointEncryptionEnabled; + } + } + return true; + }); + + $this->cache = $this->getMockBuilder(\OC\Files\Cache\Cache::class) + ->disableOriginalConstructor()->getMock(); + $this->cache->expects($this->any()) + ->method('get') + ->willReturnCallback(function ($path) { + return ['encrypted' => false, 'path' => $path]; + }); + + $this->mountManager = $this->createMock(\OC\Files\Mount\Manager::class); + $this->mountManager->method('findByStorageId') + ->willReturn([]); + + $this->instance = $this->getMockBuilder(\OC\Files\Storage\Wrapper\Encryption::class) + ->setConstructorArgs( + [ + [ + 'storage' => $this->sourceStorage, + 'root' => 'foo', + 'mountPoint' => '/', + 'mount' => $this->mount + ], + $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache + ] + ) + ->setMethods(['getMetaData', 'getCache', 'getEncryptionModule']) + ->getMock(); + + $this->instance->expects($this->any()) + ->method('getMetaData') + ->willReturnCallback(function ($path) { + return ['encrypted' => true, 'size' => $this->dummySize, 'path' => $path]; + }); + + $this->instance->expects($this->any()) + ->method('getCache') + ->willReturn($this->cache); + + $this->instance->expects($this->any()) + ->method('getEncryptionModule') + ->willReturn($mockModule); + } + + /** + * @return \PHPUnit\Framework\MockObject\MockObject + */ + protected function buildMockModule() { + $this->encryptionModule = $this->getMockBuilder(\OCP\Encryption\IEncryptionModule::class) + ->disableOriginalConstructor() + ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll', 'isReadyForUser', 'needDetailedAccessList']) + ->getMock(); + + $this->encryptionModule->expects($this->any())->method('getId')->willReturn('UNIT_TEST_MODULE'); + $this->encryptionModule->expects($this->any())->method('getDisplayName')->willReturn('Unit test module'); + $this->encryptionModule->expects($this->any())->method('begin')->willReturn([]); + $this->encryptionModule->expects($this->any())->method('end')->willReturn(''); + $this->encryptionModule->expects($this->any())->method('encrypt')->willReturnArgument(0); + $this->encryptionModule->expects($this->any())->method('decrypt')->willReturnArgument(0); + $this->encryptionModule->expects($this->any())->method('update')->willReturn(true); + $this->encryptionModule->expects($this->any())->method('shouldEncrypt')->willReturn(true); + $this->encryptionModule->expects($this->any())->method('getUnencryptedBlockSize')->willReturn(8192); + $this->encryptionModule->expects($this->any())->method('isReadable')->willReturn(true); + $this->encryptionModule->expects($this->any())->method('needDetailedAccessList')->willReturn(false); + return $this->encryptionModule; + } + + /** + * @dataProvider dataTestGetMetaData + * + * @param string $path + * @param array $metaData + * @param bool $encrypted + * @param bool $unencryptedSizeSet + * @param int $storedUnencryptedSize + * @param array $expected + */ + public function testGetMetaData($path, $metaData, $encrypted, $unencryptedSizeSet, $storedUnencryptedSize, $expected): void { + $sourceStorage = $this->getMockBuilder(\OC\Files\Storage\Storage::class) + ->disableOriginalConstructor()->getMock(); + + $cache = $this->getMockBuilder(\OC\Files\Cache\Cache::class) + ->disableOriginalConstructor()->getMock(); + $cache->expects($this->any()) + ->method('get') + ->willReturnCallback( + function ($path) use ($encrypted) { + return new CacheEntry(['encrypted' => $encrypted, 'path' => $path, 'size' => 0, 'fileid' => 1]); + } + ); + + $this->instance = $this->getMockBuilder(\OC\Files\Storage\Wrapper\Encryption::class) + ->setConstructorArgs( + [ + [ + 'storage' => $sourceStorage, + 'root' => 'foo', + 'mountPoint' => '/', + 'mount' => $this->mount + ], + $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache + ] + ) + ->setMethods(['getCache', 'verifyUnencryptedSize']) + ->getMock(); + + if ($unencryptedSizeSet) { + $this->invokePrivate($this->instance, 'unencryptedSize', [[$path => $storedUnencryptedSize]]); + } + + $fileEntry = $this->getMockBuilder(\OC\Files\Cache\Cache::class) + ->disableOriginalConstructor()->getMock(); + $sourceStorage->expects($this->once())->method('getMetaData')->with($path) + ->willReturn($metaData); + $sourceStorage->expects($this->any()) + ->method('getCache') + ->with($path) + ->willReturn($fileEntry); + if ($metaData !== null) { + $fileEntry->expects($this->any()) + ->method('get') + ->with($metaData['fileid']); + } + + $this->instance->expects($this->any())->method('getCache')->willReturn($cache); + if ($expected !== null) { + $this->instance->expects($this->any())->method('verifyUnencryptedSize') + ->with($path, 0)->willReturn($expected['size']); + } + + $result = $this->instance->getMetaData($path); + if (isset($expected['encrypted'])) { + $this->assertSame($expected['encrypted'], (bool)$result['encrypted']); + + if (isset($expected['encryptedVersion'])) { + $this->assertSame($expected['encryptedVersion'], $result['encryptedVersion']); + } + } + + if ($expected !== null) { + $this->assertSame($expected['size'], $result['size']); + } else { + $this->assertSame(null, $result); + } + } + + public function dataTestGetMetaData() { + return [ + ['/test.txt', ['size' => 42, 'encrypted' => 2, 'encryptedVersion' => 2, 'fileid' => 1], true, true, 12, ['size' => 12, 'encrypted' => true, 'encryptedVersion' => 2]], + ['/test.txt', null, true, true, 12, null], + ['/test.txt', ['size' => 42, 'encrypted' => 0, 'fileid' => 1], false, false, 12, ['size' => 42, 'encrypted' => false]], + ['/test.txt', ['size' => 42, 'encrypted' => false, 'fileid' => 1], true, false, 12, ['size' => 12, 'encrypted' => true]] + ]; + } + + public function testFilesize(): void { + $cache = $this->getMockBuilder(\OC\Files\Cache\Cache::class) + ->disableOriginalConstructor()->getMock(); + $cache->expects($this->any()) + ->method('get') + ->willReturn(new CacheEntry(['encrypted' => true, 'path' => '/test.txt', 'size' => 0, 'fileid' => 1])); + + $this->instance = $this->getMockBuilder(\OC\Files\Storage\Wrapper\Encryption::class) + ->setConstructorArgs( + [ + [ + 'storage' => $this->sourceStorage, + 'root' => 'foo', + 'mountPoint' => '/', + 'mount' => $this->mount + ], + $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache + ] + ) + ->setMethods(['getCache', 'verifyUnencryptedSize']) + ->getMock(); + + $this->instance->expects($this->any())->method('getCache')->willReturn($cache); + $this->instance->expects($this->any())->method('verifyUnencryptedSize') + ->willReturn(42); + + + $this->assertSame(42, + $this->instance->filesize('/test.txt') + ); + } + + /** + * @dataProvider dataTestVerifyUnencryptedSize + * + * @param int $encryptedSize + * @param int $unencryptedSize + * @param bool $failure + * @param int $expected + */ + public function testVerifyUnencryptedSize($encryptedSize, $unencryptedSize, $failure, $expected): void { + $sourceStorage = $this->getMockBuilder(\OC\Files\Storage\Storage::class) + ->disableOriginalConstructor()->getMock(); + + $this->instance = $this->getMockBuilder(\OC\Files\Storage\Wrapper\Encryption::class) + ->setConstructorArgs( + [ + [ + 'storage' => $sourceStorage, + 'root' => 'foo', + 'mountPoint' => '/', + 'mount' => $this->mount + ], + $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache + ] + ) + ->setMethods(['fixUnencryptedSize']) + ->getMock(); + + $sourceStorage->expects($this->once())->method('filesize')->willReturn($encryptedSize); + + $this->instance->expects($this->any())->method('fixUnencryptedSize') + ->with('/test.txt', $encryptedSize, $unencryptedSize) + ->willReturnCallback( + function () use ($failure, $expected) { + if ($failure) { + throw new \Exception(); + } else { + return $expected; + } + } + ); + + $this->assertSame( + $expected, + $this->invokePrivate($this->instance, 'verifyUnencryptedSize', ['/test.txt', $unencryptedSize]) + ); + } + + public function dataTestVerifyUnencryptedSize() { + return [ + [120, 80, false, 80], + [120, 120, false, 80], + [120, -1, false, 80], + [120, -1, true, -1] + ]; + } + + /** + * @dataProvider dataTestCopyAndRename + * + * @param string $source + * @param string $target + * @param $encryptionEnabled + * @param boolean $renameKeysReturn + */ + public function testRename($source, + $target, + $encryptionEnabled, + $renameKeysReturn): void { + if ($encryptionEnabled) { + $this->keyStore + ->expects($this->once()) + ->method('renameKeys') + ->willReturn($renameKeysReturn); + } else { + $this->keyStore + ->expects($this->never())->method('renameKeys'); + } + $this->util->expects($this->any()) + ->method('isFile')->willReturn(true); + $this->encryptionManager->expects($this->once()) + ->method('isEnabled')->willReturn($encryptionEnabled); + + $this->instance->mkdir($source); + $this->instance->mkdir(dirname($target)); + $this->instance->rename($source, $target); + } + + public function testCopyEncryption(): void { + $this->instance->file_put_contents('source.txt', 'bar'); + $this->instance->copy('source.txt', 'target.txt'); + $this->assertSame('bar', $this->instance->file_get_contents('target.txt')); + $targetMeta = $this->instance->getMetaData('target.txt'); + $sourceMeta = $this->instance->getMetaData('source.txt'); + $this->assertSame($sourceMeta['encrypted'], $targetMeta['encrypted']); + $this->assertSame($sourceMeta['size'], $targetMeta['size']); + } + + /** + * data provider for testCopyTesting() and dataTestCopyAndRename() + * + * @return array + */ + public function dataTestCopyAndRename() { + return [ + ['source', 'target', true, false, false], + ['source', 'target', true, true, false], + ['source', '/subFolder/target', true, false, false], + ['source', '/subFolder/target', true, true, true], + ['source', '/subFolder/target', false, true, false], + ]; + } + + public function testIsLocal(): void { + $this->encryptionManager->expects($this->once()) + ->method('isEnabled')->willReturn(true); + $this->assertFalse($this->instance->isLocal()); + } + + /** + * @dataProvider dataTestRmdir + * + * @param string $path + * @param boolean $rmdirResult + * @param boolean $isExcluded + * @param boolean $encryptionEnabled + */ + public function testRmdir($path, $rmdirResult, $isExcluded, $encryptionEnabled): void { + $sourceStorage = $this->getMockBuilder(\OC\Files\Storage\Storage::class) + ->disableOriginalConstructor()->getMock(); + + $util = $this->getMockBuilder(\OC\Encryption\Util::class)->disableOriginalConstructor()->getMock(); + + $sourceStorage->expects($this->once())->method('rmdir')->willReturn($rmdirResult); + $util->expects($this->any())->method('isExcluded')-> willReturn($isExcluded); + $this->encryptionManager->expects($this->any())->method('isEnabled')->willReturn($encryptionEnabled); + + $encryptionStorage = new \OC\Files\Storage\Wrapper\Encryption( + [ + 'storage' => $sourceStorage, + 'root' => 'foo', + 'mountPoint' => '/mountPoint', + 'mount' => $this->mount + ], + $this->encryptionManager, $util, $this->logger, $this->file, null, $this->keyStore, $this->update + ); + + + if ($rmdirResult === true && $isExcluded === false && $encryptionEnabled === true) { + $this->keyStore->expects($this->once())->method('deleteAllFileKeys')->with('/mountPoint' . $path); + } else { + $this->keyStore->expects($this->never())->method('deleteAllFileKeys'); + } + + $encryptionStorage->rmdir($path); + } + + public function dataTestRmdir() { + return [ + ['/file.txt', true, true, true], + ['/file.txt', false, true, true], + ['/file.txt', true, false, true], + ['/file.txt', false, false, true], + ['/file.txt', true, true, false], + ['/file.txt', false, true, false], + ['/file.txt', true, false, false], + ['/file.txt', false, false, false], + ]; + } + + /** + * @dataProvider dataTestCopyKeys + * + * @param boolean $excluded + * @param boolean $expected + */ + public function testCopyKeys($excluded, $expected): void { + $this->util->expects($this->once()) + ->method('isExcluded') + ->willReturn($excluded); + + if ($excluded) { + $this->keyStore->expects($this->never())->method('copyKeys'); + } else { + $this->keyStore->expects($this->once())->method('copyKeys')->willReturn(true); + } + + $this->assertSame($expected, + self::invokePrivate($this->instance, 'copyKeys', ['/source', '/target']) + ); + } + + public function dataTestCopyKeys() { + return [ + [true, false], + [false, true], + ]; + } + + /** + * @dataProvider dataTestGetHeader + * + * @param string $path + * @param bool $strippedPathExists + * @param string $strippedPath + */ + public function testGetHeader($path, $strippedPathExists, $strippedPath): void { + $sourceStorage = $this->getMockBuilder(\OC\Files\Storage\Storage::class) + ->disableOriginalConstructor()->getMock(); + + $util = $this->getMockBuilder(\OC\Encryption\Util::class) + ->setConstructorArgs( + [ + new View(), + new Manager( + $this->config, + $this->createMock(ICacheFactory::class), + $this->createMock(IEventDispatcher::class) + ), + $this->groupManager, + $this->config, + $this->arrayCache + ] + )->getMock(); + + $cache = $this->getMockBuilder(\OC\Files\Cache\Cache::class) + ->disableOriginalConstructor()->getMock(); + $cache->expects($this->any()) + ->method('get') + ->willReturnCallback(function ($path) { + return ['encrypted' => true, 'path' => $path]; + }); + + $instance = $this->getMockBuilder(\OC\Files\Storage\Wrapper\Encryption::class) + ->setConstructorArgs( + [ + [ + 'storage' => $sourceStorage, + 'root' => 'foo', + 'mountPoint' => '/', + 'mount' => $this->mount + ], + $this->encryptionManager, $util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache + ] + ) + ->setMethods(['getCache', 'readFirstBlock']) + ->getMock(); + + $instance->method('getCache')->willReturn($cache); + + $util->method('parseRawHeader') + ->willReturn([Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']); + + if ($strippedPathExists) { + $instance->method('readFirstBlock') + ->with($strippedPath)->willReturn(''); + } else { + $instance->method('readFirstBlock') + ->with($path)->willReturn(''); + } + + $util->expects($this->once())->method('stripPartialFileExtension') + ->with($path)->willReturn($strippedPath); + $sourceStorage->expects($this->once()) + ->method('is_file') + ->with($strippedPath) + ->willReturn($strippedPathExists); + + $this->invokePrivate($instance, 'getHeader', [$path]); + } + + public function dataTestGetHeader() { + return [ + ['/foo/bar.txt', false, '/foo/bar.txt'], + ['/foo/bar.txt.part', false, '/foo/bar.txt'], + ['/foo/bar.txt.ocTransferId7437493.part', false, '/foo/bar.txt'], + ['/foo/bar.txt.part', true, '/foo/bar.txt'], + ['/foo/bar.txt.ocTransferId7437493.part', true, '/foo/bar.txt'], + ]; + } + + /** + * test if getHeader adds the default module correctly to the header for + * legacy files + * + * @dataProvider dataTestGetHeaderAddLegacyModule + */ + public function testGetHeaderAddLegacyModule($header, $isEncrypted, $exists, $expected): void { + $sourceStorage = $this->getMockBuilder(\OC\Files\Storage\Storage::class) + ->disableOriginalConstructor()->getMock(); + + $sourceStorage->expects($this->once()) + ->method('is_file') + ->willReturn($exists); + + $util = $this->getMockBuilder(\OC\Encryption\Util::class) + ->setConstructorArgs([new View(), new Manager( + $this->config, + $this->createMock(ICacheFactory::class), + $this->createMock(IEventDispatcher::class) + ), $this->groupManager, $this->config, $this->arrayCache]) + ->getMock(); + + $cache = $this->getMockBuilder(\OC\Files\Cache\Cache::class) + ->disableOriginalConstructor()->getMock(); + $cache->expects($this->any()) + ->method('get') + ->willReturnCallback(function ($path) use ($isEncrypted) { + return ['encrypted' => $isEncrypted, 'path' => $path]; + }); + + $instance = $this->getMockBuilder(\OC\Files\Storage\Wrapper\Encryption::class) + ->setConstructorArgs( + [ + [ + 'storage' => $sourceStorage, + 'root' => 'foo', + 'mountPoint' => '/', + 'mount' => $this->mount + ], + $this->encryptionManager, $util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache + ] + ) + ->setMethods(['readFirstBlock', 'getCache']) + ->getMock(); + + $instance->method('readFirstBlock')->willReturn(''); + + $util->method(('parseRawHeader'))->willReturn($header); + $instance->method('getCache')->willReturn($cache); + + $result = $this->invokePrivate($instance, 'getHeader', ['test.txt']); + $this->assertSameSize($expected, $result); + foreach ($result as $key => $value) { + $this->assertArrayHasKey($key, $expected); + $this->assertSame($expected[$key], $value); + } + } + + public function dataTestGetHeaderAddLegacyModule() { + return [ + [['cipher' => 'AES-128'], true, true, ['cipher' => 'AES-128', Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']], + [[], true, false, []], + [[], true, true, [Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']], + [[], false, true, []], + ]; + } + + public function dataCopyBetweenStorage() { + return [ + [true, true, true], + [true, false, false], + [false, true, false], + [false, false, false], + ]; + } + + public function testCopyBetweenStorageMinimumEncryptedVersion(): void { + $storage2 = $this->createMock(\OC\Files\Storage\Storage::class); + + $sourceInternalPath = $targetInternalPath = 'file.txt'; + $preserveMtime = $isRename = false; + + $storage2->expects($this->any()) + ->method('fopen') + ->willReturnCallback(function ($path, $mode) { + $temp = \OC::$server->getTempManager(); + return fopen($temp->getTemporaryFile(), $mode); + }); + $storage2->method('getId') + ->willReturn('stroage2'); + $cache = $this->createMock(ICache::class); + $cache->expects($this->once()) + ->method('get') + ->with($sourceInternalPath) + ->willReturn(['encryptedVersion' => 0]); + $storage2->expects($this->once()) + ->method('getCache') + ->willReturn($cache); + $this->encryptionManager->expects($this->any()) + ->method('isEnabled') + ->willReturn(true); + global $mockedMountPointEncryptionEnabled; + $mockedMountPointEncryptionEnabled = true; + + $expectedCachePut = [ + 'encrypted' => true, + ]; + $expectedCachePut['encryptedVersion'] = 1; + + $this->cache->expects($this->once()) + ->method('put') + ->with($sourceInternalPath, $expectedCachePut); + + $this->invokePrivate($this->instance, 'copyBetweenStorage', [$storage2, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename]); + + $this->assertFalse(false); + } + + /** + * @dataProvider dataCopyBetweenStorage + * + * @param bool $encryptionEnabled + * @param bool $mountPointEncryptionEnabled + * @param bool $expectedEncrypted + */ + public function testCopyBetweenStorage($encryptionEnabled, $mountPointEncryptionEnabled, $expectedEncrypted): void { + $storage2 = $this->createMock(\OC\Files\Storage\Storage::class); + + $sourceInternalPath = $targetInternalPath = 'file.txt'; + $preserveMtime = $isRename = false; + + $storage2->expects($this->any()) + ->method('fopen') + ->willReturnCallback(function ($path, $mode) { + $temp = \OC::$server->getTempManager(); + return fopen($temp->getTemporaryFile(), $mode); + }); + $storage2->method('getId') + ->willReturn('stroage2'); + if ($expectedEncrypted) { + $cache = $this->createMock(ICache::class); + $cache->expects($this->once()) + ->method('get') + ->with($sourceInternalPath) + ->willReturn(['encryptedVersion' => 12345]); + $storage2->expects($this->once()) + ->method('getCache') + ->willReturn($cache); + } + $this->encryptionManager->expects($this->any()) + ->method('isEnabled') + ->willReturn($encryptionEnabled); + // FIXME can not overwrite the return after definition + // $this->mount->expects($this->at(0)) + // ->method('getOption') + // ->with('encrypt', true) + // ->willReturn($mountPointEncryptionEnabled); + global $mockedMountPointEncryptionEnabled; + $mockedMountPointEncryptionEnabled = $mountPointEncryptionEnabled; + + $expectedCachePut = [ + 'encrypted' => $expectedEncrypted, + ]; + if ($expectedEncrypted === true) { + $expectedCachePut['encryptedVersion'] = 1; + } + + $this->arrayCache->expects($this->never())->method('set'); + + $this->cache->expects($this->once()) + ->method('put') + ->with($sourceInternalPath, $expectedCachePut); + + $this->invokePrivate($this->instance, 'copyBetweenStorage', [$storage2, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename]); + + $this->assertFalse(false); + } + + /** + * @dataProvider dataTestCopyBetweenStorageVersions + * + * @param string $sourceInternalPath + * @param string $targetInternalPath + * @param bool $copyResult + * @param bool $encrypted + */ + public function testCopyBetweenStorageVersions($sourceInternalPath, $targetInternalPath, $copyResult, $encrypted): void { + $sourceStorage = $this->createMock(\OC\Files\Storage\Storage::class); + + $targetStorage = $this->createMock(\OC\Files\Storage\Storage::class); + + $cache = $this->getMockBuilder(\OC\Files\Cache\Cache::class) + ->disableOriginalConstructor()->getMock(); + + $mountPoint = '/mountPoint'; + + /** @var \OC\Files\Storage\Wrapper\Encryption |\PHPUnit\Framework\MockObject\MockObject $instance */ + $instance = $this->getMockBuilder(\OC\Files\Storage\Wrapper\Encryption::class) + ->setConstructorArgs( + [ + [ + 'storage' => $targetStorage, + 'root' => 'foo', + 'mountPoint' => $mountPoint, + 'mount' => $this->mount + ], + $this->encryptionManager, + $this->util, + $this->logger, + $this->file, + null, + $this->keyStore, + $this->update, + $this->mountManager, + $this->arrayCache + ] + ) + ->setMethods(['updateUnencryptedSize', 'getCache']) + ->getMock(); + + $targetStorage->expects($this->once())->method('copyFromStorage') + ->with($sourceStorage, $sourceInternalPath, $targetInternalPath) + ->willReturn($copyResult); + + $instance->expects($this->any())->method('getCache') + ->willReturn($cache); + + $this->arrayCache->expects($this->once())->method('set') + ->with('encryption_copy_version_' . $sourceInternalPath, true); + + if ($copyResult) { + $cache->expects($this->once())->method('get') + ->with($sourceInternalPath) + ->willReturn(new CacheEntry(['encrypted' => $encrypted, 'size' => 42])); + if ($encrypted) { + $instance->expects($this->once())->method('updateUnencryptedSize') + ->with($mountPoint . $targetInternalPath, 42); + } else { + $instance->expects($this->never())->method('updateUnencryptedSize'); + } + } else { + $instance->expects($this->never())->method('updateUnencryptedSize'); + } + + $result = $this->invokePrivate( + $instance, + 'copyBetweenStorage', + [ + $sourceStorage, + $sourceInternalPath, + $targetInternalPath, + false, + false + ] + ); + + $this->assertSame($copyResult, $result); + } + + public function dataTestCopyBetweenStorageVersions() { + return [ + ['/files/foo.txt', '/files_versions/foo.txt.768743', true, true], + ['/files/foo.txt', '/files_versions/foo.txt.768743', true, false], + ['/files/foo.txt', '/files_versions/foo.txt.768743', false, true], + ['/files/foo.txt', '/files_versions/foo.txt.768743', false, false], + ['/files_versions/foo.txt.6487634', '/files/foo.txt', true, true], + ['/files_versions/foo.txt.6487634', '/files/foo.txt', true, false], + ['/files_versions/foo.txt.6487634', '/files/foo.txt', false, true], + ['/files_versions/foo.txt.6487634', '/files/foo.txt', false, false], + + ]; + } + + /** + * @dataProvider dataTestIsVersion + * @param string $path + * @param bool $expected + */ + public function testIsVersion($path, $expected): void { + $this->assertSame($expected, + $this->invokePrivate($this->instance, 'isVersion', [$path]) + ); + } + + public function dataTestIsVersion() { + return [ + ['files_versions/foo', true], + ['/files_versions/foo', true], + ['//files_versions/foo', true], + ['files/versions/foo', false], + ['files/files_versions/foo', false], + ['files_versions_test/foo', false], + ]; + } + + /** + * @dataProvider dataTestShouldEncrypt + * + * @param bool $encryptMountPoint + * @param mixed $encryptionModule + * @param bool $encryptionModuleShouldEncrypt + * @param bool $expected + */ + public function testShouldEncrypt( + $encryptMountPoint, + $encryptionModule, + $encryptionModuleShouldEncrypt, + $expected + ): void { + $encryptionManager = $this->createMock(\OC\Encryption\Manager::class); + $util = $this->createMock(Util::class); + $fileHelper = $this->createMock(IFile::class); + $uid = null; + $keyStorage = $this->createMock(IStorage::class); + $update = $this->createMock(Update::class); + $mountManager = $this->createMock(\OC\Files\Mount\Manager::class); + $mount = $this->createMock(IMountPoint::class); + $arrayCache = $this->createMock(ArrayCache::class); + $path = '/welcome.txt'; + $fullPath = 'admin/files/welcome.txt'; + $defaultEncryptionModule = $this->createMock(IEncryptionModule::class); + + $wrapper = $this->getMockBuilder(Encryption::class) + ->setConstructorArgs( + [ + ['mountPoint' => '', 'mount' => $mount, 'storage' => ''], + $encryptionManager, + $util, + $this->logger, + $fileHelper, + $uid, + $keyStorage, + $update, + $mountManager, + $arrayCache + ] + ) + ->setMethods(['getFullPath', 'getEncryptionModule']) + ->getMock(); + + if ($encryptionModule === true) { + /** @var IEncryptionModule|\PHPUnit\Framework\MockObject\MockObject $encryptionModule */ + $encryptionModule = $this->createMock(IEncryptionModule::class); + } + + $wrapper->method('getFullPath')->with($path)->willReturn($fullPath); + $wrapper->expects($encryptMountPoint ? $this->once() : $this->never()) + ->method('getEncryptionModule') + ->with($fullPath) + ->willReturnCallback( + function () use ($encryptionModule) { + if ($encryptionModule === false) { + throw new ModuleDoesNotExistsException(); + } + return $encryptionModule; + } + ); + $mount->expects($this->once())->method('getOption')->with('encrypt', true) + ->willReturn($encryptMountPoint); + + if ($encryptionModule !== null && $encryptionModule !== false) { + $encryptionModule + ->method('shouldEncrypt') + ->with($fullPath) + ->willReturn($encryptionModuleShouldEncrypt); + } + + if ($encryptionModule === null) { + $encryptionManager->expects($this->once()) + ->method('getEncryptionModule') + ->willReturn($defaultEncryptionModule); + } + $defaultEncryptionModule->method('shouldEncrypt')->willReturn(true); + + $result = $this->invokePrivate($wrapper, 'shouldEncrypt', [$path]); + + $this->assertSame($expected, $result); + } + + public function dataTestShouldEncrypt() { + return [ + [false, false, false, false], + [true, false, false, false], + [true, true, false, false], + [true, true, true, true], + [true, null, false, true], + ]; + } +} diff --git a/tests/lib/Files/Storage/Wrapper/PermissionsMaskTest.php b/tests/lib/Files/Storage/Wrapper/PermissionsMaskTest.php index 5c0a035d094..e082e9ef06e 100644 --- a/tests/lib/Files/Storage/Wrapper/PermissionsMaskTest.php +++ b/tests/lib/Files/Storage/Wrapper/PermissionsMaskTest.php @@ -149,7 +149,7 @@ class PermissionsMaskTest extends \Test\Files\Storage\Storage { $storage = $this->getMaskedStorage(Constants::PERMISSION_READ); $scanner = $storage->getScanner(); $called = false; - $scanner->listen('\OC\Files\Cache\Scanner', 'addToCache', function () use (&$called) { + $scanner->listen(\OC\Files\Cache\Scanner::class, 'addToCache', function () use (&$called) { $called = true; }); $scanner->scan('foo', IScanner::SCAN_RECURSIVE, IScanner::REUSE_ETAG | IScanner::REUSE_SIZE); @@ -167,7 +167,7 @@ class PermissionsMaskTest extends \Test\Files\Storage\Storage { $wrappedStorage = new Wrapper(['storage' => $storage]); $scanner = $wrappedStorage->getScanner(); $called = false; - $scanner->listen('\OC\Files\Cache\Scanner', 'addToCache', function () use (&$called) { + $scanner->listen(\OC\Files\Cache\Scanner::class, 'addToCache', function () use (&$called) { $called = true; }); $scanner->scan('foo', IScanner::SCAN_RECURSIVE, IScanner::REUSE_ETAG | IScanner::REUSE_SIZE); diff --git a/tests/lib/Files/Storage/Wrapper/QuotaTest.php b/tests/lib/Files/Storage/Wrapper/QuotaTest.php index f07e6021e4e..8ad3c36d5c1 100644 --- a/tests/lib/Files/Storage/Wrapper/QuotaTest.php +++ b/tests/lib/Files/Storage/Wrapper/QuotaTest.php @@ -1,229 +1,229 @@ -<?php -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -namespace Test\Files\Storage\Wrapper; - -//ensure the constants are loaded -use OC\Files\Cache\CacheEntry; -use OC\Files\Storage\Local; - -\OC::$loader->load('\OC\Files\Filesystem'); - -/** - * Class QuotaTest - * - * @group DB - * - * @package Test\Files\Storage\Wrapper - */ -class QuotaTest extends \Test\Files\Storage\Storage { - /** - * @var string tmpDir - */ - private $tmpDir; - - protected function setUp(): void { - parent::setUp(); - - $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder(); - $storage = new \OC\Files\Storage\Local(['datadir' => $this->tmpDir]); - $this->instance = new \OC\Files\Storage\Wrapper\Quota(['storage' => $storage, 'quota' => 10000000]); - } - - protected function tearDown(): void { - \OC_Helper::rmdirr($this->tmpDir); - parent::tearDown(); - } - - /** - * @param integer $limit - */ - protected function getLimitedStorage($limit) { - $storage = new \OC\Files\Storage\Local(['datadir' => $this->tmpDir]); - $storage->mkdir('files'); - $storage->getScanner()->scan(''); - return new \OC\Files\Storage\Wrapper\Quota(['storage' => $storage, 'quota' => $limit]); - } - - public function testFilePutContentsNotEnoughSpace(): void { - $instance = $this->getLimitedStorage(3); - $this->assertFalse($instance->file_put_contents('files/foo', 'foobar')); - } - - public function testCopyNotEnoughSpace(): void { - $instance = $this->getLimitedStorage(9); - $this->assertEquals(6, $instance->file_put_contents('files/foo', 'foobar')); - $instance->getScanner()->scan(''); - $this->assertFalse($instance->copy('files/foo', 'files/bar')); - } - - public function testFreeSpace(): void { - $instance = $this->getLimitedStorage(9); - $this->assertEquals(9, $instance->free_space('')); - } - - public function testFreeSpaceWithUsedSpace(): void { - $instance = $this->getLimitedStorage(9); - $instance->getCache()->put( - '', ['size' => 3] - ); - $this->assertEquals(6, $instance->free_space('')); - } - - public function testFreeSpaceWithUnknownDiskSpace(): void { - $storage = $this->getMockBuilder(Local::class) - ->setMethods(['free_space']) - ->setConstructorArgs([['datadir' => $this->tmpDir]]) - ->getMock(); - $storage->expects($this->any()) - ->method('free_space') - ->willReturn(-2); - $storage->getScanner()->scan(''); - - $instance = new \OC\Files\Storage\Wrapper\Quota(['storage' => $storage, 'quota' => 9]); - $instance->getCache()->put( - '', ['size' => 3] - ); - $this->assertEquals(6, $instance->free_space('')); - } - - public function testFreeSpaceWithUsedSpaceAndEncryption(): void { - $instance = $this->getLimitedStorage(9); - $instance->getCache()->put( - '', ['size' => 7] - ); - $this->assertEquals(2, $instance->free_space('')); - } - - public function testFWriteNotEnoughSpace(): void { - $instance = $this->getLimitedStorage(9); - $stream = $instance->fopen('files/foo', 'w+'); - $this->assertEquals(6, fwrite($stream, 'foobar')); - $this->assertEquals(3, fwrite($stream, 'qwerty')); - fclose($stream); - $this->assertEquals('foobarqwe', $instance->file_get_contents('files/foo')); - } - - public function testStreamCopyWithEnoughSpace(): void { - $instance = $this->getLimitedStorage(16); - $inputStream = fopen('data://text/plain,foobarqwerty', 'r'); - $outputStream = $instance->fopen('files/foo', 'w+'); - [$count, $result] = \OC_Helper::streamCopy($inputStream, $outputStream); - $this->assertEquals(12, $count); - $this->assertTrue($result); - fclose($inputStream); - fclose($outputStream); - } - - public function testStreamCopyNotEnoughSpace(): void { - $instance = $this->getLimitedStorage(9); - $inputStream = fopen('data://text/plain,foobarqwerty', 'r'); - $outputStream = $instance->fopen('files/foo', 'w+'); - [$count, $result] = \OC_Helper::streamCopy($inputStream, $outputStream); - $this->assertEquals(9, $count); - $this->assertFalse($result); - fclose($inputStream); - fclose($outputStream); - } - - public function testReturnFalseWhenFopenFailed(): void { - $failStorage = $this->getMockBuilder(Local::class) - ->setMethods(['fopen']) - ->setConstructorArgs([['datadir' => $this->tmpDir]]) - ->getMock(); - $failStorage->expects($this->any()) - ->method('fopen') - ->willReturn(false); - - $instance = new \OC\Files\Storage\Wrapper\Quota(['storage' => $failStorage, 'quota' => 1000]); - - $this->assertFalse($instance->fopen('failedfopen', 'r')); - } - - public function testReturnRegularStreamOnRead(): void { - $instance = $this->getLimitedStorage(9); - - // create test file first - $stream = $instance->fopen('files/foo', 'w+'); - fwrite($stream, 'blablacontent'); - fclose($stream); - - $stream = $instance->fopen('files/foo', 'r'); - $meta = stream_get_meta_data($stream); - $this->assertEquals('plainfile', $meta['wrapper_type']); - fclose($stream); - - $stream = $instance->fopen('files/foo', 'rb'); - $meta = stream_get_meta_data($stream); - $this->assertEquals('plainfile', $meta['wrapper_type']); - fclose($stream); - } - - public function testReturnRegularStreamWhenOutsideFiles(): void { - $instance = $this->getLimitedStorage(9); - $instance->mkdir('files_other'); - - // create test file first - $stream = $instance->fopen('files_other/foo', 'w+'); - $meta = stream_get_meta_data($stream); - $this->assertEquals('plainfile', $meta['wrapper_type']); - fclose($stream); - } - - public function testReturnQuotaStreamOnWrite(): void { - $instance = $this->getLimitedStorage(9); - $stream = $instance->fopen('files/foo', 'w+'); - $meta = stream_get_meta_data($stream); - $expected_type = 'user-space'; - $this->assertEquals($expected_type, $meta['wrapper_type']); - fclose($stream); - } - - public function testSpaceRoot(): void { - $storage = $this->getMockBuilder(Local::class)->disableOriginalConstructor()->getMock(); - $cache = $this->getMockBuilder('\OC\Files\Cache\Cache')->disableOriginalConstructor()->getMock(); - $storage->expects($this->once()) - ->method('getCache') - ->willReturn($cache); - $storage->expects($this->once()) - ->method('free_space') - ->willReturn(2048); - $cache->expects($this->once()) - ->method('get') - ->with('files') - ->willReturn(new CacheEntry(['size' => 50])); - - $instance = new \OC\Files\Storage\Wrapper\Quota(['storage' => $storage, 'quota' => 1024, 'root' => 'files']); - - $this->assertEquals(1024 - 50, $instance->free_space('')); - } - - public function testInstanceOfStorageWrapper(): void { - $this->assertTrue($this->instance->instanceOfStorage('\OC\Files\Storage\Local')); - $this->assertTrue($this->instance->instanceOfStorage('\OC\Files\Storage\Wrapper\Wrapper')); - $this->assertTrue($this->instance->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota')); - } - - public function testNoMkdirQuotaZero(): void { - $instance = $this->getLimitedStorage(0.0); - $this->assertFalse($instance->mkdir('files')); - $this->assertFalse($instance->mkdir('files/foobar')); - } - - public function testMkdirQuotaZeroTrashbin(): void { - $instance = $this->getLimitedStorage(0.0); - $this->assertTrue($instance->mkdir('files_trashbin')); - $this->assertTrue($instance->mkdir('files_trashbin/files')); - $this->assertTrue($instance->mkdir('files_versions')); - $this->assertTrue($instance->mkdir('cache')); - } - - public function testNoTouchQuotaZero(): void { - $instance = $this->getLimitedStorage(0.0); - $this->assertFalse($instance->touch('foobar')); - } -} +<?php +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\Files\Storage\Wrapper; + +//ensure the constants are loaded +use OC\Files\Cache\CacheEntry; +use OC\Files\Storage\Local; + +\OC::$loader->load(\OC\Files\Filesystem::class); + +/** + * Class QuotaTest + * + * @group DB + * + * @package Test\Files\Storage\Wrapper + */ +class QuotaTest extends \Test\Files\Storage\Storage { + /** + * @var string tmpDir + */ + private $tmpDir; + + protected function setUp(): void { + parent::setUp(); + + $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder(); + $storage = new \OC\Files\Storage\Local(['datadir' => $this->tmpDir]); + $this->instance = new \OC\Files\Storage\Wrapper\Quota(['storage' => $storage, 'quota' => 10000000]); + } + + protected function tearDown(): void { + \OC_Helper::rmdirr($this->tmpDir); + parent::tearDown(); + } + + /** + * @param integer $limit + */ + protected function getLimitedStorage($limit) { + $storage = new \OC\Files\Storage\Local(['datadir' => $this->tmpDir]); + $storage->mkdir('files'); + $storage->getScanner()->scan(''); + return new \OC\Files\Storage\Wrapper\Quota(['storage' => $storage, 'quota' => $limit]); + } + + public function testFilePutContentsNotEnoughSpace(): void { + $instance = $this->getLimitedStorage(3); + $this->assertFalse($instance->file_put_contents('files/foo', 'foobar')); + } + + public function testCopyNotEnoughSpace(): void { + $instance = $this->getLimitedStorage(9); + $this->assertEquals(6, $instance->file_put_contents('files/foo', 'foobar')); + $instance->getScanner()->scan(''); + $this->assertFalse($instance->copy('files/foo', 'files/bar')); + } + + public function testFreeSpace(): void { + $instance = $this->getLimitedStorage(9); + $this->assertEquals(9, $instance->free_space('')); + } + + public function testFreeSpaceWithUsedSpace(): void { + $instance = $this->getLimitedStorage(9); + $instance->getCache()->put( + '', ['size' => 3] + ); + $this->assertEquals(6, $instance->free_space('')); + } + + public function testFreeSpaceWithUnknownDiskSpace(): void { + $storage = $this->getMockBuilder(Local::class) + ->setMethods(['free_space']) + ->setConstructorArgs([['datadir' => $this->tmpDir]]) + ->getMock(); + $storage->expects($this->any()) + ->method('free_space') + ->willReturn(-2); + $storage->getScanner()->scan(''); + + $instance = new \OC\Files\Storage\Wrapper\Quota(['storage' => $storage, 'quota' => 9]); + $instance->getCache()->put( + '', ['size' => 3] + ); + $this->assertEquals(6, $instance->free_space('')); + } + + public function testFreeSpaceWithUsedSpaceAndEncryption(): void { + $instance = $this->getLimitedStorage(9); + $instance->getCache()->put( + '', ['size' => 7] + ); + $this->assertEquals(2, $instance->free_space('')); + } + + public function testFWriteNotEnoughSpace(): void { + $instance = $this->getLimitedStorage(9); + $stream = $instance->fopen('files/foo', 'w+'); + $this->assertEquals(6, fwrite($stream, 'foobar')); + $this->assertEquals(3, fwrite($stream, 'qwerty')); + fclose($stream); + $this->assertEquals('foobarqwe', $instance->file_get_contents('files/foo')); + } + + public function testStreamCopyWithEnoughSpace(): void { + $instance = $this->getLimitedStorage(16); + $inputStream = fopen('data://text/plain,foobarqwerty', 'r'); + $outputStream = $instance->fopen('files/foo', 'w+'); + [$count, $result] = \OC_Helper::streamCopy($inputStream, $outputStream); + $this->assertEquals(12, $count); + $this->assertTrue($result); + fclose($inputStream); + fclose($outputStream); + } + + public function testStreamCopyNotEnoughSpace(): void { + $instance = $this->getLimitedStorage(9); + $inputStream = fopen('data://text/plain,foobarqwerty', 'r'); + $outputStream = $instance->fopen('files/foo', 'w+'); + [$count, $result] = \OC_Helper::streamCopy($inputStream, $outputStream); + $this->assertEquals(9, $count); + $this->assertFalse($result); + fclose($inputStream); + fclose($outputStream); + } + + public function testReturnFalseWhenFopenFailed(): void { + $failStorage = $this->getMockBuilder(Local::class) + ->setMethods(['fopen']) + ->setConstructorArgs([['datadir' => $this->tmpDir]]) + ->getMock(); + $failStorage->expects($this->any()) + ->method('fopen') + ->willReturn(false); + + $instance = new \OC\Files\Storage\Wrapper\Quota(['storage' => $failStorage, 'quota' => 1000]); + + $this->assertFalse($instance->fopen('failedfopen', 'r')); + } + + public function testReturnRegularStreamOnRead(): void { + $instance = $this->getLimitedStorage(9); + + // create test file first + $stream = $instance->fopen('files/foo', 'w+'); + fwrite($stream, 'blablacontent'); + fclose($stream); + + $stream = $instance->fopen('files/foo', 'r'); + $meta = stream_get_meta_data($stream); + $this->assertEquals('plainfile', $meta['wrapper_type']); + fclose($stream); + + $stream = $instance->fopen('files/foo', 'rb'); + $meta = stream_get_meta_data($stream); + $this->assertEquals('plainfile', $meta['wrapper_type']); + fclose($stream); + } + + public function testReturnRegularStreamWhenOutsideFiles(): void { + $instance = $this->getLimitedStorage(9); + $instance->mkdir('files_other'); + + // create test file first + $stream = $instance->fopen('files_other/foo', 'w+'); + $meta = stream_get_meta_data($stream); + $this->assertEquals('plainfile', $meta['wrapper_type']); + fclose($stream); + } + + public function testReturnQuotaStreamOnWrite(): void { + $instance = $this->getLimitedStorage(9); + $stream = $instance->fopen('files/foo', 'w+'); + $meta = stream_get_meta_data($stream); + $expected_type = 'user-space'; + $this->assertEquals($expected_type, $meta['wrapper_type']); + fclose($stream); + } + + public function testSpaceRoot(): void { + $storage = $this->getMockBuilder(Local::class)->disableOriginalConstructor()->getMock(); + $cache = $this->getMockBuilder(\OC\Files\Cache\Cache::class)->disableOriginalConstructor()->getMock(); + $storage->expects($this->once()) + ->method('getCache') + ->willReturn($cache); + $storage->expects($this->once()) + ->method('free_space') + ->willReturn(2048); + $cache->expects($this->once()) + ->method('get') + ->with('files') + ->willReturn(new CacheEntry(['size' => 50])); + + $instance = new \OC\Files\Storage\Wrapper\Quota(['storage' => $storage, 'quota' => 1024, 'root' => 'files']); + + $this->assertEquals(1024 - 50, $instance->free_space('')); + } + + public function testInstanceOfStorageWrapper(): void { + $this->assertTrue($this->instance->instanceOfStorage(\OC\Files\Storage\Local::class)); + $this->assertTrue($this->instance->instanceOfStorage(\OC\Files\Storage\Wrapper\Wrapper::class)); + $this->assertTrue($this->instance->instanceOfStorage(\OC\Files\Storage\Wrapper\Quota::class)); + } + + public function testNoMkdirQuotaZero(): void { + $instance = $this->getLimitedStorage(0.0); + $this->assertFalse($instance->mkdir('files')); + $this->assertFalse($instance->mkdir('files/foobar')); + } + + public function testMkdirQuotaZeroTrashbin(): void { + $instance = $this->getLimitedStorage(0.0); + $this->assertTrue($instance->mkdir('files_trashbin')); + $this->assertTrue($instance->mkdir('files_trashbin/files')); + $this->assertTrue($instance->mkdir('files_versions')); + $this->assertTrue($instance->mkdir('cache')); + } + + public function testNoTouchQuotaZero(): void { + $instance = $this->getLimitedStorage(0.0); + $this->assertFalse($instance->touch('foobar')); + } +} diff --git a/tests/lib/Files/Storage/Wrapper/WrapperTest.php b/tests/lib/Files/Storage/Wrapper/WrapperTest.php index 1d0f41bf3ed..9584af0db8f 100644 --- a/tests/lib/Files/Storage/Wrapper/WrapperTest.php +++ b/tests/lib/Files/Storage/Wrapper/WrapperTest.php @@ -1,33 +1,33 @@ -<?php -/** - * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -namespace Test\Files\Storage\Wrapper; - -class WrapperTest extends \Test\Files\Storage\Storage { - /** - * @var string tmpDir - */ - private $tmpDir; - - protected function setUp(): void { - parent::setUp(); - - $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder(); - $storage = new \OC\Files\Storage\Local(['datadir' => $this->tmpDir]); - $this->instance = new \OC\Files\Storage\Wrapper\Wrapper(['storage' => $storage]); - } - - protected function tearDown(): void { - \OC_Helper::rmdirr($this->tmpDir); - parent::tearDown(); - } - - public function testInstanceOfStorageWrapper(): void { - $this->assertTrue($this->instance->instanceOfStorage('\OC\Files\Storage\Local')); - $this->assertTrue($this->instance->instanceOfStorage('\OC\Files\Storage\Wrapper\Wrapper')); - } -} +<?php +/** + * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\Files\Storage\Wrapper; + +class WrapperTest extends \Test\Files\Storage\Storage { + /** + * @var string tmpDir + */ + private $tmpDir; + + protected function setUp(): void { + parent::setUp(); + + $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder(); + $storage = new \OC\Files\Storage\Local(['datadir' => $this->tmpDir]); + $this->instance = new \OC\Files\Storage\Wrapper\Wrapper(['storage' => $storage]); + } + + protected function tearDown(): void { + \OC_Helper::rmdirr($this->tmpDir); + parent::tearDown(); + } + + public function testInstanceOfStorageWrapper(): void { + $this->assertTrue($this->instance->instanceOfStorage(\OC\Files\Storage\Local::class)); + $this->assertTrue($this->instance->instanceOfStorage(\OC\Files\Storage\Wrapper\Wrapper::class)); + } +} diff --git a/tests/lib/Files/Stream/EncryptionTest.php b/tests/lib/Files/Stream/EncryptionTest.php index c29a38f2b09..0a758337539 100644 --- a/tests/lib/Files/Stream/EncryptionTest.php +++ b/tests/lib/Files/Stream/EncryptionTest.php @@ -1,371 +1,371 @@ -<?php -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-only - */ -namespace Test\Files\Stream; - -use OC\Files\Cache\CacheEntry; -use OC\Files\View; -use OC\Memcache\ArrayCache; -use OCP\EventDispatcher\IEventDispatcher; -use OCP\Files\Cache\ICache; -use OCP\ICacheFactory; -use OCP\IConfig; - -class EncryptionTest extends \Test\TestCase { - public const DEFAULT_WRAPPER = '\OC\Files\Stream\Encryption'; - - /** @var \OCP\Encryption\IEncryptionModule | \PHPUnit\Framework\MockObject\MockObject */ - private $encryptionModule; - - /** - * @param string $fileName - * @param string $mode - * @param integer $unencryptedSize - * @return resource - */ - protected function getStream($fileName, $mode, $unencryptedSize, $wrapper = self::DEFAULT_WRAPPER, $unencryptedSizeOnClose = 0) { - clearstatcache(); - $size = filesize($fileName); - $source = fopen($fileName, $mode); - $internalPath = $fileName; - $fullPath = $fileName; - $header = []; - $uid = ''; - $this->encryptionModule = $this->buildMockModule(); - $cache = $this->createMock(ICache::class); - $storage = $this->getMockBuilder('\OC\Files\Storage\Storage') - ->disableOriginalConstructor()->getMock(); - $encStorage = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption') - ->disableOriginalConstructor()->getMock(); - $config = $this->getMockBuilder(IConfig::class) - ->disableOriginalConstructor() - ->getMock(); - $arrayCache = $this->createMock(ArrayCache::class); - $groupManager = $this->getMockBuilder('\OC\Group\Manager') - ->disableOriginalConstructor() - ->getMock(); - $file = $this->getMockBuilder('\OC\Encryption\File') - ->disableOriginalConstructor() - ->setMethods(['getAccessList']) - ->getMock(); - $file->expects($this->any())->method('getAccessList')->willReturn([]); - $util = $this->getMockBuilder('\OC\Encryption\Util') - ->setMethods(['getUidAndFilename']) - ->setConstructorArgs([new View(), new \OC\User\Manager( - $config, - $this->createMock(ICacheFactory::class), - $this->createMock(IEventDispatcher::class) - ), $groupManager, $config, $arrayCache]) - ->getMock(); - $util->expects($this->any()) - ->method('getUidAndFilename') - ->willReturn(['user1', $internalPath]); - $storage->expects($this->any())->method('getCache')->willReturn($cache); - $entry = new CacheEntry([ - 'fileid' => 5, - 'encryptedVersion' => 2, - 'unencrypted_size' => $unencryptedSizeOnClose, - ]); - $cache->expects($this->any())->method('get')->willReturn($entry); - $cache->expects($this->any())->method('update')->with(5, ['encrypted' => 3, 'encryptedVersion' => 3, 'unencrypted_size' => $unencryptedSizeOnClose]); - - - return $wrapper::wrap($source, $internalPath, - $fullPath, $header, $uid, $this->encryptionModule, $storage, $encStorage, - $util, $file, $mode, $size, $unencryptedSize, 8192, $wrapper); - } - - /** - * @dataProvider dataProviderStreamOpen() - */ - public function testStreamOpen($isMasterKeyUsed, - $mode, - $fullPath, - $fileExists, - $expectedSharePath, - $expectedSize, - $expectedUnencryptedSize, - $expectedReadOnly): void { - // build mocks - $encryptionModuleMock = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule') - ->disableOriginalConstructor()->getMock(); - $encryptionModuleMock->expects($this->any())->method('needDetailedAccessList')->willReturn(!$isMasterKeyUsed); - $encryptionModuleMock->expects($this->once()) - ->method('getUnencryptedBlockSize')->willReturn(99); - $encryptionModuleMock->expects($this->once()) - ->method('begin')->willReturn(true); - - $storageMock = $this->getMockBuilder('\OC\Files\Storage\Storage') - ->disableOriginalConstructor()->getMock(); - $storageMock->expects($this->once())->method('file_exists')->willReturn($fileExists); - - $fileMock = $this->getMockBuilder('\OC\Encryption\File') - ->disableOriginalConstructor()->getMock(); - if ($isMasterKeyUsed) { - $fileMock->expects($this->never())->method('getAccessList'); - } else { - $fileMock->expects($this->once())->method('getAccessList') - ->willReturnCallback(function ($sharePath) use ($expectedSharePath) { - $this->assertSame($expectedSharePath, $sharePath); - return []; - }); - } - $utilMock = $this->getMockBuilder('\OC\Encryption\Util') - ->disableOriginalConstructor()->getMock(); - $utilMock->expects($this->any()) - ->method('getHeaderSize') - ->willReturn(8192); - - // get a instance of the stream wrapper - $streamWrapper = $this->getMockBuilder('\OC\Files\Stream\Encryption') - ->setMethods(['loadContext', 'writeHeader', 'skipHeader'])->disableOriginalConstructor()->getMock(); - - // set internal properties of the stream wrapper - $stream = new \ReflectionClass('\OC\Files\Stream\Encryption'); - $encryptionModule = $stream->getProperty('encryptionModule'); - $encryptionModule->setAccessible(true); - $encryptionModule->setValue($streamWrapper, $encryptionModuleMock); - $encryptionModule->setAccessible(false); - $storage = $stream->getProperty('storage'); - $storage->setAccessible(true); - $storage->setValue($streamWrapper, $storageMock); - $storage->setAccessible(false); - $file = $stream->getProperty('file'); - $file->setAccessible(true); - $file->setValue($streamWrapper, $fileMock); - $file->setAccessible(false); - $util = $stream->getProperty('util'); - $util->setAccessible(true); - $util->setValue($streamWrapper, $utilMock); - $util->setAccessible(false); - $fullPathP = $stream->getProperty('fullPath'); - $fullPathP->setAccessible(true); - $fullPathP->setValue($streamWrapper, $fullPath); - $fullPathP->setAccessible(false); - $header = $stream->getProperty('header'); - $header->setAccessible(true); - $header->setValue($streamWrapper, []); - $header->setAccessible(false); - $this->invokePrivate($streamWrapper, 'signed', [true]); - - // call stream_open, that's the method we want to test - $dummyVar = 'foo'; - $streamWrapper->stream_open('', $mode, '', $dummyVar); - - // check internal properties - $size = $stream->getProperty('size'); - $size->setAccessible(true); - $this->assertSame($expectedSize, - $size->getValue($streamWrapper) - ); - $size->setAccessible(false); - - $unencryptedSize = $stream->getProperty('unencryptedSize'); - $unencryptedSize->setAccessible(true); - $this->assertSame($expectedUnencryptedSize, - $unencryptedSize->getValue($streamWrapper) - ); - $unencryptedSize->setAccessible(false); - - $readOnly = $stream->getProperty('readOnly'); - $readOnly->setAccessible(true); - $this->assertSame($expectedReadOnly, - $readOnly->getValue($streamWrapper) - ); - $readOnly->setAccessible(false); - } - - public function dataProviderStreamOpen() { - return [ - [false, 'r', '/foo/bar/test.txt', true, '/foo/bar/test.txt', null, null, true], - [false, 'r', '/foo/bar/test.txt', false, '/foo/bar', null, null, true], - [false, 'w', '/foo/bar/test.txt', true, '/foo/bar/test.txt', 8192, 0, false], - [true, 'r', '/foo/bar/test.txt', true, '/foo/bar/test.txt', null, null, true], - [true, 'r', '/foo/bar/test.txt', false, '/foo/bar', null, null, true], - [true, 'w', '/foo/bar/test.txt', true, '/foo/bar/test.txt', 8192, 0, false], - ]; - } - - public function testWriteRead(): void { - $fileName = tempnam('/tmp', 'FOO'); - $stream = $this->getStream($fileName, 'w+', 0, self::DEFAULT_WRAPPER, 6); - $this->assertEquals(6, fwrite($stream, 'foobar')); - fclose($stream); - - $stream = $this->getStream($fileName, 'r', 6); - $this->assertEquals('foobar', fread($stream, 100)); - fclose($stream); - - $stream = $this->getStream($fileName, 'r+', 6, self::DEFAULT_WRAPPER, 6); - $this->assertEquals(3, fwrite($stream, 'bar')); - fclose($stream); - - $stream = $this->getStream($fileName, 'r', 6); - $this->assertEquals('barbar', fread($stream, 100)); - fclose($stream); - - unlink($fileName); - } - - public function testRewind(): void { - $fileName = tempnam('/tmp', 'FOO'); - $stream = $this->getStream($fileName, 'w+', 0, self::DEFAULT_WRAPPER, 6); - $this->assertEquals(6, fwrite($stream, 'foobar')); - $this->assertEquals(true, rewind($stream)); - $this->assertEquals('foobar', fread($stream, 100)); - $this->assertEquals(true, rewind($stream)); - $this->assertEquals(3, fwrite($stream, 'bar')); - fclose($stream); - - $stream = $this->getStream($fileName, 'r', 6); - $this->assertEquals('barbar', fread($stream, 100)); - fclose($stream); - - unlink($fileName); - } - - public function testSeek(): void { - $fileName = tempnam('/tmp', 'FOO'); - - $stream = $this->getStream($fileName, 'w+', 0, self::DEFAULT_WRAPPER, 9); - $this->assertEquals(6, fwrite($stream, 'foobar')); - $this->assertEquals(0, fseek($stream, 3)); - $this->assertEquals(6, fwrite($stream, 'foobar')); - fclose($stream); - - $stream = $this->getStream($fileName, 'r', 9); - $this->assertEquals('foofoobar', fread($stream, 100)); - $this->assertEquals(-1, fseek($stream, 10)); - $this->assertEquals(0, fseek($stream, 9)); - $this->assertEquals(-1, fseek($stream, -10, SEEK_CUR)); - $this->assertEquals(0, fseek($stream, -9, SEEK_CUR)); - $this->assertEquals(-1, fseek($stream, -10, SEEK_END)); - $this->assertEquals(0, fseek($stream, -9, SEEK_END)); - fclose($stream); - - unlink($fileName); - } - - public function dataFilesProvider() { - return [ - ['lorem-big.txt'], - ['block-aligned.txt'], - ['block-aligned-plus-one.txt'], - ]; - } - - /** - * @dataProvider dataFilesProvider - */ - public function testWriteReadBigFile($testFile): void { - $expectedData = file_get_contents(\OC::$SERVERROOT . '/tests/data/' . $testFile); - // write it - $fileName = tempnam('/tmp', 'FOO'); - $stream = $this->getStream($fileName, 'w+', 0, self::DEFAULT_WRAPPER, strlen($expectedData)); - // while writing the file from the beginning to the end we should never try - // to read parts of the file. This should only happen for write operations - // in the middle of a file - $this->encryptionModule->expects($this->never())->method('decrypt'); - fwrite($stream, $expectedData); - fclose($stream); - - // read it all - $stream = $this->getStream($fileName, 'r', strlen($expectedData)); - $data = stream_get_contents($stream); - fclose($stream); - - $this->assertEquals($expectedData, $data); - - // another read test with a loop like we do in several places: - $stream = $this->getStream($fileName, 'r', strlen($expectedData)); - $data = ''; - while (!feof($stream)) { - $data .= fread($stream, 8192); - } - fclose($stream); - - $this->assertEquals($expectedData, $data); - - unlink($fileName); - } - - /** - * simulate a non-seekable storage - * - * @dataProvider dataFilesProvider - */ - public function testWriteToNonSeekableStorage($testFile): void { - $wrapper = $this->getMockBuilder('\OC\Files\Stream\Encryption') - ->setMethods(['parentSeekStream'])->getMock(); - $wrapper->expects($this->any())->method('parentSeekStream')->willReturn(false); - - $expectedData = file_get_contents(\OC::$SERVERROOT . '/tests/data/' . $testFile); - // write it - $fileName = tempnam('/tmp', 'FOO'); - $stream = $this->getStream($fileName, 'w+', 0, '\Test\Files\Stream\DummyEncryptionWrapper', strlen($expectedData)); - // while writing the file from the beginning to the end we should never try - // to read parts of the file. This should only happen for write operations - // in the middle of a file - $this->encryptionModule->expects($this->never())->method('decrypt'); - fwrite($stream, $expectedData); - fclose($stream); - - // read it all - $stream = $this->getStream($fileName, 'r', strlen($expectedData), '\Test\Files\Stream\DummyEncryptionWrapper', strlen($expectedData)); - $data = stream_get_contents($stream); - fclose($stream); - - $this->assertEquals($expectedData, $data); - - // another read test with a loop like we do in several places: - $stream = $this->getStream($fileName, 'r', strlen($expectedData)); - $data = ''; - while (!feof($stream)) { - $data .= fread($stream, 8192); - } - fclose($stream); - - $this->assertEquals($expectedData, $data); - - unlink($fileName); - } - - /** - * @return \PHPUnit\Framework\MockObject\MockObject - */ - protected function buildMockModule() { - $encryptionModule = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule') - ->disableOriginalConstructor() - ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll', 'isReadyForUser', 'needDetailedAccessList']) - ->getMock(); - - $encryptionModule->expects($this->any())->method('getId')->willReturn('UNIT_TEST_MODULE'); - $encryptionModule->expects($this->any())->method('getDisplayName')->willReturn('Unit test module'); - $encryptionModule->expects($this->any())->method('begin')->willReturn([]); - $encryptionModule->expects($this->any())->method('end')->willReturn(''); - $encryptionModule->expects($this->any())->method('isReadable')->willReturn(true); - $encryptionModule->expects($this->any())->method('needDetailedAccessList')->willReturn(false); - $encryptionModule->expects($this->any())->method('encrypt')->willReturnCallback(function ($data) { - // simulate different block size by adding some padding to the data - if (isset($data[6125])) { - return str_pad($data, 8192, 'X'); - } - // last block - return $data; - }); - $encryptionModule->expects($this->any())->method('decrypt')->willReturnCallback(function ($data) { - if (isset($data[8191])) { - return substr($data, 0, 6126); - } - // last block - return $data; - }); - $encryptionModule->expects($this->any())->method('update')->willReturn(true); - $encryptionModule->expects($this->any())->method('shouldEncrypt')->willReturn(true); - $encryptionModule->expects($this->any())->method('getUnencryptedBlockSize')->willReturn(6126); - return $encryptionModule; - } -} +<?php +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace Test\Files\Stream; + +use OC\Files\Cache\CacheEntry; +use OC\Files\View; +use OC\Memcache\ArrayCache; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Cache\ICache; +use OCP\ICacheFactory; +use OCP\IConfig; + +class EncryptionTest extends \Test\TestCase { + public const DEFAULT_WRAPPER = '\OC\Files\Stream\Encryption'; + + /** @var \OCP\Encryption\IEncryptionModule | \PHPUnit\Framework\MockObject\MockObject */ + private $encryptionModule; + + /** + * @param string $fileName + * @param string $mode + * @param integer $unencryptedSize + * @return resource + */ + protected function getStream($fileName, $mode, $unencryptedSize, $wrapper = self::DEFAULT_WRAPPER, $unencryptedSizeOnClose = 0) { + clearstatcache(); + $size = filesize($fileName); + $source = fopen($fileName, $mode); + $internalPath = $fileName; + $fullPath = $fileName; + $header = []; + $uid = ''; + $this->encryptionModule = $this->buildMockModule(); + $cache = $this->createMock(ICache::class); + $storage = $this->getMockBuilder(\OC\Files\Storage\Storage::class) + ->disableOriginalConstructor()->getMock(); + $encStorage = $this->getMockBuilder(\OC\Files\Storage\Wrapper\Encryption::class) + ->disableOriginalConstructor()->getMock(); + $config = $this->getMockBuilder(IConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $arrayCache = $this->createMock(ArrayCache::class); + $groupManager = $this->getMockBuilder(\OC\Group\Manager::class) + ->disableOriginalConstructor() + ->getMock(); + $file = $this->getMockBuilder(\OC\Encryption\File::class) + ->disableOriginalConstructor() + ->setMethods(['getAccessList']) + ->getMock(); + $file->expects($this->any())->method('getAccessList')->willReturn([]); + $util = $this->getMockBuilder(\OC\Encryption\Util::class) + ->setMethods(['getUidAndFilename']) + ->setConstructorArgs([new View(), new \OC\User\Manager( + $config, + $this->createMock(ICacheFactory::class), + $this->createMock(IEventDispatcher::class) + ), $groupManager, $config, $arrayCache]) + ->getMock(); + $util->expects($this->any()) + ->method('getUidAndFilename') + ->willReturn(['user1', $internalPath]); + $storage->expects($this->any())->method('getCache')->willReturn($cache); + $entry = new CacheEntry([ + 'fileid' => 5, + 'encryptedVersion' => 2, + 'unencrypted_size' => $unencryptedSizeOnClose, + ]); + $cache->expects($this->any())->method('get')->willReturn($entry); + $cache->expects($this->any())->method('update')->with(5, ['encrypted' => 3, 'encryptedVersion' => 3, 'unencrypted_size' => $unencryptedSizeOnClose]); + + + return $wrapper::wrap($source, $internalPath, + $fullPath, $header, $uid, $this->encryptionModule, $storage, $encStorage, + $util, $file, $mode, $size, $unencryptedSize, 8192, $wrapper); + } + + /** + * @dataProvider dataProviderStreamOpen() + */ + public function testStreamOpen($isMasterKeyUsed, + $mode, + $fullPath, + $fileExists, + $expectedSharePath, + $expectedSize, + $expectedUnencryptedSize, + $expectedReadOnly): void { + // build mocks + $encryptionModuleMock = $this->getMockBuilder(\OCP\Encryption\IEncryptionModule::class) + ->disableOriginalConstructor()->getMock(); + $encryptionModuleMock->expects($this->any())->method('needDetailedAccessList')->willReturn(!$isMasterKeyUsed); + $encryptionModuleMock->expects($this->once()) + ->method('getUnencryptedBlockSize')->willReturn(99); + $encryptionModuleMock->expects($this->once()) + ->method('begin')->willReturn(true); + + $storageMock = $this->getMockBuilder(\OC\Files\Storage\Storage::class) + ->disableOriginalConstructor()->getMock(); + $storageMock->expects($this->once())->method('file_exists')->willReturn($fileExists); + + $fileMock = $this->getMockBuilder(\OC\Encryption\File::class) + ->disableOriginalConstructor()->getMock(); + if ($isMasterKeyUsed) { + $fileMock->expects($this->never())->method('getAccessList'); + } else { + $fileMock->expects($this->once())->method('getAccessList') + ->willReturnCallback(function ($sharePath) use ($expectedSharePath) { + $this->assertSame($expectedSharePath, $sharePath); + return []; + }); + } + $utilMock = $this->getMockBuilder(\OC\Encryption\Util::class) + ->disableOriginalConstructor()->getMock(); + $utilMock->expects($this->any()) + ->method('getHeaderSize') + ->willReturn(8192); + + // get a instance of the stream wrapper + $streamWrapper = $this->getMockBuilder(\OC\Files\Stream\Encryption::class) + ->setMethods(['loadContext', 'writeHeader', 'skipHeader'])->disableOriginalConstructor()->getMock(); + + // set internal properties of the stream wrapper + $stream = new \ReflectionClass(\OC\Files\Stream\Encryption::class); + $encryptionModule = $stream->getProperty('encryptionModule'); + $encryptionModule->setAccessible(true); + $encryptionModule->setValue($streamWrapper, $encryptionModuleMock); + $encryptionModule->setAccessible(false); + $storage = $stream->getProperty('storage'); + $storage->setAccessible(true); + $storage->setValue($streamWrapper, $storageMock); + $storage->setAccessible(false); + $file = $stream->getProperty('file'); + $file->setAccessible(true); + $file->setValue($streamWrapper, $fileMock); + $file->setAccessible(false); + $util = $stream->getProperty('util'); + $util->setAccessible(true); + $util->setValue($streamWrapper, $utilMock); + $util->setAccessible(false); + $fullPathP = $stream->getProperty('fullPath'); + $fullPathP->setAccessible(true); + $fullPathP->setValue($streamWrapper, $fullPath); + $fullPathP->setAccessible(false); + $header = $stream->getProperty('header'); + $header->setAccessible(true); + $header->setValue($streamWrapper, []); + $header->setAccessible(false); + $this->invokePrivate($streamWrapper, 'signed', [true]); + + // call stream_open, that's the method we want to test + $dummyVar = 'foo'; + $streamWrapper->stream_open('', $mode, '', $dummyVar); + + // check internal properties + $size = $stream->getProperty('size'); + $size->setAccessible(true); + $this->assertSame($expectedSize, + $size->getValue($streamWrapper) + ); + $size->setAccessible(false); + + $unencryptedSize = $stream->getProperty('unencryptedSize'); + $unencryptedSize->setAccessible(true); + $this->assertSame($expectedUnencryptedSize, + $unencryptedSize->getValue($streamWrapper) + ); + $unencryptedSize->setAccessible(false); + + $readOnly = $stream->getProperty('readOnly'); + $readOnly->setAccessible(true); + $this->assertSame($expectedReadOnly, + $readOnly->getValue($streamWrapper) + ); + $readOnly->setAccessible(false); + } + + public function dataProviderStreamOpen() { + return [ + [false, 'r', '/foo/bar/test.txt', true, '/foo/bar/test.txt', null, null, true], + [false, 'r', '/foo/bar/test.txt', false, '/foo/bar', null, null, true], + [false, 'w', '/foo/bar/test.txt', true, '/foo/bar/test.txt', 8192, 0, false], + [true, 'r', '/foo/bar/test.txt', true, '/foo/bar/test.txt', null, null, true], + [true, 'r', '/foo/bar/test.txt', false, '/foo/bar', null, null, true], + [true, 'w', '/foo/bar/test.txt', true, '/foo/bar/test.txt', 8192, 0, false], + ]; + } + + public function testWriteRead(): void { + $fileName = tempnam('/tmp', 'FOO'); + $stream = $this->getStream($fileName, 'w+', 0, self::DEFAULT_WRAPPER, 6); + $this->assertEquals(6, fwrite($stream, 'foobar')); + fclose($stream); + + $stream = $this->getStream($fileName, 'r', 6); + $this->assertEquals('foobar', fread($stream, 100)); + fclose($stream); + + $stream = $this->getStream($fileName, 'r+', 6, self::DEFAULT_WRAPPER, 6); + $this->assertEquals(3, fwrite($stream, 'bar')); + fclose($stream); + + $stream = $this->getStream($fileName, 'r', 6); + $this->assertEquals('barbar', fread($stream, 100)); + fclose($stream); + + unlink($fileName); + } + + public function testRewind(): void { + $fileName = tempnam('/tmp', 'FOO'); + $stream = $this->getStream($fileName, 'w+', 0, self::DEFAULT_WRAPPER, 6); + $this->assertEquals(6, fwrite($stream, 'foobar')); + $this->assertEquals(true, rewind($stream)); + $this->assertEquals('foobar', fread($stream, 100)); + $this->assertEquals(true, rewind($stream)); + $this->assertEquals(3, fwrite($stream, 'bar')); + fclose($stream); + + $stream = $this->getStream($fileName, 'r', 6); + $this->assertEquals('barbar', fread($stream, 100)); + fclose($stream); + + unlink($fileName); + } + + public function testSeek(): void { + $fileName = tempnam('/tmp', 'FOO'); + + $stream = $this->getStream($fileName, 'w+', 0, self::DEFAULT_WRAPPER, 9); + $this->assertEquals(6, fwrite($stream, 'foobar')); + $this->assertEquals(0, fseek($stream, 3)); + $this->assertEquals(6, fwrite($stream, 'foobar')); + fclose($stream); + + $stream = $this->getStream($fileName, 'r', 9); + $this->assertEquals('foofoobar', fread($stream, 100)); + $this->assertEquals(-1, fseek($stream, 10)); + $this->assertEquals(0, fseek($stream, 9)); + $this->assertEquals(-1, fseek($stream, -10, SEEK_CUR)); + $this->assertEquals(0, fseek($stream, -9, SEEK_CUR)); + $this->assertEquals(-1, fseek($stream, -10, SEEK_END)); + $this->assertEquals(0, fseek($stream, -9, SEEK_END)); + fclose($stream); + + unlink($fileName); + } + + public function dataFilesProvider() { + return [ + ['lorem-big.txt'], + ['block-aligned.txt'], + ['block-aligned-plus-one.txt'], + ]; + } + + /** + * @dataProvider dataFilesProvider + */ + public function testWriteReadBigFile($testFile): void { + $expectedData = file_get_contents(\OC::$SERVERROOT . '/tests/data/' . $testFile); + // write it + $fileName = tempnam('/tmp', 'FOO'); + $stream = $this->getStream($fileName, 'w+', 0, self::DEFAULT_WRAPPER, strlen($expectedData)); + // while writing the file from the beginning to the end we should never try + // to read parts of the file. This should only happen for write operations + // in the middle of a file + $this->encryptionModule->expects($this->never())->method('decrypt'); + fwrite($stream, $expectedData); + fclose($stream); + + // read it all + $stream = $this->getStream($fileName, 'r', strlen($expectedData)); + $data = stream_get_contents($stream); + fclose($stream); + + $this->assertEquals($expectedData, $data); + + // another read test with a loop like we do in several places: + $stream = $this->getStream($fileName, 'r', strlen($expectedData)); + $data = ''; + while (!feof($stream)) { + $data .= fread($stream, 8192); + } + fclose($stream); + + $this->assertEquals($expectedData, $data); + + unlink($fileName); + } + + /** + * simulate a non-seekable storage + * + * @dataProvider dataFilesProvider + */ + public function testWriteToNonSeekableStorage($testFile): void { + $wrapper = $this->getMockBuilder(\OC\Files\Stream\Encryption::class) + ->setMethods(['parentSeekStream'])->getMock(); + $wrapper->expects($this->any())->method('parentSeekStream')->willReturn(false); + + $expectedData = file_get_contents(\OC::$SERVERROOT . '/tests/data/' . $testFile); + // write it + $fileName = tempnam('/tmp', 'FOO'); + $stream = $this->getStream($fileName, 'w+', 0, \Test\Files\Stream\DummyEncryptionWrapper::class, strlen($expectedData)); + // while writing the file from the beginning to the end we should never try + // to read parts of the file. This should only happen for write operations + // in the middle of a file + $this->encryptionModule->expects($this->never())->method('decrypt'); + fwrite($stream, $expectedData); + fclose($stream); + + // read it all + $stream = $this->getStream($fileName, 'r', strlen($expectedData), \Test\Files\Stream\DummyEncryptionWrapper::class, strlen($expectedData)); + $data = stream_get_contents($stream); + fclose($stream); + + $this->assertEquals($expectedData, $data); + + // another read test with a loop like we do in several places: + $stream = $this->getStream($fileName, 'r', strlen($expectedData)); + $data = ''; + while (!feof($stream)) { + $data .= fread($stream, 8192); + } + fclose($stream); + + $this->assertEquals($expectedData, $data); + + unlink($fileName); + } + + /** + * @return \PHPUnit\Framework\MockObject\MockObject + */ + protected function buildMockModule() { + $encryptionModule = $this->getMockBuilder(\OCP\Encryption\IEncryptionModule::class) + ->disableOriginalConstructor() + ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll', 'isReadyForUser', 'needDetailedAccessList']) + ->getMock(); + + $encryptionModule->expects($this->any())->method('getId')->willReturn('UNIT_TEST_MODULE'); + $encryptionModule->expects($this->any())->method('getDisplayName')->willReturn('Unit test module'); + $encryptionModule->expects($this->any())->method('begin')->willReturn([]); + $encryptionModule->expects($this->any())->method('end')->willReturn(''); + $encryptionModule->expects($this->any())->method('isReadable')->willReturn(true); + $encryptionModule->expects($this->any())->method('needDetailedAccessList')->willReturn(false); + $encryptionModule->expects($this->any())->method('encrypt')->willReturnCallback(function ($data) { + // simulate different block size by adding some padding to the data + if (isset($data[6125])) { + return str_pad($data, 8192, 'X'); + } + // last block + return $data; + }); + $encryptionModule->expects($this->any())->method('decrypt')->willReturnCallback(function ($data) { + if (isset($data[8191])) { + return substr($data, 0, 6126); + } + // last block + return $data; + }); + $encryptionModule->expects($this->any())->method('update')->willReturn(true); + $encryptionModule->expects($this->any())->method('shouldEncrypt')->willReturn(true); + $encryptionModule->expects($this->any())->method('getUnencryptedBlockSize')->willReturn(6126); + return $encryptionModule; + } +} diff --git a/tests/lib/Files/ViewTest.php b/tests/lib/Files/ViewTest.php index 0a029889fb1..1081d5857df 100644 --- a/tests/lib/Files/ViewTest.php +++ b/tests/lib/Files/ViewTest.php @@ -51,7 +51,7 @@ class TemporaryNoCross extends Temporary { class TemporaryNoLocal extends Temporary { public function instanceOfStorage($className) { - if ($className === '\OC\Files\Storage\Local') { + if ($className === \OC\Files\Storage\Local::class) { return false; } else { return parent::instanceOfStorage($className); @@ -930,7 +930,7 @@ class ViewTest extends \Test\TestCase { $view = new View('/test'); $info = $view->getFileInfo('test.part'); - $this->assertInstanceOf('\OCP\Files\FileInfo', $info); + $this->assertInstanceOf(\OCP\Files\FileInfo::class, $info); $this->assertNull($info->getId()); $this->assertEquals(6, $info->getSize()); } diff --git a/tests/lib/Group/GroupTest.php b/tests/lib/Group/GroupTest.php index 0730f827c64..a15a6e39a24 100644 --- a/tests/lib/Group/GroupTest.php +++ b/tests/lib/Group/GroupTest.php @@ -1,475 +1,475 @@ -<?php - -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -namespace Test\Group; - -use OC\User\User; -use OCP\EventDispatcher\IEventDispatcher; -use OCP\IUser; -use PHPUnit\Framework\MockObject\MockObject; - -class GroupTest extends \Test\TestCase { - /** @var IEventDispatcher|MockObject */ - protected $dispatcher; - - protected function setUp(): void { - parent::setUp(); - $this->dispatcher = $this->createMock(IEventDispatcher::class); - } - - /** - * @param string $uid - * @param \OC\User\Backend $backend - * @return User - */ - private function newUser($uid, \OC\User\Backend $backend) { - $user = $this->createMock(IUser::class); - $user->method('getUID') - ->willReturn($uid); - $user->method('getBackend') - ->willReturn($backend); - - return $user; - } - - /** - * @return \OC\User\Manager - */ - protected function getUserManager() { - $userManager = $this->getMockBuilder('\OC\User\Manager') - ->disableOriginalConstructor() - ->getMock(); - $backend = $this->getMockBuilder('\OC\User\Backend') - ->disableOriginalConstructor() - ->getMock(); - $user1 = $this->newUser('user1', $backend); - $user2 = $this->newUser('user2', $backend); - $user3 = $this->newUser('user3', $backend); - $userManager->expects($this->any()) - ->method('get') - ->willReturnMap([ - ['user1', $user1], - ['user2', $user2], - ['user3', $user3] - ]); - return $userManager; - } - - public function testGetUsersSingleBackend(): void { - $backend = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $userManager = $this->getUserManager(); - $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); - - $backend->expects($this->once()) - ->method('usersInGroup') - ->with('group1') - ->willReturn(['user1', 'user2']); - - $users = $group->getUsers(); - - $this->assertEquals(2, count($users)); - $user1 = $users['user1']; - $user2 = $users['user2']; - $this->assertEquals('user1', $user1->getUID()); - $this->assertEquals('user2', $user2->getUID()); - } - - public function testGetUsersMultipleBackends(): void { - $backend1 = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $backend2 = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $userManager = $this->getUserManager(); - $group = new \OC\Group\Group('group1', [$backend1, $backend2], $this->dispatcher, $userManager); - - $backend1->expects($this->once()) - ->method('usersInGroup') - ->with('group1') - ->willReturn(['user1', 'user2']); - - $backend2->expects($this->once()) - ->method('usersInGroup') - ->with('group1') - ->willReturn(['user2', 'user3']); - - $users = $group->getUsers(); - - $this->assertEquals(3, count($users)); - $user1 = $users['user1']; - $user2 = $users['user2']; - $user3 = $users['user3']; - $this->assertEquals('user1', $user1->getUID()); - $this->assertEquals('user2', $user2->getUID()); - $this->assertEquals('user3', $user3->getUID()); - } - - public function testInGroupSingleBackend(): void { - $backend = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $userManager = $this->getUserManager(); - $userBackend = $this->getMockBuilder('\OC\User\Backend') - ->disableOriginalConstructor() - ->getMock(); - $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); - - $backend->expects($this->once()) - ->method('inGroup') - ->with('user1', 'group1') - ->willReturn(true); - - $this->assertTrue($group->inGroup($this->newUser('user1', $userBackend))); - } - - public function testInGroupMultipleBackends(): void { - $backend1 = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $backend2 = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $userManager = $this->getUserManager(); - $userBackend = $this->getMockBuilder(\OC\User\Backend::class) - ->disableOriginalConstructor() - ->getMock(); - $group = new \OC\Group\Group('group1', [$backend1, $backend2], $this->dispatcher, $userManager); - - $backend1->expects($this->once()) - ->method('inGroup') - ->with('user1', 'group1') - ->willReturn(false); - - $backend2->expects($this->once()) - ->method('inGroup') - ->with('user1', 'group1') - ->willReturn(true); - - $this->assertTrue($group->inGroup($this->newUser('user1', $userBackend))); - } - - public function testAddUser(): void { - $backend = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $userManager = $this->getUserManager(); - $userBackend = $this->getMockBuilder('\OC\User\Backend') - ->disableOriginalConstructor() - ->getMock(); - $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); - - $backend->expects($this->once()) - ->method('inGroup') - ->with('user1', 'group1') - ->willReturn(false); - $backend->expects($this->any()) - ->method('implementsActions') - ->willReturn(true); - - $backend->expects($this->once()) - ->method('addToGroup') - ->with('user1', 'group1'); - - $group->addUser($this->newUser('user1', $userBackend)); - } - - public function testAddUserAlreadyInGroup(): void { - $backend = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $userManager = $this->getUserManager(); - $userBackend = $this->getMockBuilder('\OC\User\Backend') - ->disableOriginalConstructor() - ->getMock(); - $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); - - $backend->expects($this->once()) - ->method('inGroup') - ->with('user1', 'group1') - ->willReturn(true); - $backend->expects($this->any()) - ->method('implementsActions') - ->willReturn(true); - - $backend->expects($this->never()) - ->method('addToGroup'); - - $group->addUser($this->newUser('user1', $userBackend)); - } - - public function testRemoveUser(): void { - $backend = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $userManager = $this->getUserManager(); - $userBackend = $this->getMockBuilder('\OC\User\Backend') - ->disableOriginalConstructor() - ->getMock(); - $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); - - $backend->expects($this->once()) - ->method('inGroup') - ->with('user1', 'group1') - ->willReturn(true); - $backend->expects($this->any()) - ->method('implementsActions') - ->willReturn(true); - - $backend->expects($this->once()) - ->method('removeFromGroup') - ->with('user1', 'group1'); - - $group->removeUser($this->newUser('user1', $userBackend)); - } - - public function testRemoveUserNotInGroup(): void { - $backend = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $userManager = $this->getUserManager(); - $userBackend = $this->getMockBuilder(\OC\User\Backend::class) - ->disableOriginalConstructor() - ->getMock(); - $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); - - $backend->expects($this->once()) - ->method('inGroup') - ->with('user1', 'group1') - ->willReturn(false); - $backend->expects($this->any()) - ->method('implementsActions') - ->willReturn(true); - - $backend->expects($this->never()) - ->method('removeFromGroup'); - - $group->removeUser($this->newUser('user1', $userBackend)); - } - - public function testRemoveUserMultipleBackends(): void { - $backend1 = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $backend2 = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $userManager = $this->getUserManager(); - $userBackend = $this->getMockBuilder('\OC\User\Backend') - ->disableOriginalConstructor() - ->getMock(); - $group = new \OC\Group\Group('group1', [$backend1, $backend2], $this->dispatcher, $userManager); - - $backend1->expects($this->once()) - ->method('inGroup') - ->with('user1', 'group1') - ->willReturn(true); - $backend1->expects($this->any()) - ->method('implementsActions') - ->willReturn(true); - - $backend1->expects($this->once()) - ->method('removeFromGroup') - ->with('user1', 'group1'); - - $backend2->expects($this->once()) - ->method('inGroup') - ->with('user1', 'group1') - ->willReturn(true); - $backend2->expects($this->any()) - ->method('implementsActions') - ->willReturn(true); - - $backend2->expects($this->once()) - ->method('removeFromGroup') - ->with('user1', 'group1'); - - $group->removeUser($this->newUser('user1', $userBackend)); - } - - public function testSearchUsers(): void { - $backend = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $userManager = $this->getUserManager(); - $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); - - $backend->expects($this->once()) - ->method('searchInGroup') - ->with('group1', '2') - ->willReturn(['user2' => new \OC\User\User('user2', null, $this->dispatcher)]); - - $users = $group->searchUsers('2'); - - $this->assertEquals(1, count($users)); - $user2 = reset($users); - $this->assertEquals('user2', $user2->getUID()); - } - - public function testSearchUsersMultipleBackends(): void { - $backend1 = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $backend2 = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $userManager = $this->getUserManager(); - $group = new \OC\Group\Group('group1', [$backend1, $backend2], $this->dispatcher, $userManager); - - $backend1->expects($this->once()) - ->method('searchInGroup') - ->with('group1', '2') - ->willReturn(['user2' => new \OC\User\User('user2', null, $this->dispatcher)]); - $backend2->expects($this->once()) - ->method('searchInGroup') - ->with('group1', '2') - ->willReturn(['user2' => new \OC\User\User('user2', null, $this->dispatcher)]); - - $users = $group->searchUsers('2'); - - $this->assertEquals(1, count($users)); - $user2 = reset($users); - $this->assertEquals('user2', $user2->getUID()); - } - - public function testSearchUsersLimitAndOffset(): void { - $backend = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $userManager = $this->getUserManager(); - $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); - - $backend->expects($this->once()) - ->method('searchInGroup') - ->with('group1', 'user', 1, 1) - ->willReturn(['user2' => new \OC\User\User('user2', null, $this->dispatcher)]); - - $users = $group->searchUsers('user', 1, 1); - - $this->assertEquals(1, count($users)); - $user2 = reset($users); - $this->assertEquals('user2', $user2->getUID()); - } - - public function testSearchUsersMultipleBackendsLimitAndOffset(): void { - $backend1 = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $backend2 = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $userManager = $this->getUserManager(); - $group = new \OC\Group\Group('group1', [$backend1, $backend2], $this->dispatcher, $userManager); - - $backend1->expects($this->once()) - ->method('searchInGroup') - ->with('group1', 'user', 2, 1) - ->willReturn(['user2' => new \OC\User\User('user2', null, $this->dispatcher)]); - $backend2->expects($this->once()) - ->method('searchInGroup') - ->with('group1', 'user', 2, 1) - ->willReturn(['user1' => new \OC\User\User('user1', null, $this->dispatcher)]); - - $users = $group->searchUsers('user', 2, 1); - - $this->assertEquals(2, count($users)); - $user2 = reset($users); - $user1 = next($users); - $this->assertEquals('user2', $user2->getUID()); - $this->assertEquals('user1', $user1->getUID()); - } - - public function testCountUsers(): void { - $backend1 = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $userManager = $this->getUserManager(); - $group = new \OC\Group\Group('group1', [$backend1], $this->dispatcher, $userManager); - - $backend1->expects($this->once()) - ->method('countUsersInGroup') - ->with('group1', '2') - ->willReturn(3); - - $backend1->expects($this->any()) - ->method('implementsActions') - ->willReturn(true); - - $users = $group->count('2'); - - $this->assertSame(3, $users); - } - - public function testCountUsersMultipleBackends(): void { - $backend1 = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $backend2 = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $userManager = $this->getUserManager(); - $group = new \OC\Group\Group('group1', [$backend1, $backend2], $this->dispatcher, $userManager); - - $backend1->expects($this->once()) - ->method('countUsersInGroup') - ->with('group1', '2') - ->willReturn(3); - $backend1->expects($this->any()) - ->method('implementsActions') - ->willReturn(true); - - $backend2->expects($this->once()) - ->method('countUsersInGroup') - ->with('group1', '2') - ->willReturn(4); - $backend2->expects($this->any()) - ->method('implementsActions') - ->willReturn(true); - - $users = $group->count('2'); - - $this->assertSame(7, $users); - } - - public function testCountUsersNoMethod(): void { - $backend1 = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $userManager = $this->getUserManager(); - $group = new \OC\Group\Group('group1', [$backend1], $this->dispatcher, $userManager); - - $backend1->expects($this->never()) - ->method('countUsersInGroup'); - $backend1->expects($this->any()) - ->method('implementsActions') - ->willReturn(false); - - $users = $group->count('2'); - - $this->assertSame(false, $users); - } - - public function testDelete(): void { - $backend = $this->getMockBuilder('OC\Group\Database') - ->disableOriginalConstructor() - ->getMock(); - $userManager = $this->getUserManager(); - $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); - - $backend->expects($this->once()) - ->method('deleteGroup') - ->with('group1'); - $backend->expects($this->any()) - ->method('implementsActions') - ->willReturn(true); - - $group->delete(); - } -} +<?php + +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\Group; + +use OC\User\User; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\IUser; +use PHPUnit\Framework\MockObject\MockObject; + +class GroupTest extends \Test\TestCase { + /** @var IEventDispatcher|MockObject */ + protected $dispatcher; + + protected function setUp(): void { + parent::setUp(); + $this->dispatcher = $this->createMock(IEventDispatcher::class); + } + + /** + * @param string $uid + * @param \OC\User\Backend $backend + * @return User + */ + private function newUser($uid, \OC\User\Backend $backend) { + $user = $this->createMock(IUser::class); + $user->method('getUID') + ->willReturn($uid); + $user->method('getBackend') + ->willReturn($backend); + + return $user; + } + + /** + * @return \OC\User\Manager + */ + protected function getUserManager() { + $userManager = $this->getMockBuilder(\OC\User\Manager::class) + ->disableOriginalConstructor() + ->getMock(); + $backend = $this->getMockBuilder(\OC\User\Backend::class) + ->disableOriginalConstructor() + ->getMock(); + $user1 = $this->newUser('user1', $backend); + $user2 = $this->newUser('user2', $backend); + $user3 = $this->newUser('user3', $backend); + $userManager->expects($this->any()) + ->method('get') + ->willReturnMap([ + ['user1', $user1], + ['user2', $user2], + ['user3', $user3] + ]); + return $userManager; + } + + public function testGetUsersSingleBackend(): void { + $backend = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $userManager = $this->getUserManager(); + $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); + + $backend->expects($this->once()) + ->method('usersInGroup') + ->with('group1') + ->willReturn(['user1', 'user2']); + + $users = $group->getUsers(); + + $this->assertEquals(2, count($users)); + $user1 = $users['user1']; + $user2 = $users['user2']; + $this->assertEquals('user1', $user1->getUID()); + $this->assertEquals('user2', $user2->getUID()); + } + + public function testGetUsersMultipleBackends(): void { + $backend1 = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $backend2 = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $userManager = $this->getUserManager(); + $group = new \OC\Group\Group('group1', [$backend1, $backend2], $this->dispatcher, $userManager); + + $backend1->expects($this->once()) + ->method('usersInGroup') + ->with('group1') + ->willReturn(['user1', 'user2']); + + $backend2->expects($this->once()) + ->method('usersInGroup') + ->with('group1') + ->willReturn(['user2', 'user3']); + + $users = $group->getUsers(); + + $this->assertEquals(3, count($users)); + $user1 = $users['user1']; + $user2 = $users['user2']; + $user3 = $users['user3']; + $this->assertEquals('user1', $user1->getUID()); + $this->assertEquals('user2', $user2->getUID()); + $this->assertEquals('user3', $user3->getUID()); + } + + public function testInGroupSingleBackend(): void { + $backend = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $userManager = $this->getUserManager(); + $userBackend = $this->getMockBuilder(\OC\User\Backend::class) + ->disableOriginalConstructor() + ->getMock(); + $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); + + $backend->expects($this->once()) + ->method('inGroup') + ->with('user1', 'group1') + ->willReturn(true); + + $this->assertTrue($group->inGroup($this->newUser('user1', $userBackend))); + } + + public function testInGroupMultipleBackends(): void { + $backend1 = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $backend2 = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $userManager = $this->getUserManager(); + $userBackend = $this->getMockBuilder(\OC\User\Backend::class) + ->disableOriginalConstructor() + ->getMock(); + $group = new \OC\Group\Group('group1', [$backend1, $backend2], $this->dispatcher, $userManager); + + $backend1->expects($this->once()) + ->method('inGroup') + ->with('user1', 'group1') + ->willReturn(false); + + $backend2->expects($this->once()) + ->method('inGroup') + ->with('user1', 'group1') + ->willReturn(true); + + $this->assertTrue($group->inGroup($this->newUser('user1', $userBackend))); + } + + public function testAddUser(): void { + $backend = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $userManager = $this->getUserManager(); + $userBackend = $this->getMockBuilder(\OC\User\Backend::class) + ->disableOriginalConstructor() + ->getMock(); + $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); + + $backend->expects($this->once()) + ->method('inGroup') + ->with('user1', 'group1') + ->willReturn(false); + $backend->expects($this->any()) + ->method('implementsActions') + ->willReturn(true); + + $backend->expects($this->once()) + ->method('addToGroup') + ->with('user1', 'group1'); + + $group->addUser($this->newUser('user1', $userBackend)); + } + + public function testAddUserAlreadyInGroup(): void { + $backend = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $userManager = $this->getUserManager(); + $userBackend = $this->getMockBuilder(\OC\User\Backend::class) + ->disableOriginalConstructor() + ->getMock(); + $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); + + $backend->expects($this->once()) + ->method('inGroup') + ->with('user1', 'group1') + ->willReturn(true); + $backend->expects($this->any()) + ->method('implementsActions') + ->willReturn(true); + + $backend->expects($this->never()) + ->method('addToGroup'); + + $group->addUser($this->newUser('user1', $userBackend)); + } + + public function testRemoveUser(): void { + $backend = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $userManager = $this->getUserManager(); + $userBackend = $this->getMockBuilder(\OC\User\Backend::class) + ->disableOriginalConstructor() + ->getMock(); + $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); + + $backend->expects($this->once()) + ->method('inGroup') + ->with('user1', 'group1') + ->willReturn(true); + $backend->expects($this->any()) + ->method('implementsActions') + ->willReturn(true); + + $backend->expects($this->once()) + ->method('removeFromGroup') + ->with('user1', 'group1'); + + $group->removeUser($this->newUser('user1', $userBackend)); + } + + public function testRemoveUserNotInGroup(): void { + $backend = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $userManager = $this->getUserManager(); + $userBackend = $this->getMockBuilder(\OC\User\Backend::class) + ->disableOriginalConstructor() + ->getMock(); + $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); + + $backend->expects($this->once()) + ->method('inGroup') + ->with('user1', 'group1') + ->willReturn(false); + $backend->expects($this->any()) + ->method('implementsActions') + ->willReturn(true); + + $backend->expects($this->never()) + ->method('removeFromGroup'); + + $group->removeUser($this->newUser('user1', $userBackend)); + } + + public function testRemoveUserMultipleBackends(): void { + $backend1 = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $backend2 = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $userManager = $this->getUserManager(); + $userBackend = $this->getMockBuilder(\OC\User\Backend::class) + ->disableOriginalConstructor() + ->getMock(); + $group = new \OC\Group\Group('group1', [$backend1, $backend2], $this->dispatcher, $userManager); + + $backend1->expects($this->once()) + ->method('inGroup') + ->with('user1', 'group1') + ->willReturn(true); + $backend1->expects($this->any()) + ->method('implementsActions') + ->willReturn(true); + + $backend1->expects($this->once()) + ->method('removeFromGroup') + ->with('user1', 'group1'); + + $backend2->expects($this->once()) + ->method('inGroup') + ->with('user1', 'group1') + ->willReturn(true); + $backend2->expects($this->any()) + ->method('implementsActions') + ->willReturn(true); + + $backend2->expects($this->once()) + ->method('removeFromGroup') + ->with('user1', 'group1'); + + $group->removeUser($this->newUser('user1', $userBackend)); + } + + public function testSearchUsers(): void { + $backend = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $userManager = $this->getUserManager(); + $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); + + $backend->expects($this->once()) + ->method('searchInGroup') + ->with('group1', '2') + ->willReturn(['user2' => new \OC\User\User('user2', null, $this->dispatcher)]); + + $users = $group->searchUsers('2'); + + $this->assertEquals(1, count($users)); + $user2 = reset($users); + $this->assertEquals('user2', $user2->getUID()); + } + + public function testSearchUsersMultipleBackends(): void { + $backend1 = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $backend2 = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $userManager = $this->getUserManager(); + $group = new \OC\Group\Group('group1', [$backend1, $backend2], $this->dispatcher, $userManager); + + $backend1->expects($this->once()) + ->method('searchInGroup') + ->with('group1', '2') + ->willReturn(['user2' => new \OC\User\User('user2', null, $this->dispatcher)]); + $backend2->expects($this->once()) + ->method('searchInGroup') + ->with('group1', '2') + ->willReturn(['user2' => new \OC\User\User('user2', null, $this->dispatcher)]); + + $users = $group->searchUsers('2'); + + $this->assertEquals(1, count($users)); + $user2 = reset($users); + $this->assertEquals('user2', $user2->getUID()); + } + + public function testSearchUsersLimitAndOffset(): void { + $backend = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $userManager = $this->getUserManager(); + $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); + + $backend->expects($this->once()) + ->method('searchInGroup') + ->with('group1', 'user', 1, 1) + ->willReturn(['user2' => new \OC\User\User('user2', null, $this->dispatcher)]); + + $users = $group->searchUsers('user', 1, 1); + + $this->assertEquals(1, count($users)); + $user2 = reset($users); + $this->assertEquals('user2', $user2->getUID()); + } + + public function testSearchUsersMultipleBackendsLimitAndOffset(): void { + $backend1 = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $backend2 = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $userManager = $this->getUserManager(); + $group = new \OC\Group\Group('group1', [$backend1, $backend2], $this->dispatcher, $userManager); + + $backend1->expects($this->once()) + ->method('searchInGroup') + ->with('group1', 'user', 2, 1) + ->willReturn(['user2' => new \OC\User\User('user2', null, $this->dispatcher)]); + $backend2->expects($this->once()) + ->method('searchInGroup') + ->with('group1', 'user', 2, 1) + ->willReturn(['user1' => new \OC\User\User('user1', null, $this->dispatcher)]); + + $users = $group->searchUsers('user', 2, 1); + + $this->assertEquals(2, count($users)); + $user2 = reset($users); + $user1 = next($users); + $this->assertEquals('user2', $user2->getUID()); + $this->assertEquals('user1', $user1->getUID()); + } + + public function testCountUsers(): void { + $backend1 = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $userManager = $this->getUserManager(); + $group = new \OC\Group\Group('group1', [$backend1], $this->dispatcher, $userManager); + + $backend1->expects($this->once()) + ->method('countUsersInGroup') + ->with('group1', '2') + ->willReturn(3); + + $backend1->expects($this->any()) + ->method('implementsActions') + ->willReturn(true); + + $users = $group->count('2'); + + $this->assertSame(3, $users); + } + + public function testCountUsersMultipleBackends(): void { + $backend1 = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $backend2 = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $userManager = $this->getUserManager(); + $group = new \OC\Group\Group('group1', [$backend1, $backend2], $this->dispatcher, $userManager); + + $backend1->expects($this->once()) + ->method('countUsersInGroup') + ->with('group1', '2') + ->willReturn(3); + $backend1->expects($this->any()) + ->method('implementsActions') + ->willReturn(true); + + $backend2->expects($this->once()) + ->method('countUsersInGroup') + ->with('group1', '2') + ->willReturn(4); + $backend2->expects($this->any()) + ->method('implementsActions') + ->willReturn(true); + + $users = $group->count('2'); + + $this->assertSame(7, $users); + } + + public function testCountUsersNoMethod(): void { + $backend1 = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $userManager = $this->getUserManager(); + $group = new \OC\Group\Group('group1', [$backend1], $this->dispatcher, $userManager); + + $backend1->expects($this->never()) + ->method('countUsersInGroup'); + $backend1->expects($this->any()) + ->method('implementsActions') + ->willReturn(false); + + $users = $group->count('2'); + + $this->assertSame(false, $users); + } + + public function testDelete(): void { + $backend = $this->getMockBuilder(\OC\Group\Database::class) + ->disableOriginalConstructor() + ->getMock(); + $userManager = $this->getUserManager(); + $group = new \OC\Group\Group('group1', [$backend], $this->dispatcher, $userManager); + + $backend->expects($this->once()) + ->method('deleteGroup') + ->with('group1'); + $backend->expects($this->any()) + ->method('implementsActions') + ->willReturn(true); + + $group->delete(); + } +} diff --git a/tests/lib/Group/MetaDataTest.php b/tests/lib/Group/MetaDataTest.php index 70f2022ae78..e42954a529d 100644 --- a/tests/lib/Group/MetaDataTest.php +++ b/tests/lib/Group/MetaDataTest.php @@ -18,7 +18,7 @@ class MetaDataTest extends \Test\TestCase { protected function setUp(): void { parent::setUp(); - $this->groupManager = $this->getMockBuilder('\OC\Group\Manager') + $this->groupManager = $this->getMockBuilder(\OC\Group\Manager::class) ->disableOriginalConstructor() ->getMock(); $this->userSession = $this->createMock(IUserSession::class); @@ -32,7 +32,7 @@ class MetaDataTest extends \Test\TestCase { } private function getGroupMock($countCallCount = 0) { - $group = $this->getMockBuilder('\OC\Group\Group') + $group = $this->getMockBuilder(\OC\Group\Group::class) ->disableOriginalConstructor() ->getMock(); diff --git a/tests/lib/HookHelper.php b/tests/lib/HookHelper.php index 8b7d17a6766..dcf5df771e3 100644 --- a/tests/lib/HookHelper.php +++ b/tests/lib/HookHelper.php @@ -20,38 +20,38 @@ class HookHelper { \OCP\Util::connectHook( Filesystem::CLASSNAME, Filesystem::signal_create, - '\Test\HookHelper', + \Test\HookHelper::class, 'createCallback' ); \OCP\Util::connectHook( Filesystem::CLASSNAME, Filesystem::signal_update, - '\Test\HookHelper', + \Test\HookHelper::class, 'updateCallback' ); \OCP\Util::connectHook( Filesystem::CLASSNAME, Filesystem::signal_write, - '\Test\HookHelper', + \Test\HookHelper::class, 'writeCallback' ); \OCP\Util::connectHook( Filesystem::CLASSNAME, Filesystem::signal_post_create, - '\Test\HookHelper', + \Test\HookHelper::class, 'postCreateCallback' ); \OCP\Util::connectHook( Filesystem::CLASSNAME, Filesystem::signal_post_update, - '\Test\HookHelper', + \Test\HookHelper::class, 'postUpdateCallback' ); \OCP\Util::connectHook( Filesystem::CLASSNAME, Filesystem::signal_post_write, - '\Test\HookHelper', + \Test\HookHelper::class, 'postWriteCallback' ); } diff --git a/tests/lib/Hooks/BasicEmitterTest.php b/tests/lib/Hooks/BasicEmitterTest.php index 98f746d38ae..b9f86865cea 100644 --- a/tests/lib/Hooks/BasicEmitterTest.php +++ b/tests/lib/Hooks/BasicEmitterTest.php @@ -63,7 +63,7 @@ class BasicEmitterTest extends \Test\TestCase { public function testStaticCallback(): void { $this->expectException(\Test\Hooks\EmittedException::class); - $this->emitter->listen('Test', 'test', ['\Test\Hooks\BasicEmitterTest', 'staticCallBack']); + $this->emitter->listen('Test', 'test', [\Test\Hooks\BasicEmitterTest::class, 'staticCallBack']); $this->emitter->emitEvent('Test', 'test'); } diff --git a/tests/lib/ImageTest.php b/tests/lib/ImageTest.php index 76b110df521..4c56623cbf8 100644 --- a/tests/lib/ImageTest.php +++ b/tests/lib/ImageTest.php @@ -23,27 +23,27 @@ class ImageTest extends \Test\TestCase { public function testConstructDestruct(): void { $img = new Image(); $img->loadFromFile(OC::$SERVERROOT.'/tests/data/testimage.png'); - $this->assertInstanceOf('\OC\Image', $img); - $this->assertInstanceOf('\OCP\IImage', $img); + $this->assertInstanceOf(\OC\Image::class, $img); + $this->assertInstanceOf(\OCP\IImage::class, $img); unset($img); $imgcreate = imagecreatefromjpeg(OC::$SERVERROOT.'/tests/data/testimage.jpg'); $img = new Image(); $img->setResource($imgcreate); - $this->assertInstanceOf('\OC\Image', $img); - $this->assertInstanceOf('\OCP\IImage', $img); + $this->assertInstanceOf(\OC\Image::class, $img); + $this->assertInstanceOf(\OCP\IImage::class, $img); unset($img); $base64 = base64_encode(file_get_contents(OC::$SERVERROOT.'/tests/data/testimage.gif')); $img = new Image(); $img->loadFromBase64($base64); - $this->assertInstanceOf('\OC\Image', $img); - $this->assertInstanceOf('\OCP\IImage', $img); + $this->assertInstanceOf(\OC\Image::class, $img); + $this->assertInstanceOf(\OCP\IImage::class, $img); unset($img); $img = new Image(); - $this->assertInstanceOf('\OC\Image', $img); - $this->assertInstanceOf('\OCP\IImage', $img); + $this->assertInstanceOf(\OC\Image::class, $img); + $this->assertInstanceOf(\OCP\IImage::class, $img); unset($img); } diff --git a/tests/lib/IntegrityCheck/CheckerTest.php b/tests/lib/IntegrityCheck/CheckerTest.php index 8d579cda529..be952765077 100644 --- a/tests/lib/IntegrityCheck/CheckerTest.php +++ b/tests/lib/IntegrityCheck/CheckerTest.php @@ -1,1153 +1,1153 @@ -<?php -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-only - */ - -namespace Test\IntegrityCheck; - -use OC\Core\Command\Maintenance\Mimetype\GenerateMimetypeFileBuilder; -use OC\IntegrityCheck\Checker; -use OC\IntegrityCheck\Helpers\AppLocator; -use OC\IntegrityCheck\Helpers\EnvironmentHelper; -use OC\IntegrityCheck\Helpers\FileAccessHelper; -use OC\Memcache\NullCache; -use OCP\App\IAppManager; -use OCP\IAppConfig; -use OCP\ICacheFactory; -use OCP\IConfig; -use phpseclib\Crypt\RSA; -use phpseclib\File\X509; -use Test\TestCase; - -class CheckerTest extends TestCase { - /** @var EnvironmentHelper|\PHPUnit\Framework\MockObject\MockObject */ - private $environmentHelper; - /** @var AppLocator|\PHPUnit\Framework\MockObject\MockObject */ - private $appLocator; - /** @var Checker */ - private $checker; - /** @var FileAccessHelper|\PHPUnit\Framework\MockObject\MockObject */ - private $fileAccessHelper; - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ - private $config; - /** @var IAppConfig|\PHPUnit\Framework\MockObject\MockObject */ - private $appConfig; - /** @var ICacheFactory|\PHPUnit\Framework\MockObject\MockObject */ - private $cacheFactory; - /** @var IAppManager|\PHPUnit\Framework\MockObject\MockObject */ - private $appManager; - /** @var \OC\Files\Type\Detection|\PHPUnit\Framework\MockObject\MockObject */ - private $mimeTypeDetector; - - protected function setUp(): void { - parent::setUp(); - $this->environmentHelper = $this->createMock(EnvironmentHelper::class); - $this->fileAccessHelper = $this->createMock(FileAccessHelper::class); - $this->appLocator = $this->createMock(AppLocator::class); - $this->config = $this->createMock(IConfig::class); - $this->appConfig = $this->createMock(IAppConfig::class); - $this->cacheFactory = $this->createMock(ICacheFactory::class); - $this->appManager = $this->createMock(IAppManager::class); - $this->mimeTypeDetector = $this->createMock(\OC\Files\Type\Detection::class); - - $this->config->method('getAppValue') - ->willReturnArgument(2); - - $this->cacheFactory - ->expects($this->any()) - ->method('createDistributed') - ->with('oc.integritycheck.checker') - ->willReturn(new NullCache()); - - $this->checker = new Checker( - $this->environmentHelper, - $this->fileAccessHelper, - $this->appLocator, - $this->config, - $this->appConfig, - $this->cacheFactory, - $this->appManager, - $this->mimeTypeDetector - ); - } - - - public function testWriteAppSignatureOfNotExistingApp(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Exception message'); - - $this->fileAccessHelper - ->expects($this->once()) - ->method('assertDirectoryExists') - ->with('NotExistingApp/appinfo') - ->willThrowException(new \Exception('Exception message')); - $this->fileAccessHelper - ->expects($this->once()) - ->method('is_writable') - ->with('NotExistingApp/appinfo') - ->willReturn(true); - - $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.crt'); - $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.key'); - $rsa = new RSA(); - $rsa->loadKey($rsaPrivateKey); - $x509 = new X509(); - $x509->loadX509($keyBundle); - $this->checker->writeAppSignature('NotExistingApp', $x509, $rsa); - } - - - public function testWriteAppSignatureWrongPermissions(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessageMatches('/[a-zA-Z\\/_-]+ is not writable/'); - - $this->fileAccessHelper - ->expects($this->once()) - ->method('file_put_contents') - ->will($this->throwException(new \Exception('Exception message'))); - - $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.crt'); - $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.key'); - $rsa = new RSA(); - $rsa->loadKey($rsaPrivateKey); - $x509 = new X509(); - $x509->loadX509($keyBundle); - $this->checker->writeAppSignature(\OC::$SERVERROOT . '/tests/data/integritycheck/app/', $x509, $rsa); - } - - public function testWriteAppSignature(): void { - $expectedSignatureFileData = '{ - "hashes": { - "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", - "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" - }, - "signature": "Y5yvXvcGHVPuRRatKVDUONWq1FpLXugZd6Km\/+aEHsQj7coVl9FeMj9OsWamBf7yRIw3dtNLguTLlAA9QAv\/b0uHN3JnbNZN+dwFOve4NMtqXfSDlWftqKN00VS+RJXpG1S2IIx9Poyp2NoghL\/5AuTv4GHiNb7zU\/DT\/kt71pUGPgPR6IIFaE+zHOD96vjYkrH+GfWZzKR0FCdLib9yyNvk+EGrcjKM6qjs2GKfS\/XFjj\/\/neDnh\/0kcPuKE3ZbofnI4TIDTv0CGqvOp7PtqVNc3Vy\/UKa7uF1PT0MAUKMww6EiMUSFZdUVP4WWF0Y72W53Qdtf1hrAZa2kfKyoK5kd7sQmCSKUPSU8978AUVZlBtTRlyT803IKwMV0iHMkw+xYB1sN2FlHup\/DESADqxhdgYuK35bCPvgkb4SBe4B8Voz\/izTvcP7VT5UvkYdAO+05\/jzdaHEmzmsD92CFfvX0q8O\/Y\/29ubftUJsqcHeMDKgcR4eZOE8+\/QVc\/89QO6WnKNuNuV+5bybO6g6PAdC9ZPsCvnihS61O2mwRXHLR3jv2UleFWm+lZEquPKtkhi6SLtDiijA4GV6dmS+dzujSLb7hGeD5o1plZcZ94uhWljl+QIp82+zU\/lYB1Zfr4Mb4e+V7r2gv7Fbv7y6YtjE2GIQwRhC5jq56bD0ZB+I=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEwTCCAqmgAwIBAgIUWv0iujufs5lUr0svCf\/qTQvoyKAwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIyNDk1M1oXDTE2MTEwMzIyNDk1M1owEjEQMA4GA1UEAwwHU29tZUFwcDCCAiIw\r\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK8q0x62agGSRBqeWsaeEwFfepMk\r\nF8cAobMMi50qHCv9IrOn\/ZH9l52xBrbIkErVmRjmly0d4JhD8Ymhidsh9ONKYl\/j\r\n+ishsZDM8eNNdp3Ew+fEYVvY1W7mR1qU24NWj0bzVsClI7hvPVIuw7AjfBDq1C5+\r\nA+ZSLSXYvOK2cEWjdxQfuNZwEZSjmA63DUllBIrm35IaTvfuyhU6BW9yHZxmb8+M\r\nw0xDv30D5UkE\/2N7Pa\/HQJLxCR+3zKibRK3nUyRDLSXxMkU9PnFNaPNX59VPgyj4\r\nGB1CFSToldJVPF4pzh7p36uGXZVxs8m3LFD4Ol8mhi7jkxDZjqFN46gzR0r23Py6\r\ndol9vfawGIoUwp9LvL0S7MvdRY0oazLXwClLP4OQ17zpSMAiCj7fgNT661JamPGj\r\nt5O7Zn2wA7I4ddDS\/HDTWCu98Zwc9fHIpsJPgCZ9awoqxi4Mnf7Pk9g5nnXhszGC\r\ncxxIASQKM+GhdzoRxKknax2RzUCwCzcPRtCj8AQT\/x\/mqN3PfRmlnFBNACUw9bpZ\r\nSOoNq2pCF9igftDWpSIXQ38pVpKLWowjjg3DVRmVKBgivHnUnVLyzYBahHPj0vaz\r\ntFtUFRaqXDnt+4qyUGyrT5h5pjZaTcHIcSB4PiarYwdVvgslgwnQzOUcGAzRWBD4\r\n6jV2brP5vFY3g6iPAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBACTY3CCHC+Z28gCf\r\nFWGKQ3wAKs+k4+0yoti0qm2EKX7rSGQ0PHSas6uW79WstC4Rj+DYkDtIhGMSg8FS\r\nHVGZHGBCc0HwdX+BOAt3zi4p7Sf3oQef70\/4imPoKxbAVCpd\/cveVcFyDC19j1yB\r\nBapwu87oh+muoeaZxOlqQI4UxjBlR\/uRSMhOn2UGauIr3dWJgAF4pGt7TtIzt+1v\r\n0uA6FtN1Y4R5O8AaJPh1bIG0CVvFBE58esGzjEYLhOydgKFnEP94kVPgJD5ds9C3\r\npPhEpo1dRpiXaF7WGIV1X6DI\/ipWvfrF7CEy6I\/kP1InY\/vMDjQjeDnJ\/VrXIWXO\r\nyZvHXVaN\/m+1RlETsH7YO\/QmxRue9ZHN3gvvWtmpCeA95sfpepOk7UcHxHZYyQbF\r\n49\/au8j+5tsr4A83xzsT1JbcKRxkAaQ7WDJpOnE5O1+H0fB+BaLakTg6XX9d4Fo7\r\n7Gin7hVWX7pL+JIyxMzME3LhfI61+CRcqZQIrpyaafUziPQbWIPfEs7h8tCOWyvW\r\nUO8ZLervYCB3j44ivkrxPlcBklDCqqKKBzDP9dYOtS\/P4RB1NkHA9+NTvmBpTonS\r\nSFXdg9fFMD7VfjDE3Vnk+8DWkVH5wBYowTAD7w9Wuzr7DumiAULexnP\/Y7xwxLv7\r\n4B+pXTAcRK0zECDEaX3npS8xWzrB\r\n-----END CERTIFICATE-----" -}'; - $this->fileAccessHelper - ->expects($this->once()) - ->method('file_put_contents') - ->with( - $this->equalTo(\OC::$SERVERROOT . '/tests/data/integritycheck/app//appinfo/signature.json'), - $this->callback(function ($signature) use ($expectedSignatureFileData) { - $expectedArray = json_decode($expectedSignatureFileData, true); - $actualArray = json_decode($signature, true); - $this->assertEquals($expectedArray, $actualArray); - return true; - }) - ); - - $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.crt'); - $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.key'); - $rsa = new RSA(); - $rsa->loadKey($rsaPrivateKey); - $x509 = new X509(); - $x509->loadX509($keyBundle); - $this->checker->writeAppSignature(\OC::$SERVERROOT . '/tests/data/integritycheck/app/', $x509, $rsa); - } - - public function testVerifyAppSignatureWithoutSignatureData(): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn('stable'); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(false); - - $expected = [ - 'EXCEPTION' => [ - 'class' => 'OC\IntegrityCheck\Exceptions\InvalidSignatureException', - 'message' => 'Signature data not found.', - ], - ]; - $this->assertSame($expected, $this->checker->verifyAppSignature('SomeApp')); - } - - public function testVerifyAppSignatureWithValidSignatureData(): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn('stable'); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(false); - - $this->appLocator - ->expects($this->once()) - ->method('getAppPath') - ->with('SomeApp') - ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'); - $signatureDataFile = '{ - "hashes": { - "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", - "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" - }, - "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" -}'; - $this->fileAccessHelper - ->expects($this->exactly(2)) - ->method('file_get_contents') - ->withConsecutive( - [\OC::$SERVERROOT . '/tests/data/integritycheck/app//appinfo/signature.json'], - ['/resources/codesigning/root.crt'], - ) - ->willReturnOnConsecutiveCalls( - $signatureDataFile, - file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') - ); - - $this->assertSame([], $this->checker->verifyAppSignature('SomeApp')); - } - - public function testVerifyAppSignatureWithTamperedSignatureData(): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn('stable'); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(false); - - $this->appLocator - ->expects($this->once()) - ->method('getAppPath') - ->with('SomeApp') - ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'); - $signatureDataFile = '{ - "hashes": { - "AnotherFile.txt": "tampered", - "subfolder\/file.txt": "tampered" - }, - "signature": "EL49UaSeyMAqyMtqId+tgOhhwgOevPZsRLX4j2blnybAB6fN07z0936JqZV7+eMPiE30Idx+UCY6rCFN531Kqe9vAOCdgtHUSOjjKyKc+lvULESlMb6YQcrZrvDlEMMjzjH49ewG7Ai8sNN6HrRUd9U8ws+ewSkW2DOOBItj\/21RBnkrSt+2AtGXGigEvuTm57HrCYDj8\/lSkumC2GVkjLUHeLOKYo4PRNOr6yP5mED5v7zo66AWvXl2fKv54InZcdxsAk35lyK9DGZbk\/027ZRd0AOHT3LImRLvQ+8EAg3XLlRUy0hOFGgPC+jYonMzgYvsAXAXi2j8LnLJlsLwpFwu1k1B+kZVPMumKZvP9OvJb70EirecXmz62V+Jiyuaq7ne4y7Kp5gKZT\/T8SeZ0lFtCmPfYyzBB0y8s5ldmTTmdVYHs54t\/OCCW82HzQZxnFNPzDTRa8HglsaMKrqPtW59+R4UvRKSWhB8M\/Ah57qgzycvPV4KMz\/FbD4l\/\/9chRKSlCfc2k3b8ZSHNmi+EzCKgJjWIoKdgN1yax94puU8jfn8UW+G7H9Y1Jsf\/jox6QLyYEgtV1vOHY2xLT7fVs2vhyvkN2MNjJnmQ70gFG5Qz2lBz5wi6ZpB+tOfCcpbLxWAkoWoIrmC\/Ilqh7mfmRZ43g5upjkepHNd93ONuY8=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEwTCCAqmgAwIBAgIUWv0iujufs5lUr0svCf\/qTQvoyKAwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIyNDk1M1oXDTE2MTEwMzIyNDk1M1owEjEQMA4GA1UEAwwHU29tZUFwcDCCAiIw\r\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK8q0x62agGSRBqeWsaeEwFfepMk\r\nF8cAobMMi50qHCv9IrOn\/ZH9l52xBrbIkErVmRjmly0d4JhD8Ymhidsh9ONKYl\/j\r\n+ishsZDM8eNNdp3Ew+fEYVvY1W7mR1qU24NWj0bzVsClI7hvPVIuw7AjfBDq1C5+\r\nA+ZSLSXYvOK2cEWjdxQfuNZwEZSjmA63DUllBIrm35IaTvfuyhU6BW9yHZxmb8+M\r\nw0xDv30D5UkE\/2N7Pa\/HQJLxCR+3zKibRK3nUyRDLSXxMkU9PnFNaPNX59VPgyj4\r\nGB1CFSToldJVPF4pzh7p36uGXZVxs8m3LFD4Ol8mhi7jkxDZjqFN46gzR0r23Py6\r\ndol9vfawGIoUwp9LvL0S7MvdRY0oazLXwClLP4OQ17zpSMAiCj7fgNT661JamPGj\r\nt5O7Zn2wA7I4ddDS\/HDTWCu98Zwc9fHIpsJPgCZ9awoqxi4Mnf7Pk9g5nnXhszGC\r\ncxxIASQKM+GhdzoRxKknax2RzUCwCzcPRtCj8AQT\/x\/mqN3PfRmlnFBNACUw9bpZ\r\nSOoNq2pCF9igftDWpSIXQ38pVpKLWowjjg3DVRmVKBgivHnUnVLyzYBahHPj0vaz\r\ntFtUFRaqXDnt+4qyUGyrT5h5pjZaTcHIcSB4PiarYwdVvgslgwnQzOUcGAzRWBD4\r\n6jV2brP5vFY3g6iPAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBACTY3CCHC+Z28gCf\r\nFWGKQ3wAKs+k4+0yoti0qm2EKX7rSGQ0PHSas6uW79WstC4Rj+DYkDtIhGMSg8FS\r\nHVGZHGBCc0HwdX+BOAt3zi4p7Sf3oQef70\/4imPoKxbAVCpd\/cveVcFyDC19j1yB\r\nBapwu87oh+muoeaZxOlqQI4UxjBlR\/uRSMhOn2UGauIr3dWJgAF4pGt7TtIzt+1v\r\n0uA6FtN1Y4R5O8AaJPh1bIG0CVvFBE58esGzjEYLhOydgKFnEP94kVPgJD5ds9C3\r\npPhEpo1dRpiXaF7WGIV1X6DI\/ipWvfrF7CEy6I\/kP1InY\/vMDjQjeDnJ\/VrXIWXO\r\nyZvHXVaN\/m+1RlETsH7YO\/QmxRue9ZHN3gvvWtmpCeA95sfpepOk7UcHxHZYyQbF\r\n49\/au8j+5tsr4A83xzsT1JbcKRxkAaQ7WDJpOnE5O1+H0fB+BaLakTg6XX9d4Fo7\r\n7Gin7hVWX7pL+JIyxMzME3LhfI61+CRcqZQIrpyaafUziPQbWIPfEs7h8tCOWyvW\r\nUO8ZLervYCB3j44ivkrxPlcBklDCqqKKBzDP9dYOtS\/P4RB1NkHA9+NTvmBpTonS\r\nSFXdg9fFMD7VfjDE3Vnk+8DWkVH5wBYowTAD7w9Wuzr7DumiAULexnP\/Y7xwxLv7\r\n4B+pXTAcRK0zECDEaX3npS8xWzrB\r\n-----END CERTIFICATE-----" -}'; - $this->fileAccessHelper - ->expects($this->exactly(2)) - ->method('file_get_contents') - ->withConsecutive( - [\OC::$SERVERROOT . '/tests/data/integritycheck/app//appinfo/signature.json'], - ['/resources/codesigning/root.crt'], - ) - ->willReturnOnConsecutiveCalls( - $signatureDataFile, - file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') - ); - - $expected = [ - 'EXCEPTION' => [ - 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', - 'message' => 'Signature could not get verified.', - ], - ]; - $this->assertEquals($expected, $this->checker->verifyAppSignature('SomeApp')); - } - - public function testVerifyAppSignatureWithTamperedFiles(): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn('stable'); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(false); - - $this->appLocator - ->expects($this->once()) - ->method('getAppPath') - ->with('SomeApp') - ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData/'); - $signatureDataFile = '{ - "hashes": { - "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", - "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" - }, - "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" -}'; - $this->fileAccessHelper - ->expects($this->exactly(2)) - ->method('file_get_contents') - ->withConsecutive( - [\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//appinfo/signature.json'], - ['/resources/codesigning/root.crt'], - ) - ->willReturnOnConsecutiveCalls( - $signatureDataFile, - file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') - ); - - - $expected = [ - 'INVALID_HASH' => [ - 'AnotherFile.txt' => [ - 'expected' => '1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112', - 'current' => '7322348ba269c6d5522efe02f424fa3a0da319a7cd9c33142a5afe32a2d9af2da3a411f086fcfc96ff4301ea566f481dba0960c2abeef3594c4d930462f6584c', - ], - ], - 'FILE_MISSING' => [ - 'subfolder/file.txt' => [ - 'expected' => '410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b', - 'current' => '', - ], - ], - 'EXTRA_FILE' => [ - 'UnecessaryFile' => [ - 'expected' => '', - 'current' => 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e', - ], - ], - - ]; - $this->assertSame($expected, $this->checker->verifyAppSignature('SomeApp')); - } - - public function testVerifyAppSignatureWithTamperedFilesAndAlternatePath(): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn('stable'); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(false); - - $this->appLocator - ->expects($this->never()) - ->method('getAppPath') - ->with('SomeApp'); - $signatureDataFile = '{ - "hashes": { - "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", - "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" - }, - "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" -}'; - $this->fileAccessHelper - ->expects($this->exactly(2)) - ->method('file_get_contents') - ->withConsecutive( - [\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//appinfo/signature.json'], - ['/resources/codesigning/root.crt'], - ) - ->willReturnOnConsecutiveCalls( - $signatureDataFile, - file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') - ); - - - $expected = [ - 'INVALID_HASH' => [ - 'AnotherFile.txt' => [ - 'expected' => '1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112', - 'current' => '7322348ba269c6d5522efe02f424fa3a0da319a7cd9c33142a5afe32a2d9af2da3a411f086fcfc96ff4301ea566f481dba0960c2abeef3594c4d930462f6584c', - ], - ], - 'FILE_MISSING' => [ - 'subfolder/file.txt' => [ - 'expected' => '410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b', - 'current' => '', - ], - ], - 'EXTRA_FILE' => [ - 'UnecessaryFile' => [ - 'expected' => '', - 'current' => 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e', - ], - ], - - ]; - $this->assertSame($expected, $this->checker->verifyAppSignature('SomeApp', \OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData/')); - } - - public function testVerifyAppWithDifferentScope(): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn('stable'); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(false); - - $this->appLocator - ->expects($this->once()) - ->method('getAppPath') - ->with('SomeApp') - ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData/'); - $signatureDataFile = '{ - "hashes": { - "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", - "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" - }, - "signature": "eXesvDm3pkek12xSwMG10y9suRES79Nye3jYNe5KYq1tTUPqRRNgxmMGAfcUro0zpLeAr2YgHeSMWtglblGOW7pmwGVPZ0O1Y4r1fE6jnep0kW+35PLIaqCorIOnCAtSzDNKBhwd1ow3zW2wC0DFouuEkIO8u5Fw28g8E8dp8zEk1xMblNPy+xtWkmYHrVJ\/dQgun1bYOF2ZFtAzatwndTI\/bGsy1i3Wsl+x6HyWKQdq8y8VObtOqKDH7uERBEpB9DHVyKflj1v1gQuEH6BhaRdATc7ee0MiQdGblraIySwYRdfo2d8i82OVKrenMB3SLwyCvDPyQ9iKpTOnSF52ZBqaqSXKM2N\/RAkweeBFQQCwcHhqxvB0cfbyHcbkOLeCZe\/tsh68IxwTiYgzvLfl7sOZ5arnZbzrPpZmB+hfV2omkoJ1tDwOWz9hEmLLNtfo2OxyUH1m0+XFaC+Gbn4WkVDgf7YZkwUcG+Qoa3oKDNMss8MEyZxewl2iDGZcf402dlidHRprlfmXbAYuVQ08\/a0HxIKYPGh\/nsMGmwnO15CWtFpAbhUA\/D5oRjsIxnvXaMDg0iAFpdu\/5Ffsj7g3EPdBkiQHNYK7YU1RRx609eH0bZyiIYHdUPw7ikLupvrebZmELqi3mqDFO99u4eISlxFJlUbUND3L4BtmWTWrKwI=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIExjCCAq6gAwIBAgIUHSJjhJqMwr+3TkoiQFg4SVVYQ1gwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIzMjc1NVoXDTE2MTEwMzIzMjc1NVowFzEVMBMGA1UEAwwMQW5vdGhlclNjb3Bl\r\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA33npb5RmUkXrDT+TbwMf\r\n0zQ33SlzsjoGxCrbSwJOn6leGGInJ6ZrdzLL0WTi\/dTpg+Y\/JS+72XWm5NSjaTxo\r\n7OHc3cQBwXQj4tN6j\/y5qqY0GDLYufEkx2rpazqt9lBSJ72u1bGl2yoOXzYCz5i0\r\n60KsJXC9K44LKzGsarzbwAgskSVNkjAsPgjnCWZmcl6icpLi5Fz9rs2UMOWbdvdI\r\nAROsn0eC9E\/akmXTy5YMu6bAIGpvjZFHzyA83FQRbvv5o1V5Gsye\/VQLEgh7rqfz\r\nT\/jgWifP+JgoeB6otzuRZ3fFsmbBiyCIRtIOzQQflozhUlWtmiEGwg4GySuMUjEH\r\nA1LF86LO+ZzDQgd2oYNKmrQ8O+EcLqx9BpV4AFhEvqdk7uycJYPHs6yl+yfbzTeJ\r\n2Xd0yVAfd9r\/iDr36clLj2bzEObdl9xzKjcCIXE4Q0G4Pur41\/BJUDK9PI390ccQ\r\nnFjjVYBMsC859OwW64tMP0zkM9Vv72LCaEzaR8jqH0j11catqxunr+StfMcmxLTN\r\nbqBJbSEq4ER3mJxCTI2UrIVmdQ7+wRxgv3QTDNOZyqrz2L8A1Rpb3h0APxtQv+oA\r\n8KIZYID5\/qsS2V2jITkMQ8Nd1W3b0cZhZ600z+znh3jLJ0TYLvwN6\/qBQTUDaM2o\r\ng1+icMqXIXIeKuoPCVVsG7cCAwEAATANBgkqhkiG9w0BAQUFAAOCAgEAHc4F\/kOV\r\nHc8In5MmGg2YtjwZzjdeoC5TIPZczRqz0B+wRbJzN6aYryKZKLmP+wKpgRnJWDzp\r\nrgKGyyEQIAfK63DEv4B9p4N1B+B3aeMKsSpVcw7wbFTD57V5A7pURGoo31d0mw5L\r\nUIXZ2u+TUfGbzucMxLdFhTwjGpz9M6Kkm\/POxmV0tvLija5LdbdKnYR9BFmyu4IX\r\nqyoIAtComATNLl+3URu3SZxhE3NxhzMz+eAeNfh1KuIf2gWIIeDCXalVSJLym+OQ\r\nHFDpqRhJqfTMprrRlmmU7Zntgbj8\/RRZuXnBvH9cQ2KykLOb4UoCPlGUqOqKyP9m\r\nDJSFRiMJfpgMQUaJk1TLhKF+IR6FnmwURLEtkONJumtDQju9KaWPlhueONdyGi0p\r\nqxLVUo1Vb52XnPhk2GEEduxpDc9V5ePJ+pdcEdMifY\/uPNBRuBj2c87yq1DLH+U4\r\n3XzP1MlwjnBWZYuoFo0j6Jq0r\/MG6HjGdmkGIsRoheRi8Z8Scz5AW5QRkNz8pKop\r\nTELFqQy9g6TyQzzC8t6HZcpNe842ZUk4raEAbCZe\/XqxWMw5svPgNceBqM3fh7sZ\r\nBSykOHLaL8kiRO\/IS3y1yZEAuiWBvtxcTNLzBb+hdRpm2y8\/qH\/pKo+CMj1VzjNT\r\nD8YRQg0cjmDytJzHDrtV\/aTc9W1aPHun0vw=\r\n-----END CERTIFICATE-----" -}'; - $this->fileAccessHelper - ->expects($this->exactly(2)) - ->method('file_get_contents') - ->withConsecutive( - [\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//appinfo/signature.json'], - ['/resources/codesigning/root.crt'], - )->willReturnOnConsecutiveCalls( - $signatureDataFile, - file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') - ); - - $expected = [ - 'EXCEPTION' => [ - 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', - 'message' => 'Certificate is not valid for required scope. (Requested: SomeApp, current: CN=AnotherScope)', - ], - ]; - $this->assertSame($expected, $this->checker->verifyAppSignature('SomeApp')); - } - - public function testVerifyAppWithDifferentScopeAndAlwaysTrustedCore(): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn('stable'); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(false); - - $this->appLocator - ->expects($this->once()) - ->method('getAppPath') - ->with('SomeApp') - ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'); - $signatureDataFile = '{ - "hashes": { - "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", - "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" - }, - "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" -}'; - $this->fileAccessHelper - ->expects($this->exactly(2)) - ->method('file_get_contents') - ->withConsecutive( - [\OC::$SERVERROOT . '/tests/data/integritycheck/app//appinfo/signature.json'], - ['/resources/codesigning/root.crt'], - )->willReturnOnConsecutiveCalls( - $signatureDataFile, - file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') - ); - - $this->assertSame([], $this->checker->verifyAppSignature('SomeApp')); - } - - - public function testWriteCoreSignatureWithException(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Exception message'); - - $this->fileAccessHelper - ->expects($this->once()) - ->method('assertDirectoryExists') - ->will($this->throwException(new \Exception('Exception message'))); - $this->fileAccessHelper - ->expects($this->once()) - ->method('is_writable') - ->with(__DIR__ . '/core') - ->willReturn(true); - - $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.crt'); - $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.key'); - $rsa = new RSA(); - $rsa->loadKey($rsaPrivateKey); - $x509 = new X509(); - $x509->loadX509($keyBundle); - $this->checker->writeCoreSignature($x509, $rsa, __DIR__); - } - - - public function testWriteCoreSignatureWrongPermissions(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessageMatches('/[a-zA-Z\\/_-]+ is not writable/'); - - $this->fileAccessHelper - ->expects($this->once()) - ->method('assertDirectoryExists') - ->will($this->throwException(new \Exception('Exception message'))); - $this->fileAccessHelper - ->expects($this->once()) - ->method('is_writable') - ->with(__DIR__ . '/core') - ->willReturn(false); - - $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.crt'); - $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.key'); - $rsa = new RSA(); - $rsa->loadKey($rsaPrivateKey); - $x509 = new X509(); - $x509->loadX509($keyBundle); - $this->checker->writeCoreSignature($x509, $rsa, __DIR__); - } - - public function testWriteCoreSignature(): void { - $expectedSignatureFileData = '{ - "hashes": { - "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", - "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" - }, - "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" -}'; - $this->environmentHelper - ->expects($this->any()) - ->method('getServerRoot') - ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'); - $this->fileAccessHelper - ->expects($this->once()) - ->method('file_put_contents') - ->with( - \OC::$SERVERROOT . '/tests/data/integritycheck/app//core/signature.json', - $this->callback(function ($signature) use ($expectedSignatureFileData) { - $expectedArray = json_decode($expectedSignatureFileData, true); - $actualArray = json_decode($signature, true); - $this->assertEquals($expectedArray, $actualArray); - return true; - }) - ); - - $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/core.crt'); - $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/core.key'); - $rsa = new RSA(); - $rsa->loadKey($rsaPrivateKey); - $x509 = new X509(); - $x509->loadX509($keyBundle); - $this->checker->writeCoreSignature($x509, $rsa, \OC::$SERVERROOT . '/tests/data/integritycheck/app/'); - } - - public function testWriteCoreSignatureWithUnmodifiedHtaccess(): void { - $expectedSignatureFileData = '{ - "hashes": { - ".htaccess": "dc479770a6232061e04a768ee1f9133fdb3aea7b3a99f7105b0e0b6197474733e8d14b5b2bbad054e6b62a410fe5d0b3d790242dee1e0f11274af2100f5289e2", - "subfolder\/.htaccess": "2c57b1e25050e11dc3ae975832f378c452159f7b69f818e47eeeafadd6ba568517461dcb4d843b90b906cd7c89d161bc1b89dff8e3ae0eb6f5088508c47befd1" - }, - "signature": "nRtR377DB\/I\/4hmh9q3elMQYfSHnQFlNtjchNgrdfmUQqVmgkU\/4qgGyxDqYkV8mSMbH2gYysfP42nx\/3zSo7n0dBYDfU87Q6f96Cv597vEV27do8CaBkEk8Xjn2SxhHw8hVxracvE2OBAPxk0H3sRp\/cQBgjoXpju4kQin0N5E+DEJMh7Sp+u8aKoFpb+2FaAZJFn\/hnqxLTlVi2nyDxGL3U0eobWY+jWH9XPt52v3Hyh8TDhcAnQ1cN30B8Jn2+jkrm8ib+buchaCXHk0cPX72xuPECdwOEKLCBNrJa3FGSvO1zWiecnCgxCXgt+R8hUgsVPTsbrdFY2YRJGIhHndYZL98XzgG7cw85SnnMMe2SulzeL7xANGF8qiEVyiC7x83bbj5xOkeM\/CUTajrLBO3vyZ23KKOxvskjgI0t+Zw1zFsl+sYW0\/O\/V5WzPOwMwV8+iApQ8k9gEMiYQg98QLEMYnSohncmp0Z9qx2qFcQuHLcKJVa1J6wGtE\/EHR\/4d0aYPd6IRjg+qshCJmdzud\/12xjpGTl+BT0Hi0VsU5o7ZMi7WhmukZmmv8u0uZsvKREQNATm4cO4WCkYySt5O9gZEJOF+jjgeynDoAh09lyrNXIgMpM9ufm\/XEG\/I\/f2zIwbAUc6J6qks5OuYlJzW5vscTiOKhwcGZU9WBLgh0=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" -}'; - $this->environmentHelper - ->expects($this->any()) - ->method('getServerRoot') - ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/htaccessUnmodified/'); - $this->fileAccessHelper - ->expects($this->once()) - ->method('file_put_contents') - ->with( - \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessUnmodified//core/signature.json', - $this->callback(function ($signature) use ($expectedSignatureFileData) { - $expectedArray = json_decode($expectedSignatureFileData, true); - $actualArray = json_decode($signature, true); - $this->assertEquals($expectedArray, $actualArray); - return true; - }) - ); - - $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/core.crt'); - $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/core.key'); - $rsa = new RSA(); - $rsa->loadKey($rsaPrivateKey); - $x509 = new X509(); - $x509->loadX509($keyBundle); - $this->checker->writeCoreSignature($x509, $rsa, \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessUnmodified/'); - } - - public function testWriteCoreSignatureWithInvalidModifiedHtaccess(): void { - $expectedSignatureFileData = '{ - "hashes": { - ".htaccess": "4a54273dc8d697b2ca615acf2ae2c1ee3c1c643492cb04f42b10984fa9aacff1420dc829fd82f93ad3476fbd0cdab0251142c887dc8f872d03e39a3a3eb6d381" - }, - "signature": "qpDddYGgAKNR3TszOgjPXRphUl2P9Ym5OQaetltocgZASGDkOun5D64+1D0QJRKb4SG2+48muxGOHyL2Ngos4NUrrSR+SIkywZacay82YQBCEdr7\/4MjW1WHRPjvboLwEJwViw0EdAjsWRpD68aPnzUGrGsy2BsCo06P5iwjk9cXcHxdjC9R39npvoC3QNvQ2jmNIbh1Lc4U97dbb+CsXEQCLU1OSa9p3q6cEFV98Easwt7uF\/DzHK+CbeZlxVZ0DwLh2\/ylT1PyGou8QC1b3vKAnPjLWMO+UsCPpCKhk3C5pV+5etQ8puGd+0x2t5tEU+qXxLzek91zWNC+rqgC\/WlqLKbwPb\/BCHs4zLGV55Q2fEQmT21x0KCUELdPs4dBnYP4Ox5tEDugtJujWFzOHzoY6gGa\/BY\/78pSZXmq9o8dWkBEtioWWvaNZ1rM0ddE83GBlBTgjigi9Ay1D++bUW\/FCBB7CMk6qyNlV81H+cBuIEODw2aymmkM9LLDD2Qbmvo8gHEPRjiQxPC5OpDlcdSNiL+zcxVxeuX4FpT+9xzz\/\/DRONhufxRpsbuCOMxd96RW7y9U2N2Uxb3Bzn\/BIqEayUUsdgZjfaGcXXYKR+chu\/LOwNYN6RlnLsgqL\/dhGKwlRVKXw1RA2\/af\/CpqyR7uVP6al1YJo\/YJ+5XJ6zE=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" -}'; - $this->fileAccessHelper - ->expects($this->once()) - ->method('file_put_contents') - ->with( - \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithInvalidModifiedContent//core/signature.json', - $this->callback(function ($signature) use ($expectedSignatureFileData) { - $expectedArray = json_decode($expectedSignatureFileData, true); - $actualArray = json_decode($signature, true); - $this->assertEquals($expectedArray, $actualArray); - return true; - }) - ); - - $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/core.crt'); - $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/core.key'); - $rsa = new RSA(); - $rsa->loadKey($rsaPrivateKey); - $x509 = new X509(); - $x509->loadX509($keyBundle); - $this->checker->writeCoreSignature($x509, $rsa, \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithInvalidModifiedContent/'); - } - - public function testWriteCoreSignatureWithValidModifiedHtaccess(): void { - $expectedSignatureFileData = '{ - "hashes": { - ".htaccess": "7e6a7a4d8ee4f3fbc45dd579407c643471575a9d127d1c75f6d0a49e80766c3c587104b2139ef76d2a4bffce3f45777900605aaa49519c9532909b71e5030227", - "subfolder\/.htaccess": "2c57b1e25050e11dc3ae975832f378c452159f7b69f818e47eeeafadd6ba568517461dcb4d843b90b906cd7c89d161bc1b89dff8e3ae0eb6f5088508c47befd1" - }, - "signature": "YVwQvl9Dh8UebCumfgzFxfz3NiZJLmYG8oJVTfEBhulI4KXBnTG1jZTprf4XxG2XIriEYAZXsoXpu9xWsUFe9QfdncwoEpqJtGq7l6aVDTofX5Be5b03MQFJr4cflgllqW77QZ84D9O9qWF\/vNDAofXcwrzT04CxLDhyQgTCgYUnRjG9pnuP\/gtbDKbTjRvxhTyfg3T0Phv1+XAvpTPnH2q5A+1+LmiqziUJ1sMipsKo+jQP614eCi9qjmqhHIgLRgcuOBvsi4g5WUcdcAIZ6qLt5gm2Y3r6rKNVchosU9ZydMUTfjuejDbVwE2fNH5UUnV57fQBxwg9CfX7iFHqKv1bfv5Zviu12paShgWCB12uR3iH\/3lmTJn8K5Xqit3G4eymFaJ5IChdUThBp\/jhQSI2r8sPcZDYSJ\/UZKuFnezFdKhEBd5hMXe8aKAd6ijGDjLARksFuqpi1sS8llC5K1Q+DzktSL\/o64TY4Vuvykiwe\/BAk2SkL9voOtrvU7vfDBcuCPbDJnSBBC0ESpcXeClTBIn6xZ9WaxqoS7sinE\/kUwtWsRd04I7d79\/ouotyNb+mBhTuRsZT12p\/gn4JHXXNUAIpTwchYzGxbfNJ4kxnYBFZWVmvsSqOLFZu1yi5BP3ktA9yhFyWIa5659azRFEKRdXpVHtQVa4IgdhxEqA=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" -}'; - $this->environmentHelper - ->expects($this->any()) - ->method('getServerRoot') - ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithValidModifiedContent'); - $this->fileAccessHelper - ->expects($this->once()) - ->method('file_put_contents') - ->with( - \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithValidModifiedContent/core/signature.json', - $this->callback(function ($signature) use ($expectedSignatureFileData) { - $expectedArray = json_decode($expectedSignatureFileData, true); - $actualArray = json_decode($signature, true); - $this->assertEquals($expectedArray, $actualArray); - return true; - }) - ); - - $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/core.crt'); - $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/core.key'); - $rsa = new RSA(); - $rsa->loadKey($rsaPrivateKey); - $x509 = new X509(); - $x509->loadX509($keyBundle); - $this->checker->writeCoreSignature($x509, $rsa, \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithValidModifiedContent'); - } - - public function testVerifyCoreSignatureWithoutSignatureData(): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn('stable'); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(false); - - $expected = [ - 'EXCEPTION' => [ - 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', - 'message' => 'Signature data not found.', - ], - ]; - $this->assertSame($expected, $this->checker->verifyCoreSignature()); - } - - public function testVerifyCoreSignatureWithValidSignatureData(): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn('stable'); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(false); - - $this->environmentHelper - ->expects($this->any()) - ->method('getServerRoot') - ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'); - $signatureDataFile = '{ - "hashes": { - "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", - "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" - }, - "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" -}'; - $this->fileAccessHelper - ->expects($this->exactly(2)) - ->method('file_get_contents') - ->withConsecutive( - [\OC::$SERVERROOT . '/tests/data/integritycheck/app//core/signature.json'], - [\OC::$SERVERROOT . '/tests/data/integritycheck/app//resources/codesigning/root.crt'], - )->willReturnOnConsecutiveCalls( - $signatureDataFile, - file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') - ); - - $this->assertSame([], $this->checker->verifyCoreSignature()); - } - - public function testVerifyCoreSignatureWithValidModifiedHtaccessSignatureData(): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn('stable'); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(false); - - $this->environmentHelper - ->expects($this->any()) - ->method('getServerRoot') - ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithValidModifiedContent'); - $signatureDataFile = '{ - "hashes": { - ".htaccess": "7e6a7a4d8ee4f3fbc45dd579407c643471575a9d127d1c75f6d0a49e80766c3c587104b2139ef76d2a4bffce3f45777900605aaa49519c9532909b71e5030227", - "subfolder\/.htaccess": "2c57b1e25050e11dc3ae975832f378c452159f7b69f818e47eeeafadd6ba568517461dcb4d843b90b906cd7c89d161bc1b89dff8e3ae0eb6f5088508c47befd1" - }, - "signature": "YVwQvl9Dh8UebCumfgzFxfz3NiZJLmYG8oJVTfEBhulI4KXBnTG1jZTprf4XxG2XIriEYAZXsoXpu9xWsUFe9QfdncwoEpqJtGq7l6aVDTofX5Be5b03MQFJr4cflgllqW77QZ84D9O9qWF\/vNDAofXcwrzT04CxLDhyQgTCgYUnRjG9pnuP\/gtbDKbTjRvxhTyfg3T0Phv1+XAvpTPnH2q5A+1+LmiqziUJ1sMipsKo+jQP614eCi9qjmqhHIgLRgcuOBvsi4g5WUcdcAIZ6qLt5gm2Y3r6rKNVchosU9ZydMUTfjuejDbVwE2fNH5UUnV57fQBxwg9CfX7iFHqKv1bfv5Zviu12paShgWCB12uR3iH\/3lmTJn8K5Xqit3G4eymFaJ5IChdUThBp\/jhQSI2r8sPcZDYSJ\/UZKuFnezFdKhEBd5hMXe8aKAd6ijGDjLARksFuqpi1sS8llC5K1Q+DzktSL\/o64TY4Vuvykiwe\/BAk2SkL9voOtrvU7vfDBcuCPbDJnSBBC0ESpcXeClTBIn6xZ9WaxqoS7sinE\/kUwtWsRd04I7d79\/ouotyNb+mBhTuRsZT12p\/gn4JHXXNUAIpTwchYzGxbfNJ4kxnYBFZWVmvsSqOLFZu1yi5BP3ktA9yhFyWIa5659azRFEKRdXpVHtQVa4IgdhxEqA=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" -}'; - $this->fileAccessHelper - ->expects($this->exactly(2)) - ->method('file_get_contents') - ->withConsecutive( - [\OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithValidModifiedContent/core/signature.json'], - [\OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithValidModifiedContent/resources/codesigning/root.crt'], - ) - ->willReturnOnConsecutiveCalls( - $signatureDataFile, - file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') - ); - - $this->assertSame([], $this->checker->verifyCoreSignature()); - } - - /** - * See inline instruction on how to update the test assets when changing mimetypealiases.dist.json - */ - public function testVerifyCoreSignatureWithModifiedMimetypelistSignatureData(): void { - $shippedMimetypeAliases = (array)json_decode(file_get_contents(\OC::$SERVERROOT . '/resources/config/mimetypealiases.dist.json')); - $allAliases = array_merge($shippedMimetypeAliases, ['my-custom/mimetype' => 'custom']); - - $this->mimeTypeDetector - ->method('getOnlyDefaultAliases') - ->willReturn($shippedMimetypeAliases); - - $this->mimeTypeDetector - ->method('getAllAliases') - ->willReturn($allAliases); - - $oldMimetypeList = new GenerateMimetypeFileBuilder(); - $all = $this->mimeTypeDetector->getAllAliases(); - $newFile = $oldMimetypeList->generateFile($all); - - // When updating the mimetype list the test assets need to be updated as well - // 1. Update core/js/mimetypelist.js with the new generated js by running the test with the next line uncommented: - // file_put_contents(\OC::$SERVERROOT . '/tests/data/integritycheck/mimetypeListModified/core/js/mimetypelist.js', $newFile); - // 2. Update signature.json using the following occ command: - // occ integrity:sign-core --privateKey=./tests/data/integritycheck/core.key --certificate=./tests/data/integritycheck/core.crt --path=./tests/data/integritycheck/mimetypeListModified - self::assertEquals($newFile, file_get_contents(\OC::$SERVERROOT . '/tests/data/integritycheck/mimetypeListModified/core/js/mimetypelist.js')); - - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn('stable'); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(false); - - $this->environmentHelper - ->expects($this->any()) - ->method('getServerRoot') - ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/mimetypeListModified'); - - $signatureDataFile = file_get_contents(__DIR__ .'/../../data/integritycheck/mimetypeListModified/core/signature.json'); - $this->fileAccessHelper - ->method('file_get_contents') - ->willReturnMap([ - [\OC::$SERVERROOT . '/tests/data/integritycheck/mimetypeListModified/core/signature.json', $signatureDataFile], - [\OC::$SERVERROOT . '/tests/data/integritycheck/mimetypeListModified/resources/codesigning/root.crt', file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt')], - ]); - - $this->assertSame([], $this->checker->verifyCoreSignature()); - } - - public function testVerifyCoreSignatureWithValidSignatureDataAndNotAlphabeticOrder(): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn('stable'); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(false); - - $this->environmentHelper - ->expects($this->any()) - ->method('getServerRoot') - ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'); - $signatureDataFile = '{ - "hashes": { - "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", - "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" - }, - "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" -}'; - $this->fileAccessHelper - ->expects($this->exactly(2)) - ->method('file_get_contents') - ->withConsecutive( - [\OC::$SERVERROOT . '/tests/data/integritycheck/app//core/signature.json'], - [\OC::$SERVERROOT . '/tests/data/integritycheck/app//resources/codesigning/root.crt'], - )->willReturnOnConsecutiveCalls( - $signatureDataFile, - file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') - ); - - $this->assertSame([], $this->checker->verifyCoreSignature()); - } - - public function testVerifyCoreSignatureWithTamperedSignatureData(): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn('stable'); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(false); - - $this->environmentHelper - ->expects($this->any()) - ->method('getServerRoot') - ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData/'); - $signatureDataFile = '{ - "hashes": { - "AnotherFile.txt": "tampered", - "subfolder\/file.txt": "tampered" - }, - "signature": "eXesvDm3pkek12xSwMG10y9suRES79Nye3jYNe5KYq1tTUPqRRNgxmMGAfcUro0zpLeAr2YgHeSMWtglblGOW7pmwGVPZ0O1Y4r1fE6jnep0kW+35PLIaqCorIOnCAtSzDNKBhwd1ow3zW2wC0DFouuEkIO8u5Fw28g8E8dp8zEk1xMblNPy+xtWkmYHrVJ\/dQgun1bYOF2ZFtAzatwndTI\/bGsy1i3Wsl+x6HyWKQdq8y8VObtOqKDH7uERBEpB9DHVyKflj1v1gQuEH6BhaRdATc7ee0MiQdGblraIySwYRdfo2d8i82OVKrenMB3SLwyCvDPyQ9iKpTOnSF52ZBqaqSXKM2N\/RAkweeBFQQCwcHhqxvB0cfbyHcbkOLeCZe\/tsh68IxwTiYgzvLfl7sOZ5arnZbzrPpZmB+hfV2omkoJ1tDwOWz9hEmLLNtfo2OxyUH1m0+XFaC+Gbn4WkVDgf7YZkwUcG+Qoa3oKDNMss8MEyZxewl2iDGZcf402dlidHRprlfmXbAYuVQ08\/a0HxIKYPGh\/nsMGmwnO15CWtFpAbhUA\/D5oRjsIxnvXaMDg0iAFpdu\/5Ffsj7g3EPdBkiQHNYK7YU1RRx609eH0bZyiIYHdUPw7ikLupvrebZmELqi3mqDFO99u4eISlxFJlUbUND3L4BtmWTWrKwI=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" -}'; - $this->fileAccessHelper - ->expects($this->exactly(2)) - ->method('file_get_contents') - ->withConsecutive( - [\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//core/signature.json'], - [\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//resources/codesigning/root.crt'], - )->willReturnOnConsecutiveCalls( - $signatureDataFile, - file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') - ); - - $expected = [ - 'EXCEPTION' => [ - 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', - 'message' => 'Signature could not get verified.', - ] - ]; - $this->assertSame($expected, $this->checker->verifyCoreSignature()); - } - - public function testVerifyCoreSignatureWithTamperedFiles(): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn('stable'); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(false); - - $this->environmentHelper - ->expects($this->any()) - ->method('getServerRoot') - ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData/'); - $signatureDataFile = '{ - "hashes": { - "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", - "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" - }, - "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" -}'; - $this->fileAccessHelper - ->expects($this->exactly(2)) - ->method('file_get_contents') - ->withConsecutive( - [\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//core/signature.json'], - [\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//resources/codesigning/root.crt'], - )->willReturnOnConsecutiveCalls( - $signatureDataFile, - file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') - ); - - $expected = [ - 'INVALID_HASH' => [ - 'AnotherFile.txt' => [ - 'expected' => '1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112', - 'current' => '7322348ba269c6d5522efe02f424fa3a0da319a7cd9c33142a5afe32a2d9af2da3a411f086fcfc96ff4301ea566f481dba0960c2abeef3594c4d930462f6584c', - ], - ], - 'FILE_MISSING' => [ - 'subfolder/file.txt' => [ - 'expected' => '410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b', - 'current' => '', - ], - ], - 'EXTRA_FILE' => [ - 'UnecessaryFile' => [ - 'expected' => '', - 'current' => 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e', - ], - ], - - ]; - $this->assertSame($expected, $this->checker->verifyCoreSignature()); - } - - public function testVerifyCoreWithInvalidCertificate(): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn('stable'); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(false); - - $this->environmentHelper - ->expects($this->any()) - ->method('getServerRoot') - ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'); - $signatureDataFile = '{ - "hashes": { - "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", - "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" - }, - "signature": "eXesvDm3pkek12xSwMG10y9suRES79Nye3jYNe5KYq1tTUPqRRNgxmMGAfcUro0zpLeAr2YgHeSMWtglblGOW7pmwGVPZ0O1Y4r1fE6jnep0kW+35PLIaqCorIOnCAtSzDNKBhwd1ow3zW2wC0DFouuEkIO8u5Fw28g8E8dp8zEk1xMblNPy+xtWkmYHrVJ\/dQgun1bYOF2ZFtAzatwndTI\/bGsy1i3Wsl+x6HyWKQdq8y8VObtOqKDH7uERBEpB9DHVyKflj1v1gQuEH6BhaRdATc7ee0MiQdGblraIySwYRdfo2d8i82OVKrenMB3SLwyCvDPyQ9iKpTOnSF52ZBqaqSXKM2N\/RAkweeBFQQCwcHhqxvB0cfbyHcbkOLeCZe\/tsh68IxwTiYgzvLfl7sOZ5arnZbzrPpZmB+hfV2omkoJ1tDwOWz9hEmLLNtfo2OxyUH1m0+XFaC+Gbn4WkVDgf7YZkwUcG+Qoa3oKDNMss8MEyZxewl2iDGZcf402dlidHRprlfmXbAYuVQ08\/a0HxIKYPGh\/nsMGmwnO15CWtFpAbhUA\/D5oRjsIxnvXaMDg0iAFpdu\/5Ffsj7g3EPdBkiQHNYK7YU1RRx609eH0bZyiIYHdUPw7ikLupvrebZmELqi3mqDFO99u4eISlxFJlUbUND3L4BtmWTWrKwI=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUPYoweUxCPqbDW4ntuh7QvgyqSrgwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIyNDIwNloXDTE2MTEwMzIyNDIwNlowDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJui3nDbjOIjxNnthdBZplphujsN6u8K\r\nQ\/62zAuSwzXVp0+3IMgM\/2sepklVE8YfCyVJ5+SUJqnqHoUWVRVfs8jL0wW6nrHM\r\n\/lsscAguWCee4iAdNOqI9kq4+DUau8J45e62XA9mrAo\/8\/NKzFE2y2WduDoQZcm+\r\n8+dwcUUHXw2jl8dfrmvEMYSqTNDdb4rGmQpeV+dr9BLqr+x03U1Q08qCG9j7mSOz\r\ncvJENjOvC5uzAh5LCuCgxqG4o+mPzB0FtNnwoRRu6IsF3Y3KacRqPc30fB\/iXDn5\r\nBPr14uNxTTYWoZJ1F0tZrLzRbXdjJJOC+dnQurTtXWZ8WjPB1BWQYK7fW6t82mkN\r\n2Qe2xen99gs9nX5yY\/sHM3TKSJdM7AVCEv\/emW3gNjkvWTtRlN\/Nc7X2ckNwXcvo\r\n0yi3fSPjzXpDgLbhp1FzrMlHDn1VzmRT3r8wLByWa\/hsxrJDsBzwunMJYhXhmeKb\r\n3wX0tN\/EUJTWBntpwVOIGnRPD51oBoQUOMaEAq\/kz8PgN181bWZkJbRuf+FWkijQ\r\no+HR2lVF1jWXXst5Uc+s9HN81Uly7X4O9MMg0QxT4+wymtGDs6AOkwMi9rgBTrRB\r\n3tLU3XL2UIwRXgmd8cPtTu\/I6Bm7LdyaYtZ3yJTxRewq3nZdWypqBhD8uhpIYVkf\r\no4bxmGkVAQVTAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAKKAX5EHgU1grODnJ0of\r\nspFpgB1K67YvclNUyuU6NQ6zBJx1\/w1RnM7uxLcxiiWj1BbUhwZQ0ojmEHeUyi6O\r\nGrDVajwhTccDMmja3u5adhEncx65\/H+lD85IPRRkS2qBDssMDdJHhZ0uI+40nI7M\r\nMq1kFjl+6wiuqZXqps66DuLbk45g\/ZlrFIrIo3Ix5vj0OVqwT+gO4LYirJK6KgVS\r\nUttbcEsc\/yKU9ThnM8\/n4m2jstZXfzKPgOsJrQcZrFOtpj+CWmBzVElBSPlDT3Nh\r\nHSgOeTFJ8bQBxj2iG5dLA+JZJQKxyJ1gy2ZtxIJ2GyvLtSe8NUSqvfPWOaAKEUV2\r\ngniytnEFLr+PcD+9EGux6jZNuj6HmtWVThTfD5VGFmtlVU2z71ZRYY0kn6J3mmFc\r\nS2ecEcCUwqG5YNLncEUCyZhC2klWql2SHyGctCEyWWY7ikIDjVzYt2EbcFvLNBnP\r\ntybN1TYHRRZxlug00CCoOE9EZfk46FkZpDvU6KmqJRofkNZ5sj+SffyGcwYwNrDH\r\nKqe8m+9lHf3CRTIDeMu8r2xl1I6M6ZZfjabbmVP9Jd6WN4s6f1FlXDWzhlT1N0Qw\r\nGzJj6xB+SPtS3UV05tBlvbfA4e06D5G9uD7Q8ONcINtMS0xsSJ2oo82AqlpvlF\/q\r\noj7YKHsaTVGA+FxBktZHfoxD\r\n-----END CERTIFICATE-----" -}'; - $this->fileAccessHelper - ->expects($this->exactly(2)) - ->method('file_get_contents') - ->withConsecutive( - [\OC::$SERVERROOT . '/tests/data/integritycheck/app//core/signature.json'], - [\OC::$SERVERROOT . '/tests/data/integritycheck/app//resources/codesigning/root.crt'], - )->willReturnOnConsecutiveCalls( - $signatureDataFile, - file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') - ); - - $expected = [ - 'EXCEPTION' => [ - 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', - 'message' => 'Certificate is not valid.', - ] - ]; - $this->assertSame($expected, $this->checker->verifyCoreSignature()); - } - - public function testVerifyCoreWithDifferentScope(): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn('stable'); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(false); - - $this->environmentHelper - ->expects($this->any()) - ->method('getServerRoot') - ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'); - $signatureDataFile = '{ - "hashes": { - "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", - "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" - }, - "signature": "EL49UaSeyMAqyMtqId+tgOhhwgOevPZsRLX4j2blnybAB6fN07z0936JqZV7+eMPiE30Idx+UCY6rCFN531Kqe9vAOCdgtHUSOjjKyKc+lvULESlMb6YQcrZrvDlEMMjzjH49ewG7Ai8sNN6HrRUd9U8ws+ewSkW2DOOBItj\/21RBnkrSt+2AtGXGigEvuTm57HrCYDj8\/lSkumC2GVkjLUHeLOKYo4PRNOr6yP5mED5v7zo66AWvXl2fKv54InZcdxsAk35lyK9DGZbk\/027ZRd0AOHT3LImRLvQ+8EAg3XLlRUy0hOFGgPC+jYonMzgYvsAXAXi2j8LnLJlsLwpFwu1k1B+kZVPMumKZvP9OvJb70EirecXmz62V+Jiyuaq7ne4y7Kp5gKZT\/T8SeZ0lFtCmPfYyzBB0y8s5ldmTTmdVYHs54t\/OCCW82HzQZxnFNPzDTRa8HglsaMKrqPtW59+R4UvRKSWhB8M\/Ah57qgzycvPV4KMz\/FbD4l\/\/9chRKSlCfc2k3b8ZSHNmi+EzCKgJjWIoKdgN1yax94puU8jfn8UW+G7H9Y1Jsf\/jox6QLyYEgtV1vOHY2xLT7fVs2vhyvkN2MNjJnmQ70gFG5Qz2lBz5wi6ZpB+tOfCcpbLxWAkoWoIrmC\/Ilqh7mfmRZ43g5upjkepHNd93ONuY8=", - "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEwTCCAqmgAwIBAgIUWv0iujufs5lUr0svCf\/qTQvoyKAwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIyNDk1M1oXDTE2MTEwMzIyNDk1M1owEjEQMA4GA1UEAwwHU29tZUFwcDCCAiIw\r\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK8q0x62agGSRBqeWsaeEwFfepMk\r\nF8cAobMMi50qHCv9IrOn\/ZH9l52xBrbIkErVmRjmly0d4JhD8Ymhidsh9ONKYl\/j\r\n+ishsZDM8eNNdp3Ew+fEYVvY1W7mR1qU24NWj0bzVsClI7hvPVIuw7AjfBDq1C5+\r\nA+ZSLSXYvOK2cEWjdxQfuNZwEZSjmA63DUllBIrm35IaTvfuyhU6BW9yHZxmb8+M\r\nw0xDv30D5UkE\/2N7Pa\/HQJLxCR+3zKibRK3nUyRDLSXxMkU9PnFNaPNX59VPgyj4\r\nGB1CFSToldJVPF4pzh7p36uGXZVxs8m3LFD4Ol8mhi7jkxDZjqFN46gzR0r23Py6\r\ndol9vfawGIoUwp9LvL0S7MvdRY0oazLXwClLP4OQ17zpSMAiCj7fgNT661JamPGj\r\nt5O7Zn2wA7I4ddDS\/HDTWCu98Zwc9fHIpsJPgCZ9awoqxi4Mnf7Pk9g5nnXhszGC\r\ncxxIASQKM+GhdzoRxKknax2RzUCwCzcPRtCj8AQT\/x\/mqN3PfRmlnFBNACUw9bpZ\r\nSOoNq2pCF9igftDWpSIXQ38pVpKLWowjjg3DVRmVKBgivHnUnVLyzYBahHPj0vaz\r\ntFtUFRaqXDnt+4qyUGyrT5h5pjZaTcHIcSB4PiarYwdVvgslgwnQzOUcGAzRWBD4\r\n6jV2brP5vFY3g6iPAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBACTY3CCHC+Z28gCf\r\nFWGKQ3wAKs+k4+0yoti0qm2EKX7rSGQ0PHSas6uW79WstC4Rj+DYkDtIhGMSg8FS\r\nHVGZHGBCc0HwdX+BOAt3zi4p7Sf3oQef70\/4imPoKxbAVCpd\/cveVcFyDC19j1yB\r\nBapwu87oh+muoeaZxOlqQI4UxjBlR\/uRSMhOn2UGauIr3dWJgAF4pGt7TtIzt+1v\r\n0uA6FtN1Y4R5O8AaJPh1bIG0CVvFBE58esGzjEYLhOydgKFnEP94kVPgJD5ds9C3\r\npPhEpo1dRpiXaF7WGIV1X6DI\/ipWvfrF7CEy6I\/kP1InY\/vMDjQjeDnJ\/VrXIWXO\r\nyZvHXVaN\/m+1RlETsH7YO\/QmxRue9ZHN3gvvWtmpCeA95sfpepOk7UcHxHZYyQbF\r\n49\/au8j+5tsr4A83xzsT1JbcKRxkAaQ7WDJpOnE5O1+H0fB+BaLakTg6XX9d4Fo7\r\n7Gin7hVWX7pL+JIyxMzME3LhfI61+CRcqZQIrpyaafUziPQbWIPfEs7h8tCOWyvW\r\nUO8ZLervYCB3j44ivkrxPlcBklDCqqKKBzDP9dYOtS\/P4RB1NkHA9+NTvmBpTonS\r\nSFXdg9fFMD7VfjDE3Vnk+8DWkVH5wBYowTAD7w9Wuzr7DumiAULexnP\/Y7xwxLv7\r\n4B+pXTAcRK0zECDEaX3npS8xWzrB\r\n-----END CERTIFICATE-----" -}'; - $this->fileAccessHelper - ->expects($this->exactly(2)) - ->method('file_get_contents') - ->withConsecutive( - [\OC::$SERVERROOT . '/tests/data/integritycheck/app//core/signature.json'], - [\OC::$SERVERROOT . '/tests/data/integritycheck/app//resources/codesigning/root.crt'], - )->willReturnOnConsecutiveCalls( - $signatureDataFile, - file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') - ); - - $expected = [ - 'EXCEPTION' => [ - 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', - 'message' => 'Certificate is not valid for required scope. (Requested: core, current: CN=SomeApp)', - ] - ]; - $this->assertSame($expected, $this->checker->verifyCoreSignature()); - } - - public function testRunInstanceVerification(): void { - $this->checker = $this->getMockBuilder('\OC\IntegrityCheck\Checker') - ->setConstructorArgs([ - $this->environmentHelper, - $this->fileAccessHelper, - $this->appLocator, - $this->config, - $this->appConfig, - $this->cacheFactory, - $this->appManager, - $this->mimeTypeDetector, - ]) - ->setMethods([ - 'verifyCoreSignature', - 'verifyAppSignature', - ]) - ->getMock(); - - $this->checker - ->expects($this->once()) - ->method('verifyCoreSignature'); - $this->appManager - ->expects($this->once()) - ->method('getAllAppsInAppsFolders') - ->willReturn([ - 'files', - 'calendar', - 'contacts', - 'dav', - ]); - $this->appManager - ->expects($this->exactly(4)) - ->method('isShipped') - ->withConsecutive( - ['files'], - ['calendar'], - ['contacts'], - ['dav'], - )->willReturnOnConsecutiveCalls( - true, - false, - false, - true, - ); - $this->checker - ->expects($this->exactly(3)) - ->method('verifyAppSignature') - ->withConsecutive( - ['files'], - ['calendar'], - ['dav'], - ); - $this->appLocator - ->expects($this->exactly(2)) - ->method('getAppPath') - ->withConsecutive( - ['calendar'], - ['contacts'], - )->willReturnOnConsecutiveCalls( - '/apps/calendar', - '/apps/contacts', - ); - $this->fileAccessHelper - ->expects($this->exactly(2)) - ->method('file_exists') - ->withConsecutive( - ['/apps/calendar/appinfo/signature.json'], - ['/apps/contacts/appinfo/signature.json'], - )->willReturnOnConsecutiveCalls( - true, - false, - ); - $this->appConfig - ->expects($this->once()) - ->method('deleteKey') - ->with('core', 'oc.integritycheck.checker'); - - $this->checker->runInstanceVerification(); - } - - public function testVerifyAppSignatureWithoutSignatureDataAndCodeCheckerDisabled(): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn('stable'); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(true); - - $expected = []; - $this->assertSame($expected, $this->checker->verifyAppSignature('SomeApp')); - } - - /** - * @return array - */ - public function channelDataProvider() { - return [ - ['stable', true], - ['git', false], - ]; - } - - /** - * @param string $channel - * @param bool $isCodeSigningEnforced - * @dataProvider channelDataProvider - */ - public function testIsCodeCheckEnforced($channel, $isCodeSigningEnforced): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn($channel); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(false); - - $this->assertSame($isCodeSigningEnforced, $this->checker->isCodeCheckEnforced()); - } - - /** - * @param string $channel - * @dataProvider channelDataProvider - */ - public function testIsCodeCheckEnforcedWithDisabledConfigSwitch($channel): void { - $this->environmentHelper - ->expects($this->once()) - ->method('getChannel') - ->willReturn($channel); - $this->config - ->expects($this->any()) - ->method('getSystemValueBool') - ->with('integrity.check.disabled', false) - ->willReturn(true); - - $this->assertFalse(self::invokePrivate($this->checker, 'isCodeCheckEnforced')); - } -} +<?php +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace Test\IntegrityCheck; + +use OC\Core\Command\Maintenance\Mimetype\GenerateMimetypeFileBuilder; +use OC\IntegrityCheck\Checker; +use OC\IntegrityCheck\Helpers\AppLocator; +use OC\IntegrityCheck\Helpers\EnvironmentHelper; +use OC\IntegrityCheck\Helpers\FileAccessHelper; +use OC\Memcache\NullCache; +use OCP\App\IAppManager; +use OCP\IAppConfig; +use OCP\ICacheFactory; +use OCP\IConfig; +use phpseclib\Crypt\RSA; +use phpseclib\File\X509; +use Test\TestCase; + +class CheckerTest extends TestCase { + /** @var EnvironmentHelper|\PHPUnit\Framework\MockObject\MockObject */ + private $environmentHelper; + /** @var AppLocator|\PHPUnit\Framework\MockObject\MockObject */ + private $appLocator; + /** @var Checker */ + private $checker; + /** @var FileAccessHelper|\PHPUnit\Framework\MockObject\MockObject */ + private $fileAccessHelper; + /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ + private $config; + /** @var IAppConfig|\PHPUnit\Framework\MockObject\MockObject */ + private $appConfig; + /** @var ICacheFactory|\PHPUnit\Framework\MockObject\MockObject */ + private $cacheFactory; + /** @var IAppManager|\PHPUnit\Framework\MockObject\MockObject */ + private $appManager; + /** @var \OC\Files\Type\Detection|\PHPUnit\Framework\MockObject\MockObject */ + private $mimeTypeDetector; + + protected function setUp(): void { + parent::setUp(); + $this->environmentHelper = $this->createMock(EnvironmentHelper::class); + $this->fileAccessHelper = $this->createMock(FileAccessHelper::class); + $this->appLocator = $this->createMock(AppLocator::class); + $this->config = $this->createMock(IConfig::class); + $this->appConfig = $this->createMock(IAppConfig::class); + $this->cacheFactory = $this->createMock(ICacheFactory::class); + $this->appManager = $this->createMock(IAppManager::class); + $this->mimeTypeDetector = $this->createMock(\OC\Files\Type\Detection::class); + + $this->config->method('getAppValue') + ->willReturnArgument(2); + + $this->cacheFactory + ->expects($this->any()) + ->method('createDistributed') + ->with('oc.integritycheck.checker') + ->willReturn(new NullCache()); + + $this->checker = new Checker( + $this->environmentHelper, + $this->fileAccessHelper, + $this->appLocator, + $this->config, + $this->appConfig, + $this->cacheFactory, + $this->appManager, + $this->mimeTypeDetector + ); + } + + + public function testWriteAppSignatureOfNotExistingApp(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Exception message'); + + $this->fileAccessHelper + ->expects($this->once()) + ->method('assertDirectoryExists') + ->with('NotExistingApp/appinfo') + ->willThrowException(new \Exception('Exception message')); + $this->fileAccessHelper + ->expects($this->once()) + ->method('is_writable') + ->with('NotExistingApp/appinfo') + ->willReturn(true); + + $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.crt'); + $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.key'); + $rsa = new RSA(); + $rsa->loadKey($rsaPrivateKey); + $x509 = new X509(); + $x509->loadX509($keyBundle); + $this->checker->writeAppSignature('NotExistingApp', $x509, $rsa); + } + + + public function testWriteAppSignatureWrongPermissions(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessageMatches('/[a-zA-Z\\/_-]+ is not writable/'); + + $this->fileAccessHelper + ->expects($this->once()) + ->method('file_put_contents') + ->will($this->throwException(new \Exception('Exception message'))); + + $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.crt'); + $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.key'); + $rsa = new RSA(); + $rsa->loadKey($rsaPrivateKey); + $x509 = new X509(); + $x509->loadX509($keyBundle); + $this->checker->writeAppSignature(\OC::$SERVERROOT . '/tests/data/integritycheck/app/', $x509, $rsa); + } + + public function testWriteAppSignature(): void { + $expectedSignatureFileData = '{ + "hashes": { + "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", + "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" + }, + "signature": "Y5yvXvcGHVPuRRatKVDUONWq1FpLXugZd6Km\/+aEHsQj7coVl9FeMj9OsWamBf7yRIw3dtNLguTLlAA9QAv\/b0uHN3JnbNZN+dwFOve4NMtqXfSDlWftqKN00VS+RJXpG1S2IIx9Poyp2NoghL\/5AuTv4GHiNb7zU\/DT\/kt71pUGPgPR6IIFaE+zHOD96vjYkrH+GfWZzKR0FCdLib9yyNvk+EGrcjKM6qjs2GKfS\/XFjj\/\/neDnh\/0kcPuKE3ZbofnI4TIDTv0CGqvOp7PtqVNc3Vy\/UKa7uF1PT0MAUKMww6EiMUSFZdUVP4WWF0Y72W53Qdtf1hrAZa2kfKyoK5kd7sQmCSKUPSU8978AUVZlBtTRlyT803IKwMV0iHMkw+xYB1sN2FlHup\/DESADqxhdgYuK35bCPvgkb4SBe4B8Voz\/izTvcP7VT5UvkYdAO+05\/jzdaHEmzmsD92CFfvX0q8O\/Y\/29ubftUJsqcHeMDKgcR4eZOE8+\/QVc\/89QO6WnKNuNuV+5bybO6g6PAdC9ZPsCvnihS61O2mwRXHLR3jv2UleFWm+lZEquPKtkhi6SLtDiijA4GV6dmS+dzujSLb7hGeD5o1plZcZ94uhWljl+QIp82+zU\/lYB1Zfr4Mb4e+V7r2gv7Fbv7y6YtjE2GIQwRhC5jq56bD0ZB+I=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEwTCCAqmgAwIBAgIUWv0iujufs5lUr0svCf\/qTQvoyKAwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIyNDk1M1oXDTE2MTEwMzIyNDk1M1owEjEQMA4GA1UEAwwHU29tZUFwcDCCAiIw\r\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK8q0x62agGSRBqeWsaeEwFfepMk\r\nF8cAobMMi50qHCv9IrOn\/ZH9l52xBrbIkErVmRjmly0d4JhD8Ymhidsh9ONKYl\/j\r\n+ishsZDM8eNNdp3Ew+fEYVvY1W7mR1qU24NWj0bzVsClI7hvPVIuw7AjfBDq1C5+\r\nA+ZSLSXYvOK2cEWjdxQfuNZwEZSjmA63DUllBIrm35IaTvfuyhU6BW9yHZxmb8+M\r\nw0xDv30D5UkE\/2N7Pa\/HQJLxCR+3zKibRK3nUyRDLSXxMkU9PnFNaPNX59VPgyj4\r\nGB1CFSToldJVPF4pzh7p36uGXZVxs8m3LFD4Ol8mhi7jkxDZjqFN46gzR0r23Py6\r\ndol9vfawGIoUwp9LvL0S7MvdRY0oazLXwClLP4OQ17zpSMAiCj7fgNT661JamPGj\r\nt5O7Zn2wA7I4ddDS\/HDTWCu98Zwc9fHIpsJPgCZ9awoqxi4Mnf7Pk9g5nnXhszGC\r\ncxxIASQKM+GhdzoRxKknax2RzUCwCzcPRtCj8AQT\/x\/mqN3PfRmlnFBNACUw9bpZ\r\nSOoNq2pCF9igftDWpSIXQ38pVpKLWowjjg3DVRmVKBgivHnUnVLyzYBahHPj0vaz\r\ntFtUFRaqXDnt+4qyUGyrT5h5pjZaTcHIcSB4PiarYwdVvgslgwnQzOUcGAzRWBD4\r\n6jV2brP5vFY3g6iPAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBACTY3CCHC+Z28gCf\r\nFWGKQ3wAKs+k4+0yoti0qm2EKX7rSGQ0PHSas6uW79WstC4Rj+DYkDtIhGMSg8FS\r\nHVGZHGBCc0HwdX+BOAt3zi4p7Sf3oQef70\/4imPoKxbAVCpd\/cveVcFyDC19j1yB\r\nBapwu87oh+muoeaZxOlqQI4UxjBlR\/uRSMhOn2UGauIr3dWJgAF4pGt7TtIzt+1v\r\n0uA6FtN1Y4R5O8AaJPh1bIG0CVvFBE58esGzjEYLhOydgKFnEP94kVPgJD5ds9C3\r\npPhEpo1dRpiXaF7WGIV1X6DI\/ipWvfrF7CEy6I\/kP1InY\/vMDjQjeDnJ\/VrXIWXO\r\nyZvHXVaN\/m+1RlETsH7YO\/QmxRue9ZHN3gvvWtmpCeA95sfpepOk7UcHxHZYyQbF\r\n49\/au8j+5tsr4A83xzsT1JbcKRxkAaQ7WDJpOnE5O1+H0fB+BaLakTg6XX9d4Fo7\r\n7Gin7hVWX7pL+JIyxMzME3LhfI61+CRcqZQIrpyaafUziPQbWIPfEs7h8tCOWyvW\r\nUO8ZLervYCB3j44ivkrxPlcBklDCqqKKBzDP9dYOtS\/P4RB1NkHA9+NTvmBpTonS\r\nSFXdg9fFMD7VfjDE3Vnk+8DWkVH5wBYowTAD7w9Wuzr7DumiAULexnP\/Y7xwxLv7\r\n4B+pXTAcRK0zECDEaX3npS8xWzrB\r\n-----END CERTIFICATE-----" +}'; + $this->fileAccessHelper + ->expects($this->once()) + ->method('file_put_contents') + ->with( + $this->equalTo(\OC::$SERVERROOT . '/tests/data/integritycheck/app//appinfo/signature.json'), + $this->callback(function ($signature) use ($expectedSignatureFileData) { + $expectedArray = json_decode($expectedSignatureFileData, true); + $actualArray = json_decode($signature, true); + $this->assertEquals($expectedArray, $actualArray); + return true; + }) + ); + + $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.crt'); + $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.key'); + $rsa = new RSA(); + $rsa->loadKey($rsaPrivateKey); + $x509 = new X509(); + $x509->loadX509($keyBundle); + $this->checker->writeAppSignature(\OC::$SERVERROOT . '/tests/data/integritycheck/app/', $x509, $rsa); + } + + public function testVerifyAppSignatureWithoutSignatureData(): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn('stable'); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(false); + + $expected = [ + 'EXCEPTION' => [ + 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, + 'message' => 'Signature data not found.', + ], + ]; + $this->assertSame($expected, $this->checker->verifyAppSignature('SomeApp')); + } + + public function testVerifyAppSignatureWithValidSignatureData(): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn('stable'); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(false); + + $this->appLocator + ->expects($this->once()) + ->method('getAppPath') + ->with('SomeApp') + ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'); + $signatureDataFile = '{ + "hashes": { + "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", + "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" + }, + "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" +}'; + $this->fileAccessHelper + ->expects($this->exactly(2)) + ->method('file_get_contents') + ->withConsecutive( + [\OC::$SERVERROOT . '/tests/data/integritycheck/app//appinfo/signature.json'], + ['/resources/codesigning/root.crt'], + ) + ->willReturnOnConsecutiveCalls( + $signatureDataFile, + file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') + ); + + $this->assertSame([], $this->checker->verifyAppSignature('SomeApp')); + } + + public function testVerifyAppSignatureWithTamperedSignatureData(): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn('stable'); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(false); + + $this->appLocator + ->expects($this->once()) + ->method('getAppPath') + ->with('SomeApp') + ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'); + $signatureDataFile = '{ + "hashes": { + "AnotherFile.txt": "tampered", + "subfolder\/file.txt": "tampered" + }, + "signature": "EL49UaSeyMAqyMtqId+tgOhhwgOevPZsRLX4j2blnybAB6fN07z0936JqZV7+eMPiE30Idx+UCY6rCFN531Kqe9vAOCdgtHUSOjjKyKc+lvULESlMb6YQcrZrvDlEMMjzjH49ewG7Ai8sNN6HrRUd9U8ws+ewSkW2DOOBItj\/21RBnkrSt+2AtGXGigEvuTm57HrCYDj8\/lSkumC2GVkjLUHeLOKYo4PRNOr6yP5mED5v7zo66AWvXl2fKv54InZcdxsAk35lyK9DGZbk\/027ZRd0AOHT3LImRLvQ+8EAg3XLlRUy0hOFGgPC+jYonMzgYvsAXAXi2j8LnLJlsLwpFwu1k1B+kZVPMumKZvP9OvJb70EirecXmz62V+Jiyuaq7ne4y7Kp5gKZT\/T8SeZ0lFtCmPfYyzBB0y8s5ldmTTmdVYHs54t\/OCCW82HzQZxnFNPzDTRa8HglsaMKrqPtW59+R4UvRKSWhB8M\/Ah57qgzycvPV4KMz\/FbD4l\/\/9chRKSlCfc2k3b8ZSHNmi+EzCKgJjWIoKdgN1yax94puU8jfn8UW+G7H9Y1Jsf\/jox6QLyYEgtV1vOHY2xLT7fVs2vhyvkN2MNjJnmQ70gFG5Qz2lBz5wi6ZpB+tOfCcpbLxWAkoWoIrmC\/Ilqh7mfmRZ43g5upjkepHNd93ONuY8=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEwTCCAqmgAwIBAgIUWv0iujufs5lUr0svCf\/qTQvoyKAwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIyNDk1M1oXDTE2MTEwMzIyNDk1M1owEjEQMA4GA1UEAwwHU29tZUFwcDCCAiIw\r\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK8q0x62agGSRBqeWsaeEwFfepMk\r\nF8cAobMMi50qHCv9IrOn\/ZH9l52xBrbIkErVmRjmly0d4JhD8Ymhidsh9ONKYl\/j\r\n+ishsZDM8eNNdp3Ew+fEYVvY1W7mR1qU24NWj0bzVsClI7hvPVIuw7AjfBDq1C5+\r\nA+ZSLSXYvOK2cEWjdxQfuNZwEZSjmA63DUllBIrm35IaTvfuyhU6BW9yHZxmb8+M\r\nw0xDv30D5UkE\/2N7Pa\/HQJLxCR+3zKibRK3nUyRDLSXxMkU9PnFNaPNX59VPgyj4\r\nGB1CFSToldJVPF4pzh7p36uGXZVxs8m3LFD4Ol8mhi7jkxDZjqFN46gzR0r23Py6\r\ndol9vfawGIoUwp9LvL0S7MvdRY0oazLXwClLP4OQ17zpSMAiCj7fgNT661JamPGj\r\nt5O7Zn2wA7I4ddDS\/HDTWCu98Zwc9fHIpsJPgCZ9awoqxi4Mnf7Pk9g5nnXhszGC\r\ncxxIASQKM+GhdzoRxKknax2RzUCwCzcPRtCj8AQT\/x\/mqN3PfRmlnFBNACUw9bpZ\r\nSOoNq2pCF9igftDWpSIXQ38pVpKLWowjjg3DVRmVKBgivHnUnVLyzYBahHPj0vaz\r\ntFtUFRaqXDnt+4qyUGyrT5h5pjZaTcHIcSB4PiarYwdVvgslgwnQzOUcGAzRWBD4\r\n6jV2brP5vFY3g6iPAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBACTY3CCHC+Z28gCf\r\nFWGKQ3wAKs+k4+0yoti0qm2EKX7rSGQ0PHSas6uW79WstC4Rj+DYkDtIhGMSg8FS\r\nHVGZHGBCc0HwdX+BOAt3zi4p7Sf3oQef70\/4imPoKxbAVCpd\/cveVcFyDC19j1yB\r\nBapwu87oh+muoeaZxOlqQI4UxjBlR\/uRSMhOn2UGauIr3dWJgAF4pGt7TtIzt+1v\r\n0uA6FtN1Y4R5O8AaJPh1bIG0CVvFBE58esGzjEYLhOydgKFnEP94kVPgJD5ds9C3\r\npPhEpo1dRpiXaF7WGIV1X6DI\/ipWvfrF7CEy6I\/kP1InY\/vMDjQjeDnJ\/VrXIWXO\r\nyZvHXVaN\/m+1RlETsH7YO\/QmxRue9ZHN3gvvWtmpCeA95sfpepOk7UcHxHZYyQbF\r\n49\/au8j+5tsr4A83xzsT1JbcKRxkAaQ7WDJpOnE5O1+H0fB+BaLakTg6XX9d4Fo7\r\n7Gin7hVWX7pL+JIyxMzME3LhfI61+CRcqZQIrpyaafUziPQbWIPfEs7h8tCOWyvW\r\nUO8ZLervYCB3j44ivkrxPlcBklDCqqKKBzDP9dYOtS\/P4RB1NkHA9+NTvmBpTonS\r\nSFXdg9fFMD7VfjDE3Vnk+8DWkVH5wBYowTAD7w9Wuzr7DumiAULexnP\/Y7xwxLv7\r\n4B+pXTAcRK0zECDEaX3npS8xWzrB\r\n-----END CERTIFICATE-----" +}'; + $this->fileAccessHelper + ->expects($this->exactly(2)) + ->method('file_get_contents') + ->withConsecutive( + [\OC::$SERVERROOT . '/tests/data/integritycheck/app//appinfo/signature.json'], + ['/resources/codesigning/root.crt'], + ) + ->willReturnOnConsecutiveCalls( + $signatureDataFile, + file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') + ); + + $expected = [ + 'EXCEPTION' => [ + 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, + 'message' => 'Signature could not get verified.', + ], + ]; + $this->assertEquals($expected, $this->checker->verifyAppSignature('SomeApp')); + } + + public function testVerifyAppSignatureWithTamperedFiles(): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn('stable'); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(false); + + $this->appLocator + ->expects($this->once()) + ->method('getAppPath') + ->with('SomeApp') + ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData/'); + $signatureDataFile = '{ + "hashes": { + "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", + "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" + }, + "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" +}'; + $this->fileAccessHelper + ->expects($this->exactly(2)) + ->method('file_get_contents') + ->withConsecutive( + [\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//appinfo/signature.json'], + ['/resources/codesigning/root.crt'], + ) + ->willReturnOnConsecutiveCalls( + $signatureDataFile, + file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') + ); + + + $expected = [ + 'INVALID_HASH' => [ + 'AnotherFile.txt' => [ + 'expected' => '1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112', + 'current' => '7322348ba269c6d5522efe02f424fa3a0da319a7cd9c33142a5afe32a2d9af2da3a411f086fcfc96ff4301ea566f481dba0960c2abeef3594c4d930462f6584c', + ], + ], + 'FILE_MISSING' => [ + 'subfolder/file.txt' => [ + 'expected' => '410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b', + 'current' => '', + ], + ], + 'EXTRA_FILE' => [ + 'UnecessaryFile' => [ + 'expected' => '', + 'current' => 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e', + ], + ], + + ]; + $this->assertSame($expected, $this->checker->verifyAppSignature('SomeApp')); + } + + public function testVerifyAppSignatureWithTamperedFilesAndAlternatePath(): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn('stable'); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(false); + + $this->appLocator + ->expects($this->never()) + ->method('getAppPath') + ->with('SomeApp'); + $signatureDataFile = '{ + "hashes": { + "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", + "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" + }, + "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" +}'; + $this->fileAccessHelper + ->expects($this->exactly(2)) + ->method('file_get_contents') + ->withConsecutive( + [\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//appinfo/signature.json'], + ['/resources/codesigning/root.crt'], + ) + ->willReturnOnConsecutiveCalls( + $signatureDataFile, + file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') + ); + + + $expected = [ + 'INVALID_HASH' => [ + 'AnotherFile.txt' => [ + 'expected' => '1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112', + 'current' => '7322348ba269c6d5522efe02f424fa3a0da319a7cd9c33142a5afe32a2d9af2da3a411f086fcfc96ff4301ea566f481dba0960c2abeef3594c4d930462f6584c', + ], + ], + 'FILE_MISSING' => [ + 'subfolder/file.txt' => [ + 'expected' => '410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b', + 'current' => '', + ], + ], + 'EXTRA_FILE' => [ + 'UnecessaryFile' => [ + 'expected' => '', + 'current' => 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e', + ], + ], + + ]; + $this->assertSame($expected, $this->checker->verifyAppSignature('SomeApp', \OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData/')); + } + + public function testVerifyAppWithDifferentScope(): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn('stable'); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(false); + + $this->appLocator + ->expects($this->once()) + ->method('getAppPath') + ->with('SomeApp') + ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData/'); + $signatureDataFile = '{ + "hashes": { + "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", + "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" + }, + "signature": "eXesvDm3pkek12xSwMG10y9suRES79Nye3jYNe5KYq1tTUPqRRNgxmMGAfcUro0zpLeAr2YgHeSMWtglblGOW7pmwGVPZ0O1Y4r1fE6jnep0kW+35PLIaqCorIOnCAtSzDNKBhwd1ow3zW2wC0DFouuEkIO8u5Fw28g8E8dp8zEk1xMblNPy+xtWkmYHrVJ\/dQgun1bYOF2ZFtAzatwndTI\/bGsy1i3Wsl+x6HyWKQdq8y8VObtOqKDH7uERBEpB9DHVyKflj1v1gQuEH6BhaRdATc7ee0MiQdGblraIySwYRdfo2d8i82OVKrenMB3SLwyCvDPyQ9iKpTOnSF52ZBqaqSXKM2N\/RAkweeBFQQCwcHhqxvB0cfbyHcbkOLeCZe\/tsh68IxwTiYgzvLfl7sOZ5arnZbzrPpZmB+hfV2omkoJ1tDwOWz9hEmLLNtfo2OxyUH1m0+XFaC+Gbn4WkVDgf7YZkwUcG+Qoa3oKDNMss8MEyZxewl2iDGZcf402dlidHRprlfmXbAYuVQ08\/a0HxIKYPGh\/nsMGmwnO15CWtFpAbhUA\/D5oRjsIxnvXaMDg0iAFpdu\/5Ffsj7g3EPdBkiQHNYK7YU1RRx609eH0bZyiIYHdUPw7ikLupvrebZmELqi3mqDFO99u4eISlxFJlUbUND3L4BtmWTWrKwI=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIExjCCAq6gAwIBAgIUHSJjhJqMwr+3TkoiQFg4SVVYQ1gwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIzMjc1NVoXDTE2MTEwMzIzMjc1NVowFzEVMBMGA1UEAwwMQW5vdGhlclNjb3Bl\r\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA33npb5RmUkXrDT+TbwMf\r\n0zQ33SlzsjoGxCrbSwJOn6leGGInJ6ZrdzLL0WTi\/dTpg+Y\/JS+72XWm5NSjaTxo\r\n7OHc3cQBwXQj4tN6j\/y5qqY0GDLYufEkx2rpazqt9lBSJ72u1bGl2yoOXzYCz5i0\r\n60KsJXC9K44LKzGsarzbwAgskSVNkjAsPgjnCWZmcl6icpLi5Fz9rs2UMOWbdvdI\r\nAROsn0eC9E\/akmXTy5YMu6bAIGpvjZFHzyA83FQRbvv5o1V5Gsye\/VQLEgh7rqfz\r\nT\/jgWifP+JgoeB6otzuRZ3fFsmbBiyCIRtIOzQQflozhUlWtmiEGwg4GySuMUjEH\r\nA1LF86LO+ZzDQgd2oYNKmrQ8O+EcLqx9BpV4AFhEvqdk7uycJYPHs6yl+yfbzTeJ\r\n2Xd0yVAfd9r\/iDr36clLj2bzEObdl9xzKjcCIXE4Q0G4Pur41\/BJUDK9PI390ccQ\r\nnFjjVYBMsC859OwW64tMP0zkM9Vv72LCaEzaR8jqH0j11catqxunr+StfMcmxLTN\r\nbqBJbSEq4ER3mJxCTI2UrIVmdQ7+wRxgv3QTDNOZyqrz2L8A1Rpb3h0APxtQv+oA\r\n8KIZYID5\/qsS2V2jITkMQ8Nd1W3b0cZhZ600z+znh3jLJ0TYLvwN6\/qBQTUDaM2o\r\ng1+icMqXIXIeKuoPCVVsG7cCAwEAATANBgkqhkiG9w0BAQUFAAOCAgEAHc4F\/kOV\r\nHc8In5MmGg2YtjwZzjdeoC5TIPZczRqz0B+wRbJzN6aYryKZKLmP+wKpgRnJWDzp\r\nrgKGyyEQIAfK63DEv4B9p4N1B+B3aeMKsSpVcw7wbFTD57V5A7pURGoo31d0mw5L\r\nUIXZ2u+TUfGbzucMxLdFhTwjGpz9M6Kkm\/POxmV0tvLija5LdbdKnYR9BFmyu4IX\r\nqyoIAtComATNLl+3URu3SZxhE3NxhzMz+eAeNfh1KuIf2gWIIeDCXalVSJLym+OQ\r\nHFDpqRhJqfTMprrRlmmU7Zntgbj8\/RRZuXnBvH9cQ2KykLOb4UoCPlGUqOqKyP9m\r\nDJSFRiMJfpgMQUaJk1TLhKF+IR6FnmwURLEtkONJumtDQju9KaWPlhueONdyGi0p\r\nqxLVUo1Vb52XnPhk2GEEduxpDc9V5ePJ+pdcEdMifY\/uPNBRuBj2c87yq1DLH+U4\r\n3XzP1MlwjnBWZYuoFo0j6Jq0r\/MG6HjGdmkGIsRoheRi8Z8Scz5AW5QRkNz8pKop\r\nTELFqQy9g6TyQzzC8t6HZcpNe842ZUk4raEAbCZe\/XqxWMw5svPgNceBqM3fh7sZ\r\nBSykOHLaL8kiRO\/IS3y1yZEAuiWBvtxcTNLzBb+hdRpm2y8\/qH\/pKo+CMj1VzjNT\r\nD8YRQg0cjmDytJzHDrtV\/aTc9W1aPHun0vw=\r\n-----END CERTIFICATE-----" +}'; + $this->fileAccessHelper + ->expects($this->exactly(2)) + ->method('file_get_contents') + ->withConsecutive( + [\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//appinfo/signature.json'], + ['/resources/codesigning/root.crt'], + )->willReturnOnConsecutiveCalls( + $signatureDataFile, + file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') + ); + + $expected = [ + 'EXCEPTION' => [ + 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, + 'message' => 'Certificate is not valid for required scope. (Requested: SomeApp, current: CN=AnotherScope)', + ], + ]; + $this->assertSame($expected, $this->checker->verifyAppSignature('SomeApp')); + } + + public function testVerifyAppWithDifferentScopeAndAlwaysTrustedCore(): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn('stable'); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(false); + + $this->appLocator + ->expects($this->once()) + ->method('getAppPath') + ->with('SomeApp') + ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'); + $signatureDataFile = '{ + "hashes": { + "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", + "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" + }, + "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" +}'; + $this->fileAccessHelper + ->expects($this->exactly(2)) + ->method('file_get_contents') + ->withConsecutive( + [\OC::$SERVERROOT . '/tests/data/integritycheck/app//appinfo/signature.json'], + ['/resources/codesigning/root.crt'], + )->willReturnOnConsecutiveCalls( + $signatureDataFile, + file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') + ); + + $this->assertSame([], $this->checker->verifyAppSignature('SomeApp')); + } + + + public function testWriteCoreSignatureWithException(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Exception message'); + + $this->fileAccessHelper + ->expects($this->once()) + ->method('assertDirectoryExists') + ->will($this->throwException(new \Exception('Exception message'))); + $this->fileAccessHelper + ->expects($this->once()) + ->method('is_writable') + ->with(__DIR__ . '/core') + ->willReturn(true); + + $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.crt'); + $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.key'); + $rsa = new RSA(); + $rsa->loadKey($rsaPrivateKey); + $x509 = new X509(); + $x509->loadX509($keyBundle); + $this->checker->writeCoreSignature($x509, $rsa, __DIR__); + } + + + public function testWriteCoreSignatureWrongPermissions(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessageMatches('/[a-zA-Z\\/_-]+ is not writable/'); + + $this->fileAccessHelper + ->expects($this->once()) + ->method('assertDirectoryExists') + ->will($this->throwException(new \Exception('Exception message'))); + $this->fileAccessHelper + ->expects($this->once()) + ->method('is_writable') + ->with(__DIR__ . '/core') + ->willReturn(false); + + $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.crt'); + $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.key'); + $rsa = new RSA(); + $rsa->loadKey($rsaPrivateKey); + $x509 = new X509(); + $x509->loadX509($keyBundle); + $this->checker->writeCoreSignature($x509, $rsa, __DIR__); + } + + public function testWriteCoreSignature(): void { + $expectedSignatureFileData = '{ + "hashes": { + "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", + "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" + }, + "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" +}'; + $this->environmentHelper + ->expects($this->any()) + ->method('getServerRoot') + ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'); + $this->fileAccessHelper + ->expects($this->once()) + ->method('file_put_contents') + ->with( + \OC::$SERVERROOT . '/tests/data/integritycheck/app//core/signature.json', + $this->callback(function ($signature) use ($expectedSignatureFileData) { + $expectedArray = json_decode($expectedSignatureFileData, true); + $actualArray = json_decode($signature, true); + $this->assertEquals($expectedArray, $actualArray); + return true; + }) + ); + + $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/core.crt'); + $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/core.key'); + $rsa = new RSA(); + $rsa->loadKey($rsaPrivateKey); + $x509 = new X509(); + $x509->loadX509($keyBundle); + $this->checker->writeCoreSignature($x509, $rsa, \OC::$SERVERROOT . '/tests/data/integritycheck/app/'); + } + + public function testWriteCoreSignatureWithUnmodifiedHtaccess(): void { + $expectedSignatureFileData = '{ + "hashes": { + ".htaccess": "dc479770a6232061e04a768ee1f9133fdb3aea7b3a99f7105b0e0b6197474733e8d14b5b2bbad054e6b62a410fe5d0b3d790242dee1e0f11274af2100f5289e2", + "subfolder\/.htaccess": "2c57b1e25050e11dc3ae975832f378c452159f7b69f818e47eeeafadd6ba568517461dcb4d843b90b906cd7c89d161bc1b89dff8e3ae0eb6f5088508c47befd1" + }, + "signature": "nRtR377DB\/I\/4hmh9q3elMQYfSHnQFlNtjchNgrdfmUQqVmgkU\/4qgGyxDqYkV8mSMbH2gYysfP42nx\/3zSo7n0dBYDfU87Q6f96Cv597vEV27do8CaBkEk8Xjn2SxhHw8hVxracvE2OBAPxk0H3sRp\/cQBgjoXpju4kQin0N5E+DEJMh7Sp+u8aKoFpb+2FaAZJFn\/hnqxLTlVi2nyDxGL3U0eobWY+jWH9XPt52v3Hyh8TDhcAnQ1cN30B8Jn2+jkrm8ib+buchaCXHk0cPX72xuPECdwOEKLCBNrJa3FGSvO1zWiecnCgxCXgt+R8hUgsVPTsbrdFY2YRJGIhHndYZL98XzgG7cw85SnnMMe2SulzeL7xANGF8qiEVyiC7x83bbj5xOkeM\/CUTajrLBO3vyZ23KKOxvskjgI0t+Zw1zFsl+sYW0\/O\/V5WzPOwMwV8+iApQ8k9gEMiYQg98QLEMYnSohncmp0Z9qx2qFcQuHLcKJVa1J6wGtE\/EHR\/4d0aYPd6IRjg+qshCJmdzud\/12xjpGTl+BT0Hi0VsU5o7ZMi7WhmukZmmv8u0uZsvKREQNATm4cO4WCkYySt5O9gZEJOF+jjgeynDoAh09lyrNXIgMpM9ufm\/XEG\/I\/f2zIwbAUc6J6qks5OuYlJzW5vscTiOKhwcGZU9WBLgh0=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" +}'; + $this->environmentHelper + ->expects($this->any()) + ->method('getServerRoot') + ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/htaccessUnmodified/'); + $this->fileAccessHelper + ->expects($this->once()) + ->method('file_put_contents') + ->with( + \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessUnmodified//core/signature.json', + $this->callback(function ($signature) use ($expectedSignatureFileData) { + $expectedArray = json_decode($expectedSignatureFileData, true); + $actualArray = json_decode($signature, true); + $this->assertEquals($expectedArray, $actualArray); + return true; + }) + ); + + $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/core.crt'); + $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/core.key'); + $rsa = new RSA(); + $rsa->loadKey($rsaPrivateKey); + $x509 = new X509(); + $x509->loadX509($keyBundle); + $this->checker->writeCoreSignature($x509, $rsa, \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessUnmodified/'); + } + + public function testWriteCoreSignatureWithInvalidModifiedHtaccess(): void { + $expectedSignatureFileData = '{ + "hashes": { + ".htaccess": "4a54273dc8d697b2ca615acf2ae2c1ee3c1c643492cb04f42b10984fa9aacff1420dc829fd82f93ad3476fbd0cdab0251142c887dc8f872d03e39a3a3eb6d381" + }, + "signature": "qpDddYGgAKNR3TszOgjPXRphUl2P9Ym5OQaetltocgZASGDkOun5D64+1D0QJRKb4SG2+48muxGOHyL2Ngos4NUrrSR+SIkywZacay82YQBCEdr7\/4MjW1WHRPjvboLwEJwViw0EdAjsWRpD68aPnzUGrGsy2BsCo06P5iwjk9cXcHxdjC9R39npvoC3QNvQ2jmNIbh1Lc4U97dbb+CsXEQCLU1OSa9p3q6cEFV98Easwt7uF\/DzHK+CbeZlxVZ0DwLh2\/ylT1PyGou8QC1b3vKAnPjLWMO+UsCPpCKhk3C5pV+5etQ8puGd+0x2t5tEU+qXxLzek91zWNC+rqgC\/WlqLKbwPb\/BCHs4zLGV55Q2fEQmT21x0KCUELdPs4dBnYP4Ox5tEDugtJujWFzOHzoY6gGa\/BY\/78pSZXmq9o8dWkBEtioWWvaNZ1rM0ddE83GBlBTgjigi9Ay1D++bUW\/FCBB7CMk6qyNlV81H+cBuIEODw2aymmkM9LLDD2Qbmvo8gHEPRjiQxPC5OpDlcdSNiL+zcxVxeuX4FpT+9xzz\/\/DRONhufxRpsbuCOMxd96RW7y9U2N2Uxb3Bzn\/BIqEayUUsdgZjfaGcXXYKR+chu\/LOwNYN6RlnLsgqL\/dhGKwlRVKXw1RA2\/af\/CpqyR7uVP6al1YJo\/YJ+5XJ6zE=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" +}'; + $this->fileAccessHelper + ->expects($this->once()) + ->method('file_put_contents') + ->with( + \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithInvalidModifiedContent//core/signature.json', + $this->callback(function ($signature) use ($expectedSignatureFileData) { + $expectedArray = json_decode($expectedSignatureFileData, true); + $actualArray = json_decode($signature, true); + $this->assertEquals($expectedArray, $actualArray); + return true; + }) + ); + + $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/core.crt'); + $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/core.key'); + $rsa = new RSA(); + $rsa->loadKey($rsaPrivateKey); + $x509 = new X509(); + $x509->loadX509($keyBundle); + $this->checker->writeCoreSignature($x509, $rsa, \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithInvalidModifiedContent/'); + } + + public function testWriteCoreSignatureWithValidModifiedHtaccess(): void { + $expectedSignatureFileData = '{ + "hashes": { + ".htaccess": "7e6a7a4d8ee4f3fbc45dd579407c643471575a9d127d1c75f6d0a49e80766c3c587104b2139ef76d2a4bffce3f45777900605aaa49519c9532909b71e5030227", + "subfolder\/.htaccess": "2c57b1e25050e11dc3ae975832f378c452159f7b69f818e47eeeafadd6ba568517461dcb4d843b90b906cd7c89d161bc1b89dff8e3ae0eb6f5088508c47befd1" + }, + "signature": "YVwQvl9Dh8UebCumfgzFxfz3NiZJLmYG8oJVTfEBhulI4KXBnTG1jZTprf4XxG2XIriEYAZXsoXpu9xWsUFe9QfdncwoEpqJtGq7l6aVDTofX5Be5b03MQFJr4cflgllqW77QZ84D9O9qWF\/vNDAofXcwrzT04CxLDhyQgTCgYUnRjG9pnuP\/gtbDKbTjRvxhTyfg3T0Phv1+XAvpTPnH2q5A+1+LmiqziUJ1sMipsKo+jQP614eCi9qjmqhHIgLRgcuOBvsi4g5WUcdcAIZ6qLt5gm2Y3r6rKNVchosU9ZydMUTfjuejDbVwE2fNH5UUnV57fQBxwg9CfX7iFHqKv1bfv5Zviu12paShgWCB12uR3iH\/3lmTJn8K5Xqit3G4eymFaJ5IChdUThBp\/jhQSI2r8sPcZDYSJ\/UZKuFnezFdKhEBd5hMXe8aKAd6ijGDjLARksFuqpi1sS8llC5K1Q+DzktSL\/o64TY4Vuvykiwe\/BAk2SkL9voOtrvU7vfDBcuCPbDJnSBBC0ESpcXeClTBIn6xZ9WaxqoS7sinE\/kUwtWsRd04I7d79\/ouotyNb+mBhTuRsZT12p\/gn4JHXXNUAIpTwchYzGxbfNJ4kxnYBFZWVmvsSqOLFZu1yi5BP3ktA9yhFyWIa5659azRFEKRdXpVHtQVa4IgdhxEqA=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" +}'; + $this->environmentHelper + ->expects($this->any()) + ->method('getServerRoot') + ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithValidModifiedContent'); + $this->fileAccessHelper + ->expects($this->once()) + ->method('file_put_contents') + ->with( + \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithValidModifiedContent/core/signature.json', + $this->callback(function ($signature) use ($expectedSignatureFileData) { + $expectedArray = json_decode($expectedSignatureFileData, true); + $actualArray = json_decode($signature, true); + $this->assertEquals($expectedArray, $actualArray); + return true; + }) + ); + + $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/core.crt'); + $rsaPrivateKey = file_get_contents(__DIR__ .'/../../data/integritycheck/core.key'); + $rsa = new RSA(); + $rsa->loadKey($rsaPrivateKey); + $x509 = new X509(); + $x509->loadX509($keyBundle); + $this->checker->writeCoreSignature($x509, $rsa, \OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithValidModifiedContent'); + } + + public function testVerifyCoreSignatureWithoutSignatureData(): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn('stable'); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(false); + + $expected = [ + 'EXCEPTION' => [ + 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, + 'message' => 'Signature data not found.', + ], + ]; + $this->assertSame($expected, $this->checker->verifyCoreSignature()); + } + + public function testVerifyCoreSignatureWithValidSignatureData(): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn('stable'); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(false); + + $this->environmentHelper + ->expects($this->any()) + ->method('getServerRoot') + ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'); + $signatureDataFile = '{ + "hashes": { + "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", + "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" + }, + "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" +}'; + $this->fileAccessHelper + ->expects($this->exactly(2)) + ->method('file_get_contents') + ->withConsecutive( + [\OC::$SERVERROOT . '/tests/data/integritycheck/app//core/signature.json'], + [\OC::$SERVERROOT . '/tests/data/integritycheck/app//resources/codesigning/root.crt'], + )->willReturnOnConsecutiveCalls( + $signatureDataFile, + file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') + ); + + $this->assertSame([], $this->checker->verifyCoreSignature()); + } + + public function testVerifyCoreSignatureWithValidModifiedHtaccessSignatureData(): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn('stable'); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(false); + + $this->environmentHelper + ->expects($this->any()) + ->method('getServerRoot') + ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithValidModifiedContent'); + $signatureDataFile = '{ + "hashes": { + ".htaccess": "7e6a7a4d8ee4f3fbc45dd579407c643471575a9d127d1c75f6d0a49e80766c3c587104b2139ef76d2a4bffce3f45777900605aaa49519c9532909b71e5030227", + "subfolder\/.htaccess": "2c57b1e25050e11dc3ae975832f378c452159f7b69f818e47eeeafadd6ba568517461dcb4d843b90b906cd7c89d161bc1b89dff8e3ae0eb6f5088508c47befd1" + }, + "signature": "YVwQvl9Dh8UebCumfgzFxfz3NiZJLmYG8oJVTfEBhulI4KXBnTG1jZTprf4XxG2XIriEYAZXsoXpu9xWsUFe9QfdncwoEpqJtGq7l6aVDTofX5Be5b03MQFJr4cflgllqW77QZ84D9O9qWF\/vNDAofXcwrzT04CxLDhyQgTCgYUnRjG9pnuP\/gtbDKbTjRvxhTyfg3T0Phv1+XAvpTPnH2q5A+1+LmiqziUJ1sMipsKo+jQP614eCi9qjmqhHIgLRgcuOBvsi4g5WUcdcAIZ6qLt5gm2Y3r6rKNVchosU9ZydMUTfjuejDbVwE2fNH5UUnV57fQBxwg9CfX7iFHqKv1bfv5Zviu12paShgWCB12uR3iH\/3lmTJn8K5Xqit3G4eymFaJ5IChdUThBp\/jhQSI2r8sPcZDYSJ\/UZKuFnezFdKhEBd5hMXe8aKAd6ijGDjLARksFuqpi1sS8llC5K1Q+DzktSL\/o64TY4Vuvykiwe\/BAk2SkL9voOtrvU7vfDBcuCPbDJnSBBC0ESpcXeClTBIn6xZ9WaxqoS7sinE\/kUwtWsRd04I7d79\/ouotyNb+mBhTuRsZT12p\/gn4JHXXNUAIpTwchYzGxbfNJ4kxnYBFZWVmvsSqOLFZu1yi5BP3ktA9yhFyWIa5659azRFEKRdXpVHtQVa4IgdhxEqA=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" +}'; + $this->fileAccessHelper + ->expects($this->exactly(2)) + ->method('file_get_contents') + ->withConsecutive( + [\OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithValidModifiedContent/core/signature.json'], + [\OC::$SERVERROOT . '/tests/data/integritycheck/htaccessWithValidModifiedContent/resources/codesigning/root.crt'], + ) + ->willReturnOnConsecutiveCalls( + $signatureDataFile, + file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') + ); + + $this->assertSame([], $this->checker->verifyCoreSignature()); + } + + /** + * See inline instruction on how to update the test assets when changing mimetypealiases.dist.json + */ + public function testVerifyCoreSignatureWithModifiedMimetypelistSignatureData(): void { + $shippedMimetypeAliases = (array)json_decode(file_get_contents(\OC::$SERVERROOT . '/resources/config/mimetypealiases.dist.json')); + $allAliases = array_merge($shippedMimetypeAliases, ['my-custom/mimetype' => 'custom']); + + $this->mimeTypeDetector + ->method('getOnlyDefaultAliases') + ->willReturn($shippedMimetypeAliases); + + $this->mimeTypeDetector + ->method('getAllAliases') + ->willReturn($allAliases); + + $oldMimetypeList = new GenerateMimetypeFileBuilder(); + $all = $this->mimeTypeDetector->getAllAliases(); + $newFile = $oldMimetypeList->generateFile($all); + + // When updating the mimetype list the test assets need to be updated as well + // 1. Update core/js/mimetypelist.js with the new generated js by running the test with the next line uncommented: + // file_put_contents(\OC::$SERVERROOT . '/tests/data/integritycheck/mimetypeListModified/core/js/mimetypelist.js', $newFile); + // 2. Update signature.json using the following occ command: + // occ integrity:sign-core --privateKey=./tests/data/integritycheck/core.key --certificate=./tests/data/integritycheck/core.crt --path=./tests/data/integritycheck/mimetypeListModified + self::assertEquals($newFile, file_get_contents(\OC::$SERVERROOT . '/tests/data/integritycheck/mimetypeListModified/core/js/mimetypelist.js')); + + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn('stable'); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(false); + + $this->environmentHelper + ->expects($this->any()) + ->method('getServerRoot') + ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/mimetypeListModified'); + + $signatureDataFile = file_get_contents(__DIR__ .'/../../data/integritycheck/mimetypeListModified/core/signature.json'); + $this->fileAccessHelper + ->method('file_get_contents') + ->willReturnMap([ + [\OC::$SERVERROOT . '/tests/data/integritycheck/mimetypeListModified/core/signature.json', $signatureDataFile], + [\OC::$SERVERROOT . '/tests/data/integritycheck/mimetypeListModified/resources/codesigning/root.crt', file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt')], + ]); + + $this->assertSame([], $this->checker->verifyCoreSignature()); + } + + public function testVerifyCoreSignatureWithValidSignatureDataAndNotAlphabeticOrder(): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn('stable'); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(false); + + $this->environmentHelper + ->expects($this->any()) + ->method('getServerRoot') + ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'); + $signatureDataFile = '{ + "hashes": { + "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", + "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" + }, + "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" +}'; + $this->fileAccessHelper + ->expects($this->exactly(2)) + ->method('file_get_contents') + ->withConsecutive( + [\OC::$SERVERROOT . '/tests/data/integritycheck/app//core/signature.json'], + [\OC::$SERVERROOT . '/tests/data/integritycheck/app//resources/codesigning/root.crt'], + )->willReturnOnConsecutiveCalls( + $signatureDataFile, + file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') + ); + + $this->assertSame([], $this->checker->verifyCoreSignature()); + } + + public function testVerifyCoreSignatureWithTamperedSignatureData(): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn('stable'); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(false); + + $this->environmentHelper + ->expects($this->any()) + ->method('getServerRoot') + ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData/'); + $signatureDataFile = '{ + "hashes": { + "AnotherFile.txt": "tampered", + "subfolder\/file.txt": "tampered" + }, + "signature": "eXesvDm3pkek12xSwMG10y9suRES79Nye3jYNe5KYq1tTUPqRRNgxmMGAfcUro0zpLeAr2YgHeSMWtglblGOW7pmwGVPZ0O1Y4r1fE6jnep0kW+35PLIaqCorIOnCAtSzDNKBhwd1ow3zW2wC0DFouuEkIO8u5Fw28g8E8dp8zEk1xMblNPy+xtWkmYHrVJ\/dQgun1bYOF2ZFtAzatwndTI\/bGsy1i3Wsl+x6HyWKQdq8y8VObtOqKDH7uERBEpB9DHVyKflj1v1gQuEH6BhaRdATc7ee0MiQdGblraIySwYRdfo2d8i82OVKrenMB3SLwyCvDPyQ9iKpTOnSF52ZBqaqSXKM2N\/RAkweeBFQQCwcHhqxvB0cfbyHcbkOLeCZe\/tsh68IxwTiYgzvLfl7sOZ5arnZbzrPpZmB+hfV2omkoJ1tDwOWz9hEmLLNtfo2OxyUH1m0+XFaC+Gbn4WkVDgf7YZkwUcG+Qoa3oKDNMss8MEyZxewl2iDGZcf402dlidHRprlfmXbAYuVQ08\/a0HxIKYPGh\/nsMGmwnO15CWtFpAbhUA\/D5oRjsIxnvXaMDg0iAFpdu\/5Ffsj7g3EPdBkiQHNYK7YU1RRx609eH0bZyiIYHdUPw7ikLupvrebZmELqi3mqDFO99u4eISlxFJlUbUND3L4BtmWTWrKwI=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" +}'; + $this->fileAccessHelper + ->expects($this->exactly(2)) + ->method('file_get_contents') + ->withConsecutive( + [\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//core/signature.json'], + [\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//resources/codesigning/root.crt'], + )->willReturnOnConsecutiveCalls( + $signatureDataFile, + file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') + ); + + $expected = [ + 'EXCEPTION' => [ + 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, + 'message' => 'Signature could not get verified.', + ] + ]; + $this->assertSame($expected, $this->checker->verifyCoreSignature()); + } + + public function testVerifyCoreSignatureWithTamperedFiles(): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn('stable'); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(false); + + $this->environmentHelper + ->expects($this->any()) + ->method('getServerRoot') + ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData/'); + $signatureDataFile = '{ + "hashes": { + "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", + "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" + }, + "signature": "dYoohBaWIFR\/To1FXEbMQB5apUhVYlEauBGSPo12nq84wxWkBx2EM3KDRgkB5Sub2tr0CgmAc2EVjPhKIEzAam26cyUb48bJziz1V6wvW7z4GZAfaJpzLkyHdSfV5117VSf5w1rDcAeZDXfGUaaNEJPWytaF4ZIxVge7f3NGshHy4odFVPADy\/u6c43BWvaOtJ4m3aJQbP6sxCO9dxwcm5yJJJR3n36jfh229sdWBxyl8BhwhH1e1DEv78\/aiL6ckKFPVNzx01R6yDFt3TgEMR97YZ\/R6lWiXG+dsJ305jNFlusLu518zBUvl7g5yjzGN778H29b2C8VLZKmi\/h1CH9jGdD72fCqCYdenD2uZKzb6dsUtXtvBmVcVT6BUGz41W1pkkEEB+YJpMrHILIxAiHRGv1+aZa9\/Oz8LWFd+BEUQjC2LJgojPnpzaG\/msw1nBkX16NNVDWWtJ25Bc\/r\/mG46rwjWB\/cmV6Lwt6KODiqlxgrC4lm9ALOCEWw+23OcYhLwNfQTYevXqHqsFfXOkhUnM8z5vDUb\/HBraB1DjFXN8iLK+1YewD4P495e+SRzrR79Oi3F8SEqRIzRLfN2rnW1BTms\/wYsz0p67cup1Slk1XlNmHwbWX25NVd2PPlLOvZRGoqcKFpIjC5few8THiZfyjiNFwt3RM0AFdZcXY=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUc\/0FxYrsgSs9rDxp03EJmbjN0NwwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIxMDMzM1oXDTE2MTEwMzIxMDMzM1owDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBALb6EgHpkAqZbO5vRO8XSh7G7XGWHw5s\r\niOf4RwPXR6SE9bWZEm\/b72SfWk\/\/J6AbrD8WiOzBuT\/ODy6k5T1arEdHO+Pux0W1\r\nMxYJJI4kH74KKgMpC0SB0Rt+8WrMqV1r3hhJ46df6Xr\/xolP3oD+eLbShPcblhdS\r\nVtkZEkoev8Sh6L2wDCeHDyPxzvj1w2dTdGVO9Kztn0xIlyfEBakqvBWtcxyi3Ln0\r\nklnxlMx3tPDUE4kqvpia9qNiB1AN2PV93eNr5\/2riAzIssMFSCarWCx0AKYb54+d\r\nxLpcYFyqPJ0ydBCkF78DD45RCZet6PNYkdzgbqlUWEGGomkuDoJbBg4wzgzO0D77\r\nH87KFhYW8tKFFvF1V3AHl\/sFQ9tDHaxM9Y0pZ2jPp\/ccdiqnmdkBxBDqsiRvHvVB\r\nCn6qpb4vWGFC7vHOBfYspmEL1zLlKXZv3ezMZEZw7O9ZvUP3VO\/wAtd2vUW8UFiq\r\ns2v1QnNLN6jNh51obcwmrBvWhJy9vQIdtIjQbDxqWTHh1zUSrw9wrlklCBZ\/zrM0\r\ni8nfCFwTxWRxp3H9KoECzO\/zS5R5KIS7s3\/wq\/w9T2Ie4rcecgXwDizwnn0C\/aKc\r\nbDIjujpL1s9HO05pcD\/V3wKcPZ1izymBkmMyIbL52iRVN5FTVHeZdXPpFuq+CTQJ\r\nQ238lC+A\/KOVAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAGoKTnh8RfJV4sQItVC2\r\nAvfJagkrIqZ3iiQTUBQGTKBsTnAqE1H7QgUSV9vSd+8rgvHkyZsRjmtyR1e3A6Ji\r\noNCXUbExC\/0iCPUqdHZIVb+Lc\/vWuv4ByFMybGPydgtLoEUX2ZrKFWmcgZFDUSRd\r\n9Uj26vtUhCC4bU4jgu6hIrR9IuxOBLQUxGTRZyAcXvj7obqRAEZwFAKQgFpfpqTb\r\nH+kjcbZSaAlLVSF7vBc1syyI8RGYbqpwvtREqJtl5IEIwe6huEqJ3zPnlP2th\/55\r\ncf3Fovj6JJgbb9XFxrdnsOsDOu\/tpnaRWlvv5ib4+SzG5wWFT5UUEo4Wg2STQiiX\r\nuVSRQxK1LE1yg84bs3NZk9FSQh4B8vZVuRr5FaJsZZkwlFlhRO\/\/+TJtXRbyNgsf\r\noMRZGi8DLGU2SGEAHcRH\/QZHq\/XDUWVzdxrSBYcy7GSpT7UDVzGv1rEJUrn5veP1\r\n0KmauAqtiIaYRm4f6YBsn0INcZxzIPZ0p8qFtVZBPeHhvQtvOt0iXI\/XUxEWOa2F\r\nK2EqhErgMK\/N07U1JJJay5tYZRtvkGq46oP\/5kQG8hYST0MDK6VihJoPpvCmAm4E\r\npEYKQ96x6A4EH9Y9mZlYozH\/eqmxPbTK8n89\/p7Ydun4rI+B2iiLnY8REWWy6+UQ\r\nV204fGUkJqW5CrKy3P3XvY9X\r\n-----END CERTIFICATE-----" +}'; + $this->fileAccessHelper + ->expects($this->exactly(2)) + ->method('file_get_contents') + ->withConsecutive( + [\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//core/signature.json'], + [\OC::$SERVERROOT . '/tests/data/integritycheck/appWithInvalidData//resources/codesigning/root.crt'], + )->willReturnOnConsecutiveCalls( + $signatureDataFile, + file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') + ); + + $expected = [ + 'INVALID_HASH' => [ + 'AnotherFile.txt' => [ + 'expected' => '1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112', + 'current' => '7322348ba269c6d5522efe02f424fa3a0da319a7cd9c33142a5afe32a2d9af2da3a411f086fcfc96ff4301ea566f481dba0960c2abeef3594c4d930462f6584c', + ], + ], + 'FILE_MISSING' => [ + 'subfolder/file.txt' => [ + 'expected' => '410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b', + 'current' => '', + ], + ], + 'EXTRA_FILE' => [ + 'UnecessaryFile' => [ + 'expected' => '', + 'current' => 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e', + ], + ], + + ]; + $this->assertSame($expected, $this->checker->verifyCoreSignature()); + } + + public function testVerifyCoreWithInvalidCertificate(): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn('stable'); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(false); + + $this->environmentHelper + ->expects($this->any()) + ->method('getServerRoot') + ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'); + $signatureDataFile = '{ + "hashes": { + "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", + "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" + }, + "signature": "eXesvDm3pkek12xSwMG10y9suRES79Nye3jYNe5KYq1tTUPqRRNgxmMGAfcUro0zpLeAr2YgHeSMWtglblGOW7pmwGVPZ0O1Y4r1fE6jnep0kW+35PLIaqCorIOnCAtSzDNKBhwd1ow3zW2wC0DFouuEkIO8u5Fw28g8E8dp8zEk1xMblNPy+xtWkmYHrVJ\/dQgun1bYOF2ZFtAzatwndTI\/bGsy1i3Wsl+x6HyWKQdq8y8VObtOqKDH7uERBEpB9DHVyKflj1v1gQuEH6BhaRdATc7ee0MiQdGblraIySwYRdfo2d8i82OVKrenMB3SLwyCvDPyQ9iKpTOnSF52ZBqaqSXKM2N\/RAkweeBFQQCwcHhqxvB0cfbyHcbkOLeCZe\/tsh68IxwTiYgzvLfl7sOZ5arnZbzrPpZmB+hfV2omkoJ1tDwOWz9hEmLLNtfo2OxyUH1m0+XFaC+Gbn4WkVDgf7YZkwUcG+Qoa3oKDNMss8MEyZxewl2iDGZcf402dlidHRprlfmXbAYuVQ08\/a0HxIKYPGh\/nsMGmwnO15CWtFpAbhUA\/D5oRjsIxnvXaMDg0iAFpdu\/5Ffsj7g3EPdBkiQHNYK7YU1RRx609eH0bZyiIYHdUPw7ikLupvrebZmELqi3mqDFO99u4eISlxFJlUbUND3L4BtmWTWrKwI=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEvjCCAqagAwIBAgIUPYoweUxCPqbDW4ntuh7QvgyqSrgwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIyNDIwNloXDTE2MTEwMzIyNDIwNlowDzENMAsGA1UEAwwEY29yZTCCAiIwDQYJ\r\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJui3nDbjOIjxNnthdBZplphujsN6u8K\r\nQ\/62zAuSwzXVp0+3IMgM\/2sepklVE8YfCyVJ5+SUJqnqHoUWVRVfs8jL0wW6nrHM\r\n\/lsscAguWCee4iAdNOqI9kq4+DUau8J45e62XA9mrAo\/8\/NKzFE2y2WduDoQZcm+\r\n8+dwcUUHXw2jl8dfrmvEMYSqTNDdb4rGmQpeV+dr9BLqr+x03U1Q08qCG9j7mSOz\r\ncvJENjOvC5uzAh5LCuCgxqG4o+mPzB0FtNnwoRRu6IsF3Y3KacRqPc30fB\/iXDn5\r\nBPr14uNxTTYWoZJ1F0tZrLzRbXdjJJOC+dnQurTtXWZ8WjPB1BWQYK7fW6t82mkN\r\n2Qe2xen99gs9nX5yY\/sHM3TKSJdM7AVCEv\/emW3gNjkvWTtRlN\/Nc7X2ckNwXcvo\r\n0yi3fSPjzXpDgLbhp1FzrMlHDn1VzmRT3r8wLByWa\/hsxrJDsBzwunMJYhXhmeKb\r\n3wX0tN\/EUJTWBntpwVOIGnRPD51oBoQUOMaEAq\/kz8PgN181bWZkJbRuf+FWkijQ\r\no+HR2lVF1jWXXst5Uc+s9HN81Uly7X4O9MMg0QxT4+wymtGDs6AOkwMi9rgBTrRB\r\n3tLU3XL2UIwRXgmd8cPtTu\/I6Bm7LdyaYtZ3yJTxRewq3nZdWypqBhD8uhpIYVkf\r\no4bxmGkVAQVTAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBAKKAX5EHgU1grODnJ0of\r\nspFpgB1K67YvclNUyuU6NQ6zBJx1\/w1RnM7uxLcxiiWj1BbUhwZQ0ojmEHeUyi6O\r\nGrDVajwhTccDMmja3u5adhEncx65\/H+lD85IPRRkS2qBDssMDdJHhZ0uI+40nI7M\r\nMq1kFjl+6wiuqZXqps66DuLbk45g\/ZlrFIrIo3Ix5vj0OVqwT+gO4LYirJK6KgVS\r\nUttbcEsc\/yKU9ThnM8\/n4m2jstZXfzKPgOsJrQcZrFOtpj+CWmBzVElBSPlDT3Nh\r\nHSgOeTFJ8bQBxj2iG5dLA+JZJQKxyJ1gy2ZtxIJ2GyvLtSe8NUSqvfPWOaAKEUV2\r\ngniytnEFLr+PcD+9EGux6jZNuj6HmtWVThTfD5VGFmtlVU2z71ZRYY0kn6J3mmFc\r\nS2ecEcCUwqG5YNLncEUCyZhC2klWql2SHyGctCEyWWY7ikIDjVzYt2EbcFvLNBnP\r\ntybN1TYHRRZxlug00CCoOE9EZfk46FkZpDvU6KmqJRofkNZ5sj+SffyGcwYwNrDH\r\nKqe8m+9lHf3CRTIDeMu8r2xl1I6M6ZZfjabbmVP9Jd6WN4s6f1FlXDWzhlT1N0Qw\r\nGzJj6xB+SPtS3UV05tBlvbfA4e06D5G9uD7Q8ONcINtMS0xsSJ2oo82AqlpvlF\/q\r\noj7YKHsaTVGA+FxBktZHfoxD\r\n-----END CERTIFICATE-----" +}'; + $this->fileAccessHelper + ->expects($this->exactly(2)) + ->method('file_get_contents') + ->withConsecutive( + [\OC::$SERVERROOT . '/tests/data/integritycheck/app//core/signature.json'], + [\OC::$SERVERROOT . '/tests/data/integritycheck/app//resources/codesigning/root.crt'], + )->willReturnOnConsecutiveCalls( + $signatureDataFile, + file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') + ); + + $expected = [ + 'EXCEPTION' => [ + 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, + 'message' => 'Certificate is not valid.', + ] + ]; + $this->assertSame($expected, $this->checker->verifyCoreSignature()); + } + + public function testVerifyCoreWithDifferentScope(): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn('stable'); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(false); + + $this->environmentHelper + ->expects($this->any()) + ->method('getServerRoot') + ->willReturn(\OC::$SERVERROOT . '/tests/data/integritycheck/app/'); + $signatureDataFile = '{ + "hashes": { + "AnotherFile.txt": "1570ca9420e37629de4328f48c51da29840ddeaa03ae733da4bf1d854b8364f594aac560601270f9e1797ed4cd57c1aea87bf44cf4245295c94f2e935a2f0112", + "subfolder\/file.txt": "410738545fb623c0a5c8a71f561e48ea69e3ada0981a455e920a5ae9bf17c6831ae654df324f9328ff8453de179276ae51931cca0fa71fe8ccde6c083ca0574b" + }, + "signature": "EL49UaSeyMAqyMtqId+tgOhhwgOevPZsRLX4j2blnybAB6fN07z0936JqZV7+eMPiE30Idx+UCY6rCFN531Kqe9vAOCdgtHUSOjjKyKc+lvULESlMb6YQcrZrvDlEMMjzjH49ewG7Ai8sNN6HrRUd9U8ws+ewSkW2DOOBItj\/21RBnkrSt+2AtGXGigEvuTm57HrCYDj8\/lSkumC2GVkjLUHeLOKYo4PRNOr6yP5mED5v7zo66AWvXl2fKv54InZcdxsAk35lyK9DGZbk\/027ZRd0AOHT3LImRLvQ+8EAg3XLlRUy0hOFGgPC+jYonMzgYvsAXAXi2j8LnLJlsLwpFwu1k1B+kZVPMumKZvP9OvJb70EirecXmz62V+Jiyuaq7ne4y7Kp5gKZT\/T8SeZ0lFtCmPfYyzBB0y8s5ldmTTmdVYHs54t\/OCCW82HzQZxnFNPzDTRa8HglsaMKrqPtW59+R4UvRKSWhB8M\/Ah57qgzycvPV4KMz\/FbD4l\/\/9chRKSlCfc2k3b8ZSHNmi+EzCKgJjWIoKdgN1yax94puU8jfn8UW+G7H9Y1Jsf\/jox6QLyYEgtV1vOHY2xLT7fVs2vhyvkN2MNjJnmQ70gFG5Qz2lBz5wi6ZpB+tOfCcpbLxWAkoWoIrmC\/Ilqh7mfmRZ43g5upjkepHNd93ONuY8=", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEwTCCAqmgAwIBAgIUWv0iujufs5lUr0svCf\/qTQvoyKAwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIyNDk1M1oXDTE2MTEwMzIyNDk1M1owEjEQMA4GA1UEAwwHU29tZUFwcDCCAiIw\r\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK8q0x62agGSRBqeWsaeEwFfepMk\r\nF8cAobMMi50qHCv9IrOn\/ZH9l52xBrbIkErVmRjmly0d4JhD8Ymhidsh9ONKYl\/j\r\n+ishsZDM8eNNdp3Ew+fEYVvY1W7mR1qU24NWj0bzVsClI7hvPVIuw7AjfBDq1C5+\r\nA+ZSLSXYvOK2cEWjdxQfuNZwEZSjmA63DUllBIrm35IaTvfuyhU6BW9yHZxmb8+M\r\nw0xDv30D5UkE\/2N7Pa\/HQJLxCR+3zKibRK3nUyRDLSXxMkU9PnFNaPNX59VPgyj4\r\nGB1CFSToldJVPF4pzh7p36uGXZVxs8m3LFD4Ol8mhi7jkxDZjqFN46gzR0r23Py6\r\ndol9vfawGIoUwp9LvL0S7MvdRY0oazLXwClLP4OQ17zpSMAiCj7fgNT661JamPGj\r\nt5O7Zn2wA7I4ddDS\/HDTWCu98Zwc9fHIpsJPgCZ9awoqxi4Mnf7Pk9g5nnXhszGC\r\ncxxIASQKM+GhdzoRxKknax2RzUCwCzcPRtCj8AQT\/x\/mqN3PfRmlnFBNACUw9bpZ\r\nSOoNq2pCF9igftDWpSIXQ38pVpKLWowjjg3DVRmVKBgivHnUnVLyzYBahHPj0vaz\r\ntFtUFRaqXDnt+4qyUGyrT5h5pjZaTcHIcSB4PiarYwdVvgslgwnQzOUcGAzRWBD4\r\n6jV2brP5vFY3g6iPAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBACTY3CCHC+Z28gCf\r\nFWGKQ3wAKs+k4+0yoti0qm2EKX7rSGQ0PHSas6uW79WstC4Rj+DYkDtIhGMSg8FS\r\nHVGZHGBCc0HwdX+BOAt3zi4p7Sf3oQef70\/4imPoKxbAVCpd\/cveVcFyDC19j1yB\r\nBapwu87oh+muoeaZxOlqQI4UxjBlR\/uRSMhOn2UGauIr3dWJgAF4pGt7TtIzt+1v\r\n0uA6FtN1Y4R5O8AaJPh1bIG0CVvFBE58esGzjEYLhOydgKFnEP94kVPgJD5ds9C3\r\npPhEpo1dRpiXaF7WGIV1X6DI\/ipWvfrF7CEy6I\/kP1InY\/vMDjQjeDnJ\/VrXIWXO\r\nyZvHXVaN\/m+1RlETsH7YO\/QmxRue9ZHN3gvvWtmpCeA95sfpepOk7UcHxHZYyQbF\r\n49\/au8j+5tsr4A83xzsT1JbcKRxkAaQ7WDJpOnE5O1+H0fB+BaLakTg6XX9d4Fo7\r\n7Gin7hVWX7pL+JIyxMzME3LhfI61+CRcqZQIrpyaafUziPQbWIPfEs7h8tCOWyvW\r\nUO8ZLervYCB3j44ivkrxPlcBklDCqqKKBzDP9dYOtS\/P4RB1NkHA9+NTvmBpTonS\r\nSFXdg9fFMD7VfjDE3Vnk+8DWkVH5wBYowTAD7w9Wuzr7DumiAULexnP\/Y7xwxLv7\r\n4B+pXTAcRK0zECDEaX3npS8xWzrB\r\n-----END CERTIFICATE-----" +}'; + $this->fileAccessHelper + ->expects($this->exactly(2)) + ->method('file_get_contents') + ->withConsecutive( + [\OC::$SERVERROOT . '/tests/data/integritycheck/app//core/signature.json'], + [\OC::$SERVERROOT . '/tests/data/integritycheck/app//resources/codesigning/root.crt'], + )->willReturnOnConsecutiveCalls( + $signatureDataFile, + file_get_contents(__DIR__ .'/../../data/integritycheck/root.crt') + ); + + $expected = [ + 'EXCEPTION' => [ + 'class' => \OC\IntegrityCheck\Exceptions\InvalidSignatureException::class, + 'message' => 'Certificate is not valid for required scope. (Requested: core, current: CN=SomeApp)', + ] + ]; + $this->assertSame($expected, $this->checker->verifyCoreSignature()); + } + + public function testRunInstanceVerification(): void { + $this->checker = $this->getMockBuilder(\OC\IntegrityCheck\Checker::class) + ->setConstructorArgs([ + $this->environmentHelper, + $this->fileAccessHelper, + $this->appLocator, + $this->config, + $this->appConfig, + $this->cacheFactory, + $this->appManager, + $this->mimeTypeDetector, + ]) + ->setMethods([ + 'verifyCoreSignature', + 'verifyAppSignature', + ]) + ->getMock(); + + $this->checker + ->expects($this->once()) + ->method('verifyCoreSignature'); + $this->appManager + ->expects($this->once()) + ->method('getAllAppsInAppsFolders') + ->willReturn([ + 'files', + 'calendar', + 'contacts', + 'dav', + ]); + $this->appManager + ->expects($this->exactly(4)) + ->method('isShipped') + ->withConsecutive( + ['files'], + ['calendar'], + ['contacts'], + ['dav'], + )->willReturnOnConsecutiveCalls( + true, + false, + false, + true, + ); + $this->checker + ->expects($this->exactly(3)) + ->method('verifyAppSignature') + ->withConsecutive( + ['files'], + ['calendar'], + ['dav'], + ); + $this->appLocator + ->expects($this->exactly(2)) + ->method('getAppPath') + ->withConsecutive( + ['calendar'], + ['contacts'], + )->willReturnOnConsecutiveCalls( + '/apps/calendar', + '/apps/contacts', + ); + $this->fileAccessHelper + ->expects($this->exactly(2)) + ->method('file_exists') + ->withConsecutive( + ['/apps/calendar/appinfo/signature.json'], + ['/apps/contacts/appinfo/signature.json'], + )->willReturnOnConsecutiveCalls( + true, + false, + ); + $this->appConfig + ->expects($this->once()) + ->method('deleteKey') + ->with('core', 'oc.integritycheck.checker'); + + $this->checker->runInstanceVerification(); + } + + public function testVerifyAppSignatureWithoutSignatureDataAndCodeCheckerDisabled(): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn('stable'); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(true); + + $expected = []; + $this->assertSame($expected, $this->checker->verifyAppSignature('SomeApp')); + } + + /** + * @return array + */ + public function channelDataProvider() { + return [ + ['stable', true], + ['git', false], + ]; + } + + /** + * @param string $channel + * @param bool $isCodeSigningEnforced + * @dataProvider channelDataProvider + */ + public function testIsCodeCheckEnforced($channel, $isCodeSigningEnforced): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn($channel); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(false); + + $this->assertSame($isCodeSigningEnforced, $this->checker->isCodeCheckEnforced()); + } + + /** + * @param string $channel + * @dataProvider channelDataProvider + */ + public function testIsCodeCheckEnforcedWithDisabledConfigSwitch($channel): void { + $this->environmentHelper + ->expects($this->once()) + ->method('getChannel') + ->willReturn($channel); + $this->config + ->expects($this->any()) + ->method('getSystemValueBool') + ->with('integrity.check.disabled', false) + ->willReturn(true); + + $this->assertFalse(self::invokePrivate($this->checker, 'isCodeCheckEnforced')); + } +} diff --git a/tests/lib/Mail/MailerTest.php b/tests/lib/Mail/MailerTest.php index 9f37b776f17..c15b4b1a748 100644 --- a/tests/lib/Mail/MailerTest.php +++ b/tests/lib/Mail/MailerTest.php @@ -179,7 +179,7 @@ class MailerTest extends TestCase { ->method('getSystemValueBool') ->with('mail_send_plaintext_only', false) ->willReturn(false); - $this->assertInstanceOf('\OC\Mail\Message', $this->mailer->createMessage()); + $this->assertInstanceOf(\OC\Mail\Message::class, $this->mailer->createMessage()); } @@ -194,7 +194,7 @@ class MailerTest extends TestCase { $this->expectException(\Exception::class); /** @var Message&MockObject */ - $message = $this->getMockBuilder('\OC\Mail\Message') + $message = $this->getMockBuilder(\OC\Mail\Message::class) ->disableOriginalConstructor()->getMock(); $message->expects($this->once()) ->method('getSymfonyEmail') diff --git a/tests/lib/Memcache/CasTraitTest.php b/tests/lib/Memcache/CasTraitTest.php index 129819045f2..c8b35d5cb0d 100644 --- a/tests/lib/Memcache/CasTraitTest.php +++ b/tests/lib/Memcache/CasTraitTest.php @@ -18,7 +18,7 @@ class CasTraitTest extends TestCase { */ private function getCache() { $sourceCache = new \OC\Memcache\ArrayCache(); - $mock = $this->getMockForTrait('\OC\Memcache\CasTrait'); + $mock = $this->getMockForTrait(\OC\Memcache\CasTrait::class); $mock->expects($this->any()) ->method('set') diff --git a/tests/lib/Migration/BackgroundRepairTest.php b/tests/lib/Migration/BackgroundRepairTest.php index 585ebc420ad..318b3a36856 100644 --- a/tests/lib/Migration/BackgroundRepairTest.php +++ b/tests/lib/Migration/BackgroundRepairTest.php @@ -106,7 +106,7 @@ class BackgroundRepairTest extends TestCase { $this->job->setArgument([ 'app' => 'test', - 'step' => '\Test\Migration\TestRepairStep' + 'step' => \Test\Migration\TestRepairStep::class ]); $this->job->start($this->jobList); } diff --git a/tests/lib/OCS/ProviderTest.php b/tests/lib/OCS/ProviderTest.php index 3834c1d613e..a86a2b1aebb 100644 --- a/tests/lib/OCS/ProviderTest.php +++ b/tests/lib/OCS/ProviderTest.php @@ -20,8 +20,8 @@ class ProviderTest extends \Test\TestCase { protected function setUp(): void { parent::setUp(); - $this->request = $this->getMockBuilder('\\OCP\\IRequest')->getMock(); - $this->appManager = $this->getMockBuilder('\\OCP\\App\\IAppManager')->getMock(); + $this->request = $this->getMockBuilder(\OCP\IRequest::class)->getMock(); + $this->appManager = $this->getMockBuilder(\OCP\App\IAppManager::class)->getMock(); $this->ocsProvider = new Provider('ocs_provider', $this->request, $this->appManager); } diff --git a/tests/lib/Repair/CleanTagsTest.php b/tests/lib/Repair/CleanTagsTest.php index 13aca706a5a..f484a0cd1aa 100644 --- a/tests/lib/Repair/CleanTagsTest.php +++ b/tests/lib/Repair/CleanTagsTest.php @@ -37,7 +37,7 @@ class CleanTagsTest extends \Test\TestCase { protected function setUp(): void { parent::setUp(); - $this->outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + $this->outputMock = $this->getMockBuilder(\OCP\Migration\IOutput::class) ->disableOriginalConstructor() ->getMock(); diff --git a/tests/lib/Repair/OldGroupMembershipSharesTest.php b/tests/lib/Repair/OldGroupMembershipSharesTest.php index 5d3590499e6..269e2f016cf 100644 --- a/tests/lib/Repair/OldGroupMembershipSharesTest.php +++ b/tests/lib/Repair/OldGroupMembershipSharesTest.php @@ -32,7 +32,7 @@ class OldGroupMembershipSharesTest extends \Test\TestCase { parent::setUp(); /** \OCP\IGroupManager|\PHPUnit\Framework\MockObject\MockObject */ - $this->groupManager = $this->getMockBuilder('OCP\IGroupManager') + $this->groupManager = $this->getMockBuilder(\OCP\IGroupManager::class) ->disableOriginalConstructor() ->getMock(); $this->connection = \OC::$server->getDatabaseConnection(); @@ -82,7 +82,7 @@ class OldGroupMembershipSharesTest extends \Test\TestCase { $result->closeCursor(); /** @var IOutput | \PHPUnit\Framework\MockObject\MockObject $outputMock */ - $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + $outputMock = $this->getMockBuilder(\OCP\Migration\IOutput::class) ->disableOriginalConstructor() ->getMock(); diff --git a/tests/lib/Repair/RepairCollationTest.php b/tests/lib/Repair/RepairCollationTest.php index 2b5091ad927..82d0a3702a0 100644 --- a/tests/lib/Repair/RepairCollationTest.php +++ b/tests/lib/Repair/RepairCollationTest.php @@ -81,7 +81,7 @@ class RepairCollationTest extends TestCase { $this->assertGreaterThanOrEqual(1, count($tables)); /** @var IOutput | \PHPUnit\Framework\MockObject\MockObject $outputMock */ - $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + $outputMock = $this->getMockBuilder(\OCP\Migration\IOutput::class) ->disableOriginalConstructor() ->getMock(); diff --git a/tests/lib/Repair/RepairInvalidSharesTest.php b/tests/lib/Repair/RepairInvalidSharesTest.php index d728e0c7ecd..23d03ba14af 100644 --- a/tests/lib/Repair/RepairInvalidSharesTest.php +++ b/tests/lib/Repair/RepairInvalidSharesTest.php @@ -109,7 +109,7 @@ class RepairInvalidSharesTest extends TestCase { $result->closeCursor(); /** @var IOutput | \PHPUnit\Framework\MockObject\MockObject $outputMock */ - $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + $outputMock = $this->getMockBuilder(\OCP\Migration\IOutput::class) ->disableOriginalConstructor() ->getMock(); @@ -172,7 +172,7 @@ class RepairInvalidSharesTest extends TestCase { $shareId = $this->getLastShareId(); /** @var IOutput | \PHPUnit\Framework\MockObject\MockObject $outputMock */ - $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + $outputMock = $this->getMockBuilder(\OCP\Migration\IOutput::class) ->disableOriginalConstructor() ->getMock(); diff --git a/tests/lib/Repair/RepairMimeTypesTest.php b/tests/lib/Repair/RepairMimeTypesTest.php index 0f1a945bd8d..3efef4b3bf5 100644 --- a/tests/lib/Repair/RepairMimeTypesTest.php +++ b/tests/lib/Repair/RepairMimeTypesTest.php @@ -98,7 +98,7 @@ class RepairMimeTypesTest extends \Test\TestCase { $this->addEntries($currentMimeTypes); /** @var IOutput | \PHPUnit\Framework\MockObject\MockObject $outputMock */ - $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + $outputMock = $this->getMockBuilder(\OCP\Migration\IOutput::class) ->disableOriginalConstructor() ->getMock(); diff --git a/tests/lib/Security/Bruteforce/Backend/MemoryCacheBackendTest.php b/tests/lib/Security/Bruteforce/Backend/MemoryCacheBackendTest.php index 82bffb74e01..e566f4f4e5a 100644 --- a/tests/lib/Security/Bruteforce/Backend/MemoryCacheBackendTest.php +++ b/tests/lib/Security/Bruteforce/Backend/MemoryCacheBackendTest.php @@ -36,7 +36,7 @@ class MemoryCacheBackendTest extends TestCase { $this->cacheFactory ->expects($this->once()) ->method('createDistributed') - ->with('OC\Security\Bruteforce\Backend\MemoryCacheBackend') + ->with(\OC\Security\Bruteforce\Backend\MemoryCacheBackend::class) ->willReturn($this->cache); $this->backend = new MemoryCacheBackend( diff --git a/tests/lib/Security/CSRF/CsrfTokenGeneratorTest.php b/tests/lib/Security/CSRF/CsrfTokenGeneratorTest.php index 98eddf602ee..dca60d022d2 100644 --- a/tests/lib/Security/CSRF/CsrfTokenGeneratorTest.php +++ b/tests/lib/Security/CSRF/CsrfTokenGeneratorTest.php @@ -18,7 +18,7 @@ class CsrfTokenGeneratorTest extends \Test\TestCase { protected function setUp(): void { parent::setUp(); - $this->random = $this->getMockBuilder('\OCP\Security\ISecureRandom') + $this->random = $this->getMockBuilder(\OCP\Security\ISecureRandom::class) ->disableOriginalConstructor()->getMock(); $this->csrfTokenGenerator = new \OC\Security\CSRF\CsrfTokenGenerator($this->random); } diff --git a/tests/lib/Security/CSRF/CsrfTokenManagerTest.php b/tests/lib/Security/CSRF/CsrfTokenManagerTest.php index 47f873bfe13..aeb512f1521 100644 --- a/tests/lib/Security/CSRF/CsrfTokenManagerTest.php +++ b/tests/lib/Security/CSRF/CsrfTokenManagerTest.php @@ -20,9 +20,9 @@ class CsrfTokenManagerTest extends \Test\TestCase { protected function setUp(): void { parent::setUp(); - $this->tokenGenerator = $this->getMockBuilder('\OC\Security\CSRF\CsrfTokenGenerator') + $this->tokenGenerator = $this->getMockBuilder(\OC\Security\CSRF\CsrfTokenGenerator::class) ->disableOriginalConstructor()->getMock(); - $this->storageInterface = $this->getMockBuilder('\OC\Security\CSRF\TokenStorage\SessionStorage') + $this->storageInterface = $this->getMockBuilder(\OC\Security\CSRF\TokenStorage\SessionStorage::class) ->disableOriginalConstructor()->getMock(); $this->csrfTokenManager = new \OC\Security\CSRF\CsrfTokenManager( diff --git a/tests/lib/Security/CertificateManagerTest.php b/tests/lib/Security/CertificateManagerTest.php index 14036b3dd3b..e6177272875 100644 --- a/tests/lib/Security/CertificateManagerTest.php +++ b/tests/lib/Security/CertificateManagerTest.php @@ -151,7 +151,7 @@ class CertificateManagerTest extends \Test\TestCase { $config = $this->createMock(IConfig::class); /** @var CertificateManager | \PHPUnit\Framework\MockObject\MockObject $certificateManager */ - $certificateManager = $this->getMockBuilder('OC\Security\CertificateManager') + $certificateManager = $this->getMockBuilder(\OC\Security\CertificateManager::class) ->setConstructorArgs([$view, $config, $this->createMock(LoggerInterface::class), $this->random]) ->setMethods(['getFilemtimeOfCaBundle', 'getCertificateBundle']) ->getMock(); diff --git a/tests/lib/Security/RateLimiting/Backend/MemoryCacheBackendTest.php b/tests/lib/Security/RateLimiting/Backend/MemoryCacheBackendTest.php index 24e3ab1a209..ddbcecd72f9 100644 --- a/tests/lib/Security/RateLimiting/Backend/MemoryCacheBackendTest.php +++ b/tests/lib/Security/RateLimiting/Backend/MemoryCacheBackendTest.php @@ -39,7 +39,7 @@ class MemoryCacheBackendTest extends TestCase { $this->cacheFactory ->expects($this->once()) ->method('createDistributed') - ->with('OC\Security\RateLimiting\Backend\MemoryCacheBackend') + ->with(\OC\Security\RateLimiting\Backend\MemoryCacheBackend::class) ->willReturn($this->cache); $this->config->method('getSystemValueBool') diff --git a/tests/lib/ServerTest.php b/tests/lib/ServerTest.php index 7f7d3125fdd..881531af246 100644 --- a/tests/lib/ServerTest.php +++ b/tests/lib/ServerTest.php @@ -1,175 +1,175 @@ -<?php -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-only - */ - -namespace Test; - -use OC\App\AppStore\Fetcher\AppFetcher; -use OC\App\AppStore\Fetcher\CategoryFetcher; -use OCP\Comments\ICommentsManager; - -/** - * Class Server - * - * @group DB - * - * @package Test - */ -class ServerTest extends \Test\TestCase { - /** @var \OC\Server */ - protected $server; - - - protected function setUp(): void { - parent::setUp(); - $config = new \OC\Config(\OC::$configDir); - $this->server = new \OC\Server('', $config); - } - - public function dataTestQuery() { - return [ - ['ActivityManager', '\OC\Activity\Manager'], - ['ActivityManager', '\OCP\Activity\IManager'], - ['AllConfig', '\OC\AllConfig'], - ['AllConfig', '\OCP\IConfig'], - ['AppConfig', '\OC\AppConfig'], - ['AppConfig', '\OCP\IAppConfig'], - ['AppFetcher', AppFetcher::class], - ['AppManager', '\OC\App\AppManager'], - ['AppManager', '\OCP\App\IAppManager'], - ['AsyncCommandBus', '\OC\Command\AsyncBus'], - ['AsyncCommandBus', '\OCP\Command\IBus'], - ['AvatarManager', '\OC\Avatar\AvatarManager'], - ['AvatarManager', '\OCP\IAvatarManager'], - - ['CategoryFetcher', CategoryFetcher::class], - ['CapabilitiesManager', '\OC\CapabilitiesManager'], - ['ContactsManager', '\OC\ContactsManager'], - ['ContactsManager', '\OCP\Contacts\IManager'], - ['ContentSecurityPolicyManager', '\OC\Security\CSP\ContentSecurityPolicyManager'], - ['CommentsManager', '\OCP\Comments\ICommentsManager'], - ['Crypto', '\OC\Security\Crypto'], - ['Crypto', '\OCP\Security\ICrypto'], - ['CryptoWrapper', '\OC\Session\CryptoWrapper'], - ['CsrfTokenManager', '\OC\Security\CSRF\CsrfTokenManager'], - - ['DatabaseConnection', '\OC\DB\ConnectionAdapter'], - ['DatabaseConnection', '\OCP\IDBConnection'], - ['DateTimeFormatter', '\OC\DateTimeFormatter'], - ['DateTimeFormatter', '\OCP\IDateTimeFormatter'], - ['DateTimeZone', '\OC\DateTimeZone'], - ['DateTimeZone', '\OCP\IDateTimeZone'], - - ['EncryptionFileHelper', '\OC\Encryption\File'], - ['EncryptionFileHelper', '\OCP\Encryption\IFile'], - ['EncryptionKeyStorage', '\OC\Encryption\Keys\Storage'], - ['EncryptionKeyStorage', '\OCP\Encryption\Keys\IStorage'], - ['EncryptionManager', '\OC\Encryption\Manager'], - ['EncryptionManager', '\OCP\Encryption\IManager'], - ['EventLogger', '\OCP\Diagnostics\IEventLogger'], - - ['GroupManager', '\OC\Group\Manager'], - ['GroupManager', '\OCP\IGroupManager'], - - ['Hasher', '\OC\Security\Hasher'], - ['Hasher', '\OCP\Security\IHasher'], - ['HttpClientService', '\OC\Http\Client\ClientService'], - ['HttpClientService', '\OCP\Http\Client\IClientService'], - - ['IniWrapper', '\bantu\IniGetWrapper\IniGetWrapper'], - ['MimeTypeDetector', '\OCP\Files\IMimeTypeDetector'], - ['MimeTypeDetector', '\OC\Files\Type\Detection'], - - ['JobList', '\OC\BackgroundJob\JobList'], - ['JobList', '\OCP\BackgroundJob\IJobList'], - - ['L10NFactory', '\OC\L10N\Factory'], - ['L10NFactory', '\OCP\L10N\IFactory'], - ['LockingProvider', '\OCP\Lock\ILockingProvider'], - ['Logger', '\OC\Log'], - ['Logger', '\OCP\ILogger'], - - ['Mailer', '\OC\Mail\Mailer'], - ['Mailer', '\OCP\Mail\IMailer'], - ['MemCacheFactory', '\OC\Memcache\Factory'], - ['MemCacheFactory', '\OCP\ICacheFactory'], - ['MountConfigManager', '\OC\Files\Config\MountProviderCollection'], - ['MountConfigManager', '\OCP\Files\Config\IMountProviderCollection'], - - ['NavigationManager', '\OC\NavigationManager'], - ['NavigationManager', '\OCP\INavigationManager'], - ['NotificationManager', '\OC\Notification\Manager'], - ['NotificationManager', '\OCP\Notification\IManager'], - ['UserCache', '\OC\Cache\File'], - ['UserCache', '\OCP\ICache'], - - ['PreviewManager', '\OC\PreviewManager'], - ['PreviewManager', '\OCP\IPreview'], - - ['QueryLogger', '\OCP\Diagnostics\IQueryLogger'], - - ['Request', '\OC\AppFramework\Http\Request'], - ['Request', '\OCP\IRequest'], - ['RootFolder', '\OC\Files\Node\Root'], - ['RootFolder', '\OC\Files\Node\Folder'], - ['RootFolder', '\OCP\Files\IRootFolder'], - ['RootFolder', '\OCP\Files\Folder'], - ['Router', '\OCP\Route\IRouter'], - - ['SecureRandom', '\OC\Security\SecureRandom'], - ['SecureRandom', '\OCP\Security\ISecureRandom'], - ['ShareManager', '\OC\Share20\Manager'], - ['ShareManager', '\OCP\Share\IManager'], - ['SystemConfig', '\OC\SystemConfig'], - - ['URLGenerator', '\OC\URLGenerator'], - ['URLGenerator', '\OCP\IURLGenerator'], - ['UserManager', '\OC\User\Manager'], - ['UserManager', '\OCP\IUserManager'], - ['UserSession', '\OC\User\Session'], - ['UserSession', '\OCP\IUserSession'], - - ['TagMapper', '\OC\Tagging\TagMapper'], - ['TagMapper', '\OCP\AppFramework\Db\QBMapper'], - ['TagManager', '\OC\TagManager'], - ['TagManager', '\OCP\ITagManager'], - ['TempManager', '\OC\TempManager'], - ['TempManager', '\OCP\ITempManager'], - ['ThemingDefaults', '\OCA\Theming\ThemingDefaults'], - ['TrustedDomainHelper', '\OC\Security\TrustedDomainHelper'], - - ['SystemTagManager', '\OCP\SystemTag\ISystemTagManager'], - ['SystemTagObjectMapper', '\OCP\SystemTag\ISystemTagObjectMapper'], - ]; - } - - /** - * @dataProvider dataTestQuery - * - * @param string $serviceName - * @param string $instanceOf - */ - public function testQuery($serviceName, $instanceOf): void { - $this->assertInstanceOf($instanceOf, $this->server->query($serviceName), 'Service "' . $serviceName . '"" did not return the right class'); - } - - public function testGetCertificateManager(): void { - $this->assertInstanceOf('\OC\Security\CertificateManager', $this->server->getCertificateManager(), 'service returned by "getCertificateManager" did not return the right class'); - $this->assertInstanceOf('\OCP\ICertificateManager', $this->server->getCertificateManager(), 'service returned by "getCertificateManager" did not return the right class'); - } - - public function testOverwriteDefaultCommentsManager(): void { - $config = $this->server->getConfig(); - $defaultManagerFactory = $config->getSystemValue('comments.managerFactory', '\OC\Comments\ManagerFactory'); - - $config->setSystemValue('comments.managerFactory', '\Test\Comments\FakeFactory'); - - $manager = $this->server->get(ICommentsManager::class); - $this->assertInstanceOf('\OCP\Comments\ICommentsManager', $manager); - - $config->setSystemValue('comments.managerFactory', $defaultManagerFactory); - } -} +<?php +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace Test; + +use OC\App\AppStore\Fetcher\AppFetcher; +use OC\App\AppStore\Fetcher\CategoryFetcher; +use OCP\Comments\ICommentsManager; + +/** + * Class Server + * + * @group DB + * + * @package Test + */ +class ServerTest extends \Test\TestCase { + /** @var \OC\Server */ + protected $server; + + + protected function setUp(): void { + parent::setUp(); + $config = new \OC\Config(\OC::$configDir); + $this->server = new \OC\Server('', $config); + } + + public function dataTestQuery() { + return [ + ['ActivityManager', \OC\Activity\Manager::class], + ['ActivityManager', \OCP\Activity\IManager::class], + ['AllConfig', \OC\AllConfig::class], + ['AllConfig', \OCP\IConfig::class], + ['AppConfig', \OC\AppConfig::class], + ['AppConfig', \OCP\IAppConfig::class], + ['AppFetcher', AppFetcher::class], + ['AppManager', \OC\App\AppManager::class], + ['AppManager', \OCP\App\IAppManager::class], + ['AsyncCommandBus', \OC\Command\AsyncBus::class], + ['AsyncCommandBus', \OCP\Command\IBus::class], + ['AvatarManager', \OC\Avatar\AvatarManager::class], + ['AvatarManager', \OCP\IAvatarManager::class], + + ['CategoryFetcher', CategoryFetcher::class], + ['CapabilitiesManager', \OC\CapabilitiesManager::class], + ['ContactsManager', \OC\ContactsManager::class], + ['ContactsManager', \OCP\Contacts\IManager::class], + ['ContentSecurityPolicyManager', \OC\Security\CSP\ContentSecurityPolicyManager::class], + ['CommentsManager', \OCP\Comments\ICommentsManager::class], + ['Crypto', \OC\Security\Crypto::class], + ['Crypto', \OCP\Security\ICrypto::class], + ['CryptoWrapper', \OC\Session\CryptoWrapper::class], + ['CsrfTokenManager', \OC\Security\CSRF\CsrfTokenManager::class], + + ['DatabaseConnection', \OC\DB\ConnectionAdapter::class], + ['DatabaseConnection', \OCP\IDBConnection::class], + ['DateTimeFormatter', \OC\DateTimeFormatter::class], + ['DateTimeFormatter', \OCP\IDateTimeFormatter::class], + ['DateTimeZone', \OC\DateTimeZone::class], + ['DateTimeZone', \OCP\IDateTimeZone::class], + + ['EncryptionFileHelper', \OC\Encryption\File::class], + ['EncryptionFileHelper', \OCP\Encryption\IFile::class], + ['EncryptionKeyStorage', \OC\Encryption\Keys\Storage::class], + ['EncryptionKeyStorage', \OCP\Encryption\Keys\IStorage::class], + ['EncryptionManager', \OC\Encryption\Manager::class], + ['EncryptionManager', \OCP\Encryption\IManager::class], + ['EventLogger', \OCP\Diagnostics\IEventLogger::class], + + ['GroupManager', \OC\Group\Manager::class], + ['GroupManager', \OCP\IGroupManager::class], + + ['Hasher', \OC\Security\Hasher::class], + ['Hasher', \OCP\Security\IHasher::class], + ['HttpClientService', \OC\Http\Client\ClientService::class], + ['HttpClientService', \OCP\Http\Client\IClientService::class], + + ['IniWrapper', '\bantu\IniGetWrapper\IniGetWrapper'], + ['MimeTypeDetector', \OCP\Files\IMimeTypeDetector::class], + ['MimeTypeDetector', \OC\Files\Type\Detection::class], + + ['JobList', \OC\BackgroundJob\JobList::class], + ['JobList', \OCP\BackgroundJob\IJobList::class], + + ['L10NFactory', \OC\L10N\Factory::class], + ['L10NFactory', \OCP\L10N\IFactory::class], + ['LockingProvider', \OCP\Lock\ILockingProvider::class], + ['Logger', \OC\Log::class], + ['Logger', \OCP\ILogger::class], + + ['Mailer', \OC\Mail\Mailer::class], + ['Mailer', \OCP\Mail\IMailer::class], + ['MemCacheFactory', \OC\Memcache\Factory::class], + ['MemCacheFactory', \OCP\ICacheFactory::class], + ['MountConfigManager', \OC\Files\Config\MountProviderCollection::class], + ['MountConfigManager', \OCP\Files\Config\IMountProviderCollection::class], + + ['NavigationManager', \OC\NavigationManager::class], + ['NavigationManager', \OCP\INavigationManager::class], + ['NotificationManager', \OC\Notification\Manager::class], + ['NotificationManager', \OCP\Notification\IManager::class], + ['UserCache', \OC\Cache\File::class], + ['UserCache', \OCP\ICache::class], + + ['PreviewManager', \OC\PreviewManager::class], + ['PreviewManager', \OCP\IPreview::class], + + ['QueryLogger', \OCP\Diagnostics\IQueryLogger::class], + + ['Request', \OC\AppFramework\Http\Request::class], + ['Request', \OCP\IRequest::class], + ['RootFolder', \OC\Files\Node\Root::class], + ['RootFolder', \OC\Files\Node\Folder::class], + ['RootFolder', \OCP\Files\IRootFolder::class], + ['RootFolder', \OCP\Files\Folder::class], + ['Router', \OCP\Route\IRouter::class], + + ['SecureRandom', \OC\Security\SecureRandom::class], + ['SecureRandom', \OCP\Security\ISecureRandom::class], + ['ShareManager', \OC\Share20\Manager::class], + ['ShareManager', \OCP\Share\IManager::class], + ['SystemConfig', \OC\SystemConfig::class], + + ['URLGenerator', \OC\URLGenerator::class], + ['URLGenerator', \OCP\IURLGenerator::class], + ['UserManager', \OC\User\Manager::class], + ['UserManager', \OCP\IUserManager::class], + ['UserSession', \OC\User\Session::class], + ['UserSession', \OCP\IUserSession::class], + + ['TagMapper', \OC\Tagging\TagMapper::class], + ['TagMapper', \OCP\AppFramework\Db\QBMapper::class], + ['TagManager', \OC\TagManager::class], + ['TagManager', \OCP\ITagManager::class], + ['TempManager', \OC\TempManager::class], + ['TempManager', \OCP\ITempManager::class], + ['ThemingDefaults', \OCA\Theming\ThemingDefaults::class], + ['TrustedDomainHelper', \OC\Security\TrustedDomainHelper::class], + + ['SystemTagManager', \OCP\SystemTag\ISystemTagManager::class], + ['SystemTagObjectMapper', \OCP\SystemTag\ISystemTagObjectMapper::class], + ]; + } + + /** + * @dataProvider dataTestQuery + * + * @param string $serviceName + * @param string $instanceOf + */ + public function testQuery($serviceName, $instanceOf): void { + $this->assertInstanceOf($instanceOf, $this->server->query($serviceName), 'Service "' . $serviceName . '"" did not return the right class'); + } + + public function testGetCertificateManager(): void { + $this->assertInstanceOf(\OC\Security\CertificateManager::class, $this->server->getCertificateManager(), 'service returned by "getCertificateManager" did not return the right class'); + $this->assertInstanceOf(\OCP\ICertificateManager::class, $this->server->getCertificateManager(), 'service returned by "getCertificateManager" did not return the right class'); + } + + public function testOverwriteDefaultCommentsManager(): void { + $config = $this->server->getConfig(); + $defaultManagerFactory = $config->getSystemValue('comments.managerFactory', \OC\Comments\ManagerFactory::class); + + $config->setSystemValue('comments.managerFactory', \Test\Comments\FakeFactory::class); + + $manager = $this->server->get(ICommentsManager::class); + $this->assertInstanceOf(\OCP\Comments\ICommentsManager::class, $manager); + + $config->setSystemValue('comments.managerFactory', $defaultManagerFactory); + } +} diff --git a/tests/lib/Session/CryptoWrappingTest.php b/tests/lib/Session/CryptoWrappingTest.php index 8afbf61bddc..f8c5ba44a9a 100644 --- a/tests/lib/Session/CryptoWrappingTest.php +++ b/tests/lib/Session/CryptoWrappingTest.php @@ -27,7 +27,7 @@ class CryptoWrappingTest extends TestCase { $this->wrappedSession = $this->getMockBuilder(ISession::class) ->disableOriginalConstructor() ->getMock(); - $this->crypto = $this->getMockBuilder('OCP\Security\ICrypto') + $this->crypto = $this->getMockBuilder(\OCP\Security\ICrypto::class) ->disableOriginalConstructor() ->getMock(); $this->crypto->expects($this->any()) diff --git a/tests/lib/Share/ShareTest.php b/tests/lib/Share/ShareTest.php index 60891e10ca2..72bd4ac99ec 100644 --- a/tests/lib/Share/ShareTest.php +++ b/tests/lib/Share/ShareTest.php @@ -76,8 +76,8 @@ class ShareTest extends \Test\TestCase { $this->groupAndUser_group->addUser($this->user2); $this->groupAndUser_group->addUser($this->user3); - Share::registerBackend('test', 'Test\Share\Backend'); - \OC_Hook::clear('OCP\\Share'); + Share::registerBackend('test', \Test\Share\Backend::class); + \OC_Hook::clear(\OCP\Share::class); \OC::registerShareHooks(\OC::$server->getSystemConfig()); $this->resharing = \OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_resharing', 'yes'); \OC::$server->getConfig()->setAppValue('core', 'shareapi_allow_resharing', 'yes'); diff --git a/tests/lib/Share20/LegacyHooksTest.php b/tests/lib/Share20/LegacyHooksTest.php index 0761eed592b..3699d95182b 100644 --- a/tests/lib/Share20/LegacyHooksTest.php +++ b/tests/lib/Share20/LegacyHooksTest.php @@ -61,7 +61,7 @@ class LegacyHooksTest extends TestCase { ->setNodeCacheEntry($info); $hookListner = $this->getMockBuilder('Dummy')->setMethods(['pre'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'pre_unshare', $hookListner, 'pre'); + \OCP\Util::connectHook(\OCP\Share::class, 'pre_unshare', $hookListner, 'pre'); $hookListnerExpectsPre = [ 'id' => 42, @@ -102,7 +102,7 @@ class LegacyHooksTest extends TestCase { ->setNodeCacheEntry($info); $hookListner = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_unshare', $hookListner, 'post'); + \OCP\Util::connectHook(\OCP\Share::class, 'post_unshare', $hookListner, 'post'); $hookListnerExpectsPost = [ 'id' => 42, @@ -156,7 +156,7 @@ class LegacyHooksTest extends TestCase { ->setNodeCacheEntry($info); $hookListner = $this->getMockBuilder('Dummy')->setMethods(['postFromSelf'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_unshareFromSelf', $hookListner, 'postFromSelf'); + \OCP\Util::connectHook(\OCP\Share::class, 'post_unshareFromSelf', $hookListner, 'postFromSelf'); $hookListnerExpectsPostFromSelf = [ 'id' => 42, @@ -213,7 +213,7 @@ class LegacyHooksTest extends TestCase { $hookListner = $this->getMockBuilder('Dummy')->setMethods(['preShare'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'pre_shared', $hookListner, 'preShare'); + \OCP\Util::connectHook(\OCP\Share::class, 'pre_shared', $hookListner, 'preShare'); $run = true; $error = ''; @@ -261,7 +261,7 @@ class LegacyHooksTest extends TestCase { $hookListner = $this->getMockBuilder('Dummy')->setMethods(['preShare'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'pre_shared', $hookListner, 'preShare'); + \OCP\Util::connectHook(\OCP\Share::class, 'pre_shared', $hookListner, 'preShare'); $run = true; $error = ''; @@ -317,7 +317,7 @@ class LegacyHooksTest extends TestCase { $hookListner = $this->getMockBuilder('Dummy')->setMethods(['postShare'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_shared', $hookListner, 'postShare'); + \OCP\Util::connectHook(\OCP\Share::class, 'post_shared', $hookListner, 'postShare'); $expected = [ 'id' => 42, diff --git a/tests/lib/Share20/ManagerTest.php b/tests/lib/Share20/ManagerTest.php index 2250e28bd13..759e11f10dc 100644 --- a/tests/lib/Share20/ManagerTest.php +++ b/tests/lib/Share20/ManagerTest.php @@ -1,4690 +1,4690 @@ -<?php -/** - * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2016 ownCloud, Inc. - * SPDX-License-Identifier: AGPL-3.0-only - */ - -namespace Test\Share20; - -use DateTimeZone; -use OC\Files\Mount\MoveableMount; -use OC\KnownUser\KnownUserService; -use OC\Share20\DefaultShareProvider; -use OC\Share20\Exception; -use OC\Share20\Manager; -use OC\Share20\Share; -use OC\Share20\ShareDisableChecker; -use OCP\EventDispatcher\Event; -use OCP\EventDispatcher\IEventDispatcher; -use OCP\Files\File; -use OCP\Files\Folder; -use OCP\Files\IRootFolder; -use OCP\Files\Mount\IMountManager; -use OCP\Files\Mount\IMountPoint; -use OCP\Files\Node; -use OCP\Files\Storage; -use OCP\HintException; -use OCP\IConfig; -use OCP\IDateTimeZone; -use OCP\IGroup; -use OCP\IGroupManager; -use OCP\IL10N; -use OCP\IServerContainer; -use OCP\IURLGenerator; -use OCP\IUser; -use OCP\IUserManager; -use OCP\IUserSession; -use OCP\L10N\IFactory; -use OCP\Mail\IMailer; -use OCP\Security\Events\ValidatePasswordPolicyEvent; -use OCP\Security\IHasher; -use OCP\Security\ISecureRandom; -use OCP\Share\Events\BeforeShareCreatedEvent; -use OCP\Share\Events\BeforeShareDeletedEvent; -use OCP\Share\Events\ShareCreatedEvent; -use OCP\Share\Events\ShareDeletedEvent; -use OCP\Share\Events\ShareDeletedFromSelfEvent; -use OCP\Share\Exceptions\AlreadySharedException; -use OCP\Share\Exceptions\ShareNotFound; -use OCP\Share\IManager; -use OCP\Share\IProviderFactory; -use OCP\Share\IShare; -use OCP\Share\IShareProvider; -use PHPUnit\Framework\MockObject\MockBuilder; -use PHPUnit\Framework\MockObject\MockObject; -use Psr\Log\LoggerInterface; - -/** - * Class ManagerTest - * - * @package Test\Share20 - * @group DB - */ -class ManagerTest extends \Test\TestCase { - /** @var Manager */ - protected $manager; - /** @var LoggerInterface|MockObject */ - protected $logger; - /** @var IConfig|MockObject */ - protected $config; - /** @var ISecureRandom|MockObject */ - protected $secureRandom; - /** @var IHasher|MockObject */ - protected $hasher; - /** @var IShareProvider|MockObject */ - protected $defaultProvider; - /** @var IMountManager|MockObject */ - protected $mountManager; - /** @var IGroupManager|MockObject */ - protected $groupManager; - /** @var IL10N|MockObject */ - protected $l; - /** @var IFactory|MockObject */ - protected $l10nFactory; - /** @var DummyFactory */ - protected $factory; - /** @var IUserManager|MockObject */ - protected $userManager; - /** @var IRootFolder | MockObject */ - protected $rootFolder; - /** @var IEventDispatcher|MockObject */ - protected $dispatcher; - /** @var IMailer|MockObject */ - protected $mailer; - /** @var IURLGenerator|MockObject */ - protected $urlGenerator; - /** @var \OC_Defaults|MockObject */ - protected $defaults; - /** @var IUserSession|MockObject */ - protected $userSession; - /** @var KnownUserService|MockObject */ - protected $knownUserService; - /** @var ShareDisableChecker|MockObject */ - protected $shareDisabledChecker; - private DateTimeZone $timezone; - /** @var IDateTimeZone|MockObject */ - protected $dateTimeZone; - - protected function setUp(): void { - $this->logger = $this->createMock(LoggerInterface::class); - $this->config = $this->createMock(IConfig::class); - $this->secureRandom = $this->createMock(ISecureRandom::class); - $this->hasher = $this->createMock(IHasher::class); - $this->mountManager = $this->createMock(IMountManager::class); - $this->groupManager = $this->createMock(IGroupManager::class); - $this->userManager = $this->createMock(IUserManager::class); - $this->rootFolder = $this->createMock(IRootFolder::class); - $this->mailer = $this->createMock(IMailer::class); - $this->urlGenerator = $this->createMock(IURLGenerator::class); - $this->defaults = $this->createMock(\OC_Defaults::class); - $this->dispatcher = $this->createMock(IEventDispatcher::class); - $this->userSession = $this->createMock(IUserSession::class); - $this->knownUserService = $this->createMock(KnownUserService::class); - - $this->shareDisabledChecker = new ShareDisableChecker($this->config, $this->userManager, $this->groupManager); - $this->dateTimeZone = $this->createMock(IDateTimeZone::class); - $this->timezone = new \DateTimeZone('Pacific/Auckland'); - $this->dateTimeZone->method('getTimeZone')->willReturnCallback(fn () => $this->timezone); - - $this->l10nFactory = $this->createMock(IFactory::class); - $this->l = $this->createMock(IL10N::class); - $this->l->method('t') - ->willReturnCallback(function ($text, $parameters = []) { - return vsprintf($text, $parameters); - }); - $this->l->method('n') - ->willReturnCallback(function ($singular, $plural, $count, $parameters = []) { - return vsprintf(str_replace('%n', $count, ($count === 1) ? $singular : $plural), $parameters); - }); - $this->l10nFactory->method('get')->willReturn($this->l); - - $this->factory = new DummyFactory(\OC::$server); - - $this->manager = $this->createManager($this->factory); - - $this->defaultProvider = $this->createMock(DefaultShareProvider::class); - $this->defaultProvider->method('identifier')->willReturn('default'); - $this->factory->setProvider($this->defaultProvider); - } - - private function createManager(IProviderFactory $factory): Manager { - return new Manager( - $this->logger, - $this->config, - $this->secureRandom, - $this->hasher, - $this->mountManager, - $this->groupManager, - $this->l10nFactory, - $factory, - $this->userManager, - $this->rootFolder, - $this->mailer, - $this->urlGenerator, - $this->defaults, - $this->dispatcher, - $this->userSession, - $this->knownUserService, - $this->shareDisabledChecker, - $this->dateTimeZone, - ); - } - - /** - * @return MockBuilder - */ - private function createManagerMock() { - return $this->getMockBuilder(Manager::class) - ->setConstructorArgs([ - $this->logger, - $this->config, - $this->secureRandom, - $this->hasher, - $this->mountManager, - $this->groupManager, - $this->l10nFactory, - $this->factory, - $this->userManager, - $this->rootFolder, - $this->mailer, - $this->urlGenerator, - $this->defaults, - $this->dispatcher, - $this->userSession, - $this->knownUserService, - $this->shareDisabledChecker, - $this->dateTimeZone, - ]); - } - - - public function testDeleteNoShareId(): void { - $this->expectException(\InvalidArgumentException::class); - - $share = $this->manager->newShare(); - - $this->manager->deleteShare($share); - } - - public function dataTestDelete() { - $user = $this->createMock(IUser::class); - $user->method('getUID')->willReturn('sharedWithUser'); - - $group = $this->createMock(IGroup::class); - $group->method('getGID')->willReturn('sharedWithGroup'); - - return [ - [IShare::TYPE_USER, 'sharedWithUser'], - [IShare::TYPE_GROUP, 'sharedWithGroup'], - [IShare::TYPE_LINK, ''], - [IShare::TYPE_REMOTE, 'foo@bar.com'], - ]; - } - - /** - * @dataProvider dataTestDelete - */ - public function testDelete($shareType, $sharedWith): void { - $manager = $this->createManagerMock() - ->setMethods(['getShareById', 'deleteChildren']) - ->getMock(); - - $manager->method('deleteChildren')->willReturn([]); - - $path = $this->createMock(File::class); - $path->method('getId')->willReturn(1); - - $share = $this->manager->newShare(); - $share->setId(42) - ->setProviderId('prov') - ->setShareType($shareType) - ->setSharedWith($sharedWith) - ->setSharedBy('sharedBy') - ->setNode($path) - ->setTarget('myTarget'); - - $manager->expects($this->once())->method('deleteChildren')->with($share); - - $this->defaultProvider - ->expects($this->once()) - ->method('delete') - ->with($share); - - $this->dispatcher->expects($this->exactly(2)) - ->method('dispatchTyped') - ->withConsecutive( - [ - $this->callBack(function (BeforeShareDeletedEvent $e) use ($share) { - return $e->getShare() === $share; - })], - [ - $this->callBack(function (ShareDeletedEvent $e) use ($share) { - return $e->getShare() === $share; - })] - ); - - $manager->deleteShare($share); - } - - public function testDeleteLazyShare(): void { - $manager = $this->createManagerMock() - ->setMethods(['getShareById', 'deleteChildren']) - ->getMock(); - - $manager->method('deleteChildren')->willReturn([]); - - $share = $this->manager->newShare(); - $share->setId(42) - ->setProviderId('prov') - ->setShareType(IShare::TYPE_USER) - ->setSharedWith('sharedWith') - ->setSharedBy('sharedBy') - ->setShareOwner('shareOwner') - ->setTarget('myTarget') - ->setNodeId(1) - ->setNodeType('file'); - - $this->rootFolder->expects($this->never())->method($this->anything()); - - $manager->expects($this->once())->method('deleteChildren')->with($share); - - $this->defaultProvider - ->expects($this->once()) - ->method('delete') - ->with($share); - - $this->dispatcher->expects($this->exactly(2)) - ->method('dispatchTyped') - ->withConsecutive( - [ - $this->callBack(function (BeforeShareDeletedEvent $e) use ($share) { - return $e->getShare() === $share; - })], - [ - $this->callBack(function (ShareDeletedEvent $e) use ($share) { - return $e->getShare() === $share; - })] - ); - - $manager->deleteShare($share); - } - - public function testDeleteNested(): void { - $manager = $this->createManagerMock() - ->setMethods(['getShareById']) - ->getMock(); - - $path = $this->createMock(File::class); - $path->method('getId')->willReturn(1); - - $share1 = $this->manager->newShare(); - $share1->setId(42) - ->setProviderId('prov') - ->setShareType(IShare::TYPE_USER) - ->setSharedWith('sharedWith1') - ->setSharedBy('sharedBy1') - ->setNode($path) - ->setTarget('myTarget1'); - - $share2 = $this->manager->newShare(); - $share2->setId(43) - ->setProviderId('prov') - ->setShareType(IShare::TYPE_GROUP) - ->setSharedWith('sharedWith2') - ->setSharedBy('sharedBy2') - ->setNode($path) - ->setTarget('myTarget2') - ->setParent(42); - - $share3 = $this->manager->newShare(); - $share3->setId(44) - ->setProviderId('prov') - ->setShareType(IShare::TYPE_LINK) - ->setSharedBy('sharedBy3') - ->setNode($path) - ->setTarget('myTarget3') - ->setParent(43); - - $this->defaultProvider - ->method('getChildren') - ->willReturnMap([ - [$share1, [$share2]], - [$share2, [$share3]], - [$share3, []], - ]); - - $this->defaultProvider - ->method('delete') - ->withConsecutive([$share3], [$share2], [$share1]); - - $this->dispatcher->expects($this->exactly(6)) - ->method('dispatchTyped') - ->withConsecutive( - [ - $this->callBack(function (BeforeShareDeletedEvent $e) use ($share1) { - return $e->getShare()->getId() === $share1->getId(); - }) - ], - [ - $this->callBack(function (BeforeShareDeletedEvent $e) use ($share2) { - return $e->getShare()->getId() === $share2->getId(); - }) - ], - [ - $this->callBack(function (BeforeShareDeletedEvent $e) use ($share3) { - return $e->getShare()->getId() === $share3->getId(); - }) - ], - [ - $this->callBack(function (ShareDeletedEvent $e) use ($share3) { - return $e->getShare()->getId() === $share3->getId(); - }) - ], - [ - $this->callBack(function (ShareDeletedEvent $e) use ($share2) { - return $e->getShare()->getId() === $share2->getId(); - }) - ], - [ - $this->callBack(function (ShareDeletedEvent $e) use ($share1) { - return $e->getShare()->getId() === $share1->getId(); - }) - ], - ); - - $manager->deleteShare($share1); - } - - public function testDeleteFromSelf(): void { - $manager = $this->createManagerMock() - ->setMethods(['getShareById']) - ->getMock(); - - $recipientId = 'unshareFrom'; - $share = $this->manager->newShare(); - $share->setId(42) - ->setProviderId('prov') - ->setShareType(IShare::TYPE_USER) - ->setSharedWith('sharedWith') - ->setSharedBy('sharedBy') - ->setShareOwner('shareOwner') - ->setTarget('myTarget') - ->setNodeId(1) - ->setNodeType('file'); - - $this->defaultProvider - ->expects($this->once()) - ->method('deleteFromSelf') - ->with($share, $recipientId); - - $this->dispatcher->expects($this->once()) - ->method('dispatchTyped') - ->with( - $this->callBack(function (ShareDeletedFromSelfEvent $e) use ($share) { - return $e->getShare() === $share; - }) - ); - - $manager->deleteFromSelf($share, $recipientId); - } - - public function testDeleteChildren(): void { - $manager = $this->createManagerMock() - ->setMethods(['deleteShare']) - ->getMock(); - - $share = $this->createMock(IShare::class); - $share->method('getShareType')->willReturn(IShare::TYPE_USER); - - $child1 = $this->createMock(IShare::class); - $child1->method('getShareType')->willReturn(IShare::TYPE_USER); - $child2 = $this->createMock(IShare::class); - $child2->method('getShareType')->willReturn(IShare::TYPE_USER); - $child3 = $this->createMock(IShare::class); - $child3->method('getShareType')->willReturn(IShare::TYPE_USER); - - $shares = [ - $child1, - $child2, - $child3, - ]; - - $this->defaultProvider - ->expects($this->exactly(4)) - ->method('getChildren') - ->willReturnCallback(function ($_share) use ($share, $shares) { - if ($_share === $share) { - return $shares; - } - return []; - }); - - $this->defaultProvider - ->expects($this->exactly(3)) - ->method('delete') - ->withConsecutive([$child1], [$child2], [$child3]); - - $result = self::invokePrivate($manager, 'deleteChildren', [$share]); - $this->assertSame($shares, $result); - } - - public function testGetShareById(): void { - $share = $this->createMock(IShare::class); - - $this->defaultProvider - ->expects($this->once()) - ->method('getShareById') - ->with(42) - ->willReturn($share); - - $this->assertEquals($share, $this->manager->getShareById('default:42')); - } - - - public function testGetExpiredShareById(): void { - $this->expectException(\OCP\Share\Exceptions\ShareNotFound::class); - - $manager = $this->createManagerMock() - ->setMethods(['deleteShare']) - ->getMock(); - - $date = new \DateTime(); - $date->setTime(0, 0, 0); - - $share = $this->manager->newShare(); - $share->setExpirationDate($date) - ->setShareType(IShare::TYPE_LINK); - - $this->defaultProvider->expects($this->once()) - ->method('getShareById') - ->with('42') - ->willReturn($share); - - $manager->expects($this->once()) - ->method('deleteShare') - ->with($share); - - $manager->getShareById('default:42'); - } - - - public function testVerifyPasswordNullButEnforced(): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Passwords are enforced for link and mail shares'); - - $this->config->method('getAppValue')->willReturnMap([ - ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], - ['core', 'shareapi_enforce_links_password', 'no', 'yes'], - ]); - - self::invokePrivate($this->manager, 'verifyPassword', [null]); - } - - public function testVerifyPasswordNotEnforcedGroup(): void { - $this->config->method('getAppValue')->willReturnMap([ - ['core', 'shareapi_enforce_links_password_excluded_groups', '', '["admin"]'], - ['core', 'shareapi_enforce_links_password', 'no', 'yes'], - ]); - - // Create admin user - $user = $this->createMock(IUser::class); - $this->userSession->method('getUser')->willReturn($user); - $this->groupManager->method('getUserGroupIds')->with($user)->willReturn(['admin']); - - $result = self::invokePrivate($this->manager, 'verifyPassword', [null]); - $this->assertNull($result); - } - - public function testVerifyPasswordNotEnforcedMultipleGroups(): void { - $this->config->method('getAppValue')->willReturnMap([ - ['core', 'shareapi_enforce_links_password_excluded_groups', '', '["admin", "special"]'], - ['core', 'shareapi_enforce_links_password', 'no', 'yes'], - ]); - - // Create admin user - $user = $this->createMock(IUser::class); - $this->userSession->method('getUser')->willReturn($user); - $this->groupManager->method('getUserGroupIds')->with($user)->willReturn(['special']); - - $result = self::invokePrivate($this->manager, 'verifyPassword', [null]); - $this->assertNull($result); - } - - public function testVerifyPasswordNull(): void { - $this->config->method('getAppValue')->willReturnMap([ - ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], - ['core', 'shareapi_enforce_links_password', 'no', 'no'], - ]); - - $result = self::invokePrivate($this->manager, 'verifyPassword', [null]); - $this->assertNull($result); - } - - public function testVerifyPasswordHook(): void { - $this->config->method('getAppValue')->willReturnMap([ - ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], - ['core', 'shareapi_enforce_links_password', 'no', 'no'], - ]); - - $this->dispatcher->expects($this->once())->method('dispatchTyped') - ->willReturnCallback(function (Event $event) { - $this->assertInstanceOf(ValidatePasswordPolicyEvent::class, $event); - /** @var ValidatePasswordPolicyEvent $event */ - $this->assertSame('password', $event->getPassword()); - } - ); - - $result = self::invokePrivate($this->manager, 'verifyPassword', ['password']); - $this->assertNull($result); - } - - - public function testVerifyPasswordHookFails(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('password not accepted'); - - $this->config->method('getAppValue')->willReturnMap([ - ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], - ['core', 'shareapi_enforce_links_password', 'no', 'no'], - ]); - - $this->dispatcher->expects($this->once())->method('dispatchTyped') - ->willReturnCallback(function (Event $event) { - $this->assertInstanceOf(ValidatePasswordPolicyEvent::class, $event); - /** @var ValidatePasswordPolicyEvent $event */ - $this->assertSame('password', $event->getPassword()); - throw new HintException('message', 'password not accepted'); - } - ); - - self::invokePrivate($this->manager, 'verifyPassword', ['password']); - } - - public function createShare($id, $type, $node, $sharedWith, $sharedBy, $shareOwner, - $permissions, $expireDate = null, $password = null, $attributes = null) { - $share = $this->createMock(IShare::class); - - $share->method('getShareType')->willReturn($type); - $share->method('getSharedWith')->willReturn($sharedWith); - $share->method('getSharedBy')->willReturn($sharedBy); - $share->method('getShareOwner')->willReturn($shareOwner); - $share->method('getNode')->willReturn($node); - if ($node && $node->getId()) { - $share->method('getNodeId')->willReturn($node->getId()); - } - $share->method('getPermissions')->willReturn($permissions); - $share->method('getAttributes')->willReturn($attributes); - $share->method('getExpirationDate')->willReturn($expireDate); - $share->method('getPassword')->willReturn($password); - - return $share; - } - - public function dataGeneralChecks() { - $user0 = 'user0'; - $user2 = 'user1'; - $group0 = 'group0'; - $owner = $this->createMock(IUser::class); - $owner->method('getUID') - ->willReturn($user0); - - $file = $this->createMock(File::class); - $node = $this->createMock(Node::class); - $storage = $this->createMock(Storage\IStorage::class); - $storage->method('instanceOfStorage') - ->with('\OCA\Files_Sharing\External\Storage') - ->willReturn(false); - $file->method('getStorage') - ->willReturn($storage); - $file->method('getId')->willReturn(108); - $node->method('getStorage') - ->willReturn($storage); - $node->method('getId')->willReturn(108); - - $data = [ - [$this->createShare(null, IShare::TYPE_USER, $file, null, $user0, $user0, 31, null, null), 'SharedWith is not a valid user', true], - [$this->createShare(null, IShare::TYPE_USER, $file, $group0, $user0, $user0, 31, null, null), 'SharedWith is not a valid user', true], - [$this->createShare(null, IShare::TYPE_USER, $file, 'foo@bar.com', $user0, $user0, 31, null, null), 'SharedWith is not a valid user', true], - [$this->createShare(null, IShare::TYPE_GROUP, $file, null, $user0, $user0, 31, null, null), 'SharedWith is not a valid group', true], - [$this->createShare(null, IShare::TYPE_GROUP, $file, $user2, $user0, $user0, 31, null, null), 'SharedWith is not a valid group', true], - [$this->createShare(null, IShare::TYPE_GROUP, $file, 'foo@bar.com', $user0, $user0, 31, null, null), 'SharedWith is not a valid group', true], - [$this->createShare(null, IShare::TYPE_LINK, $file, $user2, $user0, $user0, 31, null, null), 'SharedWith should be empty', true], - [$this->createShare(null, IShare::TYPE_LINK, $file, $group0, $user0, $user0, 31, null, null), 'SharedWith should be empty', true], - [$this->createShare(null, IShare::TYPE_LINK, $file, 'foo@bar.com', $user0, $user0, 31, null, null), 'SharedWith should be empty', true], - [$this->createShare(null, -1, $file, null, $user0, $user0, 31, null, null), 'Unknown share type', true], - - [$this->createShare(null, IShare::TYPE_USER, $file, $user2, null, $user0, 31, null, null), 'SharedBy should be set', true], - [$this->createShare(null, IShare::TYPE_GROUP, $file, $group0, null, $user0, 31, null, null), 'SharedBy should be set', true], - [$this->createShare(null, IShare::TYPE_LINK, $file, null, null, $user0, 31, null, null), 'SharedBy should be set', true], - - [$this->createShare(null, IShare::TYPE_USER, $file, $user0, $user0, $user0, 31, null, null), 'Cannot share with yourself', true], - - [$this->createShare(null, IShare::TYPE_USER, null, $user2, $user0, $user0, 31, null, null), 'Path should be set', true], - [$this->createShare(null, IShare::TYPE_GROUP, null, $group0, $user0, $user0, 31, null, null), 'Path should be set', true], - [$this->createShare(null, IShare::TYPE_LINK, null, null, $user0, $user0, 31, null, null), 'Path should be set', true], - - [$this->createShare(null, IShare::TYPE_USER, $node, $user2, $user0, $user0, 31, null, null), 'Path should be either a file or a folder', true], - [$this->createShare(null, IShare::TYPE_GROUP, $node, $group0, $user0, $user0, 31, null, null), 'Path should be either a file or a folder', true], - [$this->createShare(null, IShare::TYPE_LINK, $node, null, $user0, $user0, 31, null, null), 'Path should be either a file or a folder', true], - ]; - - $nonShareAble = $this->createMock(Folder::class); - $nonShareAble->method('getId')->willReturn(108); - $nonShareAble->method('isShareable')->willReturn(false); - $nonShareAble->method('getPath')->willReturn('path'); - $nonShareAble->method('getName')->willReturn('name'); - $nonShareAble->method('getOwner') - ->willReturn($owner); - $nonShareAble->method('getStorage') - ->willReturn($storage); - - $data[] = [$this->createShare(null, IShare::TYPE_USER, $nonShareAble, $user2, $user0, $user0, 31, null, null), 'You are not allowed to share name', true]; - $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $nonShareAble, $group0, $user0, $user0, 31, null, null), 'You are not allowed to share name', true]; - $data[] = [$this->createShare(null, IShare::TYPE_LINK, $nonShareAble, null, $user0, $user0, 31, null, null), 'You are not allowed to share name', true]; - - $limitedPermssions = $this->createMock(File::class); - $limitedPermssions->method('isShareable')->willReturn(true); - $limitedPermssions->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_READ); - $limitedPermssions->method('getId')->willReturn(108); - $limitedPermssions->method('getPath')->willReturn('path'); - $limitedPermssions->method('getName')->willReturn('name'); - $limitedPermssions->method('getOwner') - ->willReturn($owner); - $limitedPermssions->method('getStorage') - ->willReturn($storage); - - $data[] = [$this->createShare(null, IShare::TYPE_USER, $limitedPermssions, $user2, $user0, $user0, null, null, null), 'A share requires permissions', true]; - $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $limitedPermssions, $group0, $user0, $user0, null, null, null), 'A share requires permissions', true]; - $data[] = [$this->createShare(null, IShare::TYPE_LINK, $limitedPermssions, null, $user0, $user0, null, null, null), 'A share requires permissions', true]; - - $mount = $this->createMock(MoveableMount::class); - $limitedPermssions->method('getMountPoint')->willReturn($mount); - - - $data[] = [$this->createShare(null, IShare::TYPE_USER, $limitedPermssions, $user2, $user0, $user0, 31, null, null), 'Cannot increase permissions of path', true]; - $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $limitedPermssions, $group0, $user0, $user0, 17, null, null), 'Cannot increase permissions of path', true]; - $data[] = [$this->createShare(null, IShare::TYPE_LINK, $limitedPermssions, null, $user0, $user0, 3, null, null), 'Cannot increase permissions of path', true]; - - $nonMovableStorage = $this->createMock(Storage\IStorage::class); - $nonMovableStorage->method('instanceOfStorage') - ->with('\OCA\Files_Sharing\External\Storage') - ->willReturn(false); - $nonMovableStorage->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_ALL); - $nonMoveableMountPermssions = $this->createMock(Folder::class); - $nonMoveableMountPermssions->method('isShareable')->willReturn(true); - $nonMoveableMountPermssions->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_READ); - $nonMoveableMountPermssions->method('getId')->willReturn(108); - $nonMoveableMountPermssions->method('getPath')->willReturn('path'); - $nonMoveableMountPermssions->method('getName')->willReturn('name'); - $nonMoveableMountPermssions->method('getInternalPath')->willReturn(''); - $nonMoveableMountPermssions->method('getOwner') - ->willReturn($owner); - $nonMoveableMountPermssions->method('getStorage') - ->willReturn($nonMovableStorage); - - $data[] = [$this->createShare(null, IShare::TYPE_USER, $nonMoveableMountPermssions, $user2, $user0, $user0, 11, null, null), 'Cannot increase permissions of path', false]; - $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $nonMoveableMountPermssions, $group0, $user0, $user0, 11, null, null), 'Cannot increase permissions of path', false]; - - $rootFolder = $this->createMock(Folder::class); - $rootFolder->method('isShareable')->willReturn(true); - $rootFolder->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_ALL); - $rootFolder->method('getId')->willReturn(42); - - $data[] = [$this->createShare(null, IShare::TYPE_USER, $rootFolder, $user2, $user0, $user0, 30, null, null), 'You cannot share your root folder', true]; - $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $rootFolder, $group0, $user0, $user0, 2, null, null), 'You cannot share your root folder', true]; - $data[] = [$this->createShare(null, IShare::TYPE_LINK, $rootFolder, null, $user0, $user0, 16, null, null), 'You cannot share your root folder', true]; - - $allPermssions = $this->createMock(Folder::class); - $allPermssions->method('isShareable')->willReturn(true); - $allPermssions->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_ALL); - $allPermssions->method('getId')->willReturn(108); - $allPermssions->method('getOwner') - ->willReturn($owner); - $allPermssions->method('getStorage') - ->willReturn($storage); - - $data[] = [$this->createShare(null, IShare::TYPE_USER, $allPermssions, $user2, $user0, $user0, 30, null, null), 'Shares need at least read permissions', true]; - $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $allPermssions, $group0, $user0, $user0, 2, null, null), 'Shares need at least read permissions', true]; - - $data[] = [$this->createShare(null, IShare::TYPE_USER, $allPermssions, $user2, $user0, $user0, 31, null, null), null, false]; - $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $allPermssions, $group0, $user0, $user0, 3, null, null), null, false]; - $data[] = [$this->createShare(null, IShare::TYPE_LINK, $allPermssions, null, $user0, $user0, 17, null, null), null, false]; - - - $remoteStorage = $this->createMock(Storage\IStorage::class); - $remoteStorage->method('instanceOfStorage') - ->with('\OCA\Files_Sharing\External\Storage') - ->willReturn(true); - $remoteFile = $this->createMock(Folder::class); - $remoteFile->method('isShareable')->willReturn(true); - $remoteFile->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_READ ^ \OCP\Constants::PERMISSION_UPDATE); - $remoteFile->method('getId')->willReturn(108); - $remoteFile->method('getOwner') - ->willReturn($owner); - $remoteFile->method('getStorage') - ->willReturn($storage); - $data[] = [$this->createShare(null, IShare::TYPE_REMOTE, $remoteFile, $user2, $user0, $user0, 1, null, null), null, false]; - $data[] = [$this->createShare(null, IShare::TYPE_REMOTE, $remoteFile, $user2, $user0, $user0, 3, null, null), null, false]; - $data[] = [$this->createShare(null, IShare::TYPE_REMOTE, $remoteFile, $user2, $user0, $user0, 31, null, null), 'Cannot increase permissions of ', true]; - - return $data; - } - - /** - * @dataProvider dataGeneralChecks - * - * @param $share - * @param $exceptionMessage - * @param $exception - */ - public function testGeneralChecks($share, $exceptionMessage, $exception): void { - $thrown = null; - - $this->userManager->method('userExists')->willReturnMap([ - ['user0', true], - ['user1', true], - ]); - - $this->groupManager->method('groupExists')->willReturnMap([ - ['group0', true], - ]); - - $userFolder = $this->createMock(Folder::class); - $userFolder->expects($this->any()) - ->method('getId') - ->willReturn(42); - // Id 108 is used in the data to refer to the node of the share. - $userFolder->method('getById') - ->with(108) - ->willReturn([$share->getNode()]); - $userFolder->expects($this->any()) - ->method('getRelativePath') - ->willReturnArgument(0); - $this->rootFolder->method('getUserFolder')->willReturn($userFolder); - - - try { - self::invokePrivate($this->manager, 'generalCreateChecks', [$share]); - $thrown = false; - } catch (\OCP\Share\Exceptions\GenericShareException $e) { - $this->assertEquals($exceptionMessage, $e->getHint()); - $thrown = true; - } catch (\InvalidArgumentException $e) { - $this->assertEquals($exceptionMessage, $e->getMessage()); - $thrown = true; - } - - $this->assertSame($exception, $thrown); - } - - - public function testGeneralCheckShareRoot(): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('You cannot share your root folder'); - - $thrown = null; - - $this->userManager->method('userExists')->willReturnMap([ - ['user0', true], - ['user1', true], - ]); - - $userFolder = $this->createMock(Folder::class); - $userFolder->method('isSubNode')->with($userFolder)->willReturn(false); - $this->rootFolder->method('getUserFolder')->willReturn($userFolder); - - $share = $this->manager->newShare(); - - $share->setShareType(IShare::TYPE_USER) - ->setSharedWith('user0') - ->setSharedBy('user1') - ->setNode($userFolder); - - self::invokePrivate($this->manager, 'generalCreateChecks', [$share]); - } - - public function validateExpirationDateInternalProvider() { - return [[IShare::TYPE_USER], [IShare::TYPE_REMOTE], [IShare::TYPE_REMOTE_GROUP]]; - } - - /** - * @dataProvider validateExpirationDateInternalProvider - */ - public function testValidateExpirationDateInternalInPast($shareType): void { - $this->expectException(\OCP\Share\Exceptions\GenericShareException::class); - $this->expectExceptionMessage('Expiration date is in the past'); - - // Expire date in the past - $past = new \DateTime(); - $past->sub(new \DateInterval('P1D')); - - $share = $this->manager->newShare(); - $share->setShareType($shareType); - $share->setExpirationDate($past); - - self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); - } - - /** - * @dataProvider validateExpirationDateInternalProvider - */ - public function testValidateExpirationDateInternalEnforceButNotSet($shareType): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Expiration date is enforced'); - - $share = $this->manager->newShare(); - $share->setProviderId('foo')->setId('bar'); - $share->setShareType($shareType); - if ($shareType === IShare::TYPE_USER) { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'], - ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'], - ]); - } else { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'], - ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'], - ]); - } - - self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); - } - - /** - * @dataProvider validateExpirationDateInternalProvider - */ - public function testValidateExpirationDateInternalEnforceButNotEnabledAndNotSet($shareType): void { - $share = $this->manager->newShare(); - $share->setProviderId('foo')->setId('bar'); - $share->setShareType($shareType); - - if ($shareType === IShare::TYPE_USER) { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'], - ]); - } else { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'], - ]); - } - - self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); - - $this->assertNull($share->getExpirationDate()); - } - - /** - * @dataProvider validateExpirationDateInternalProvider - */ - public function testValidateExpirationDateInternalEnforceButNotSetNewShare($shareType): void { - $share = $this->manager->newShare(); - $share->setShareType($shareType); - - if ($shareType === IShare::TYPE_USER) { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'], - ['core', 'shareapi_internal_expire_after_n_days', '7', '3'], - ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'], - ['core', 'internal_defaultExpDays', '3', '3'], - ]); - } else { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'], - ['core', 'shareapi_remote_expire_after_n_days', '7', '3'], - ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'], - ['core', 'remote_defaultExpDays', '3', '3'], - ]); - } - - $expected = new \DateTime('now', $this->timezone); - $expected->setTime(0, 0, 0); - $expected->add(new \DateInterval('P3D')); - - self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); - - $this->assertNotNull($share->getExpirationDate()); - $this->assertEquals($expected, $share->getExpirationDate()); - } - - /** - * @dataProvider validateExpirationDateInternalProvider - */ - public function testValidateExpirationDateInternalEnforceRelaxedDefaultButNotSetNewShare($shareType): void { - $share = $this->manager->newShare(); - $share->setShareType($shareType); - - if ($shareType === IShare::TYPE_USER) { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'], - ['core', 'shareapi_internal_expire_after_n_days', '7', '3'], - ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'], - ['core', 'internal_defaultExpDays', '3', '1'], - ]); - } else { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'], - ['core', 'shareapi_remote_expire_after_n_days', '7', '3'], - ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'], - ['core', 'remote_defaultExpDays', '3', '1'], - ]); - } - - $expected = new \DateTime('now', $this->timezone); - $expected->setTime(0, 0, 0); - $expected->add(new \DateInterval('P1D')); - - self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); - - $this->assertNotNull($share->getExpirationDate()); - $this->assertEquals($expected, $share->getExpirationDate()); - } - - /** - * @dataProvider validateExpirationDateInternalProvider - */ - public function testValidateExpirationDateInternalEnforceTooFarIntoFuture($shareType): void { - $this->expectException(\OCP\Share\Exceptions\GenericShareException::class); - $this->expectExceptionMessage('Cannot set expiration date more than 3 days in the future'); - - $future = new \DateTime(); - $future->add(new \DateInterval('P7D')); - - $share = $this->manager->newShare(); - $share->setShareType($shareType); - $share->setExpirationDate($future); - - if ($shareType === IShare::TYPE_USER) { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'], - ['core', 'shareapi_internal_expire_after_n_days', '7', '3'], - ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'], - ]); - } else { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'], - ['core', 'shareapi_remote_expire_after_n_days', '7', '3'], - ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'], - ]); - } - - self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); - } - - /** - * @dataProvider validateExpirationDateInternalProvider - */ - public function testValidateExpirationDateInternalEnforceValid($shareType): void { - $future = new \DateTime('now', $this->dateTimeZone->getTimeZone()); - $future->add(new \DateInterval('P2D')); - $future->setTime(1, 2, 3); - - $expected = clone $future; - $expected->setTime(0, 0, 0); - - $share = $this->manager->newShare(); - $share->setShareType($shareType); - $share->setExpirationDate($future); - - if ($shareType === IShare::TYPE_USER) { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'], - ['core', 'shareapi_internal_expire_after_n_days', '7', '3'], - ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'], - ]); - } else { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'], - ['core', 'shareapi_remote_expire_after_n_days', '7', '3'], - ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'], - ]); - } - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); - \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); - $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($future) { - return $data['expirationDate'] == $future; - })); - - self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); - - $this->assertEquals($expected, $share->getExpirationDate()); - } - - /** - * @dataProvider validateExpirationDateInternalProvider - */ - public function testValidateExpirationDateInternalNoDefault($shareType): void { - $date = new \DateTime('now', $this->dateTimeZone->getTimeZone()); - $date->add(new \DateInterval('P5D')); - $date->setTime(1, 2, 3); - - $expected = clone $date; - $expected->setTime(0, 0, 0); - - $share = $this->manager->newShare(); - $share->setShareType($shareType); - $share->setExpirationDate($date); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); - \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); - $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) { - return $data['expirationDate'] == $expected && $data['passwordSet'] === false; - })); - - self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); - - $this->assertEquals($expected, $share->getExpirationDate()); - } - - /** - * @dataProvider validateExpirationDateInternalProvider - */ - public function testValidateExpirationDateInternalNoDateNoDefault($shareType): void { - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); - \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); - $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) { - return $data['expirationDate'] === null && $data['passwordSet'] === true; - })); - - $share = $this->manager->newShare(); - $share->setShareType($shareType); - $share->setPassword('password'); - - self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); - - $this->assertNull($share->getExpirationDate()); - } - - /** - * @dataProvider validateExpirationDateInternalProvider - */ - public function testValidateExpirationDateInternalNoDateDefault($shareType): void { - $share = $this->manager->newShare(); - $share->setShareType($shareType); - - $expected = new \DateTime('now', $this->timezone); - $expected->setTime(0, 0); - $expected->add(new \DateInterval('P3D')); - $expected->setTimezone(new \DateTimeZone(date_default_timezone_get())); - - if ($shareType === IShare::TYPE_USER) { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'], - ['core', 'shareapi_internal_expire_after_n_days', '7', '3'], - ['core', 'internal_defaultExpDays', '3', '3'], - ]); - } else { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'], - ['core', 'shareapi_remote_expire_after_n_days', '7', '3'], - ['core', 'remote_defaultExpDays', '3', '3'], - ]); - } - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); - \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); - $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) { - return $data['expirationDate'] == $expected; - })); - - self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); - - $this->assertEquals($expected, $share->getExpirationDate()); - } - - /** - * @dataProvider validateExpirationDateInternalProvider - */ - public function testValidateExpirationDateInternalDefault($shareType): void { - $future = new \DateTime('now', $this->timezone); - $future->add(new \DateInterval('P5D')); - $future->setTime(1, 2, 3); - - $expected = clone $future; - $expected->setTime(0, 0); - - $share = $this->manager->newShare(); - $share->setShareType($shareType); - $share->setExpirationDate($future); - - if ($shareType === IShare::TYPE_USER) { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'], - ['core', 'shareapi_internal_expire_after_n_days', '7', '3'], - ['core', 'internal_defaultExpDays', '3', '1'], - ]); - } else { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'], - ['core', 'shareapi_remote_expire_after_n_days', '7', '3'], - ['core', 'remote_defaultExpDays', '3', '1'], - ]); - } - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); - \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); - $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) { - return $data['expirationDate'] == $expected; - })); - - self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); - - $this->assertEquals($expected, $share->getExpirationDate()); - } - - /** - * @dataProvider validateExpirationDateInternalProvider - */ - public function testValidateExpirationDateInternalHookModification($shareType): void { - $nextWeek = new \DateTime('now', $this->timezone); - $nextWeek->add(new \DateInterval('P7D')); - $nextWeek->setTime(0, 0, 0); - - $save = clone $nextWeek; - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); - \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); - $hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) { - $data['expirationDate']->sub(new \DateInterval('P2D')); - }); - - $share = $this->manager->newShare(); - $share->setShareType($shareType); - $share->setExpirationDate($nextWeek); - - self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); - - $save->sub(new \DateInterval('P2D')); - $this->assertEquals($save, $share->getExpirationDate()); - } - - /** - * @dataProvider validateExpirationDateInternalProvider - */ - public function testValidateExpirationDateInternalHookException($shareType): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Invalid date!'); - - $nextWeek = new \DateTime(); - $nextWeek->add(new \DateInterval('P7D')); - $nextWeek->setTime(0, 0, 0); - - $share = $this->manager->newShare(); - $share->setShareType($shareType); - $share->setExpirationDate($nextWeek); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); - \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); - $hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) { - $data['accepted'] = false; - $data['message'] = 'Invalid date!'; - }); - - self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); - } - - /** - * @dataProvider validateExpirationDateInternalProvider - */ - public function testValidateExpirationDateInternalExistingShareNoDefault($shareType): void { - $share = $this->manager->newShare(); - $share->setShareType($shareType); - $share->setId('42')->setProviderId('foo'); - - if ($shareType === IShare::TYPE_USER) { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'], - ['core', 'shareapi_internal_expire_after_n_days', '7', '6'], - ]); - } else { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'], - ['core', 'shareapi_remote_expire_after_n_days', '7', '6'], - ]); - } - - self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); - - $this->assertEquals(null, $share->getExpirationDate()); - } - - public function testValidateExpirationDateInPast(): void { - $this->expectException(\OCP\Share\Exceptions\GenericShareException::class); - $this->expectExceptionMessage('Expiration date is in the past'); - - // Expire date in the past - $past = new \DateTime(); - $past->sub(new \DateInterval('P1D')); - - $share = $this->manager->newShare(); - $share->setExpirationDate($past); - - self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); - } - - public function testValidateExpirationDateEnforceButNotSet(): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Expiration date is enforced'); - - $share = $this->manager->newShare(); - $share->setProviderId('foo')->setId('bar'); - - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_default_expire_date', 'no', 'yes'], - ['core', 'shareapi_enforce_expire_date', 'no', 'yes'], - ]); - - self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); - } - - public function testValidateExpirationDateEnforceButNotEnabledAndNotSet(): void { - $share = $this->manager->newShare(); - $share->setProviderId('foo')->setId('bar'); - - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_enforce_expire_date', 'no', 'yes'], - ]); - - self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); - - $this->assertNull($share->getExpirationDate()); - } - - public function testValidateExpirationDateEnforceButNotSetNewShare(): void { - $share = $this->manager->newShare(); - - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_enforce_expire_date', 'no', 'yes'], - ['core', 'shareapi_expire_after_n_days', '7', '3'], - ['core', 'shareapi_default_expire_date', 'no', 'yes'], - ['core', 'link_defaultExpDays', '3', '3'], - ]); - - $expected = new \DateTime('now', $this->timezone); - $expected->setTime(0, 0, 0); - $expected->add(new \DateInterval('P3D')); - - self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); - - $this->assertNotNull($share->getExpirationDate()); - $this->assertEquals($expected, $share->getExpirationDate()); - } - - public function testValidateExpirationDateEnforceRelaxedDefaultButNotSetNewShare(): void { - $share = $this->manager->newShare(); - - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_enforce_expire_date', 'no', 'yes'], - ['core', 'shareapi_expire_after_n_days', '7', '3'], - ['core', 'shareapi_default_expire_date', 'no', 'yes'], - ['core', 'link_defaultExpDays', '3', '1'], - ]); - - $expected = new \DateTime('now', $this->timezone); - $expected->setTime(0, 0, 0); - $expected->add(new \DateInterval('P1D')); - - self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); - - $this->assertNotNull($share->getExpirationDate()); - $this->assertEquals($expected, $share->getExpirationDate()); - } - - public function testValidateExpirationDateEnforceTooFarIntoFuture(): void { - $this->expectException(\OCP\Share\Exceptions\GenericShareException::class); - $this->expectExceptionMessage('Cannot set expiration date more than 3 days in the future'); - - $future = new \DateTime(); - $future->add(new \DateInterval('P7D')); - - $share = $this->manager->newShare(); - $share->setExpirationDate($future); - - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_enforce_expire_date', 'no', 'yes'], - ['core', 'shareapi_expire_after_n_days', '7', '3'], - ['core', 'shareapi_default_expire_date', 'no', 'yes'], - ]); - - self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); - } - - public function testValidateExpirationDateEnforceValid(): void { - $future = new \DateTime('now', $this->timezone); - $future->add(new \DateInterval('P2D')); - $future->setTime(1, 2, 3); - - $expected = clone $future; - $expected->setTime(0, 0, 0); - - $share = $this->manager->newShare(); - $share->setExpirationDate($future); - - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_enforce_expire_date', 'no', 'yes'], - ['core', 'shareapi_expire_after_n_days', '7', '3'], - ['core', 'shareapi_default_expire_date', 'no', 'yes'], - ]); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); - \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); - $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($future) { - return $data['expirationDate'] == $future; - })); - - self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); - - $this->assertEquals($expected, $share->getExpirationDate()); - } - - public function testValidateExpirationDateNoDefault(): void { - $date = new \DateTime('now', $this->timezone); - $date->add(new \DateInterval('P5D')); - $date->setTime(1, 2, 3); - - $expected = clone $date; - $expected->setTime(0, 0); - $expected->setTimezone(new \DateTimeZone(date_default_timezone_get())); - - $share = $this->manager->newShare(); - $share->setExpirationDate($date); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); - \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); - $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) { - return $data['expirationDate'] == $expected && $data['passwordSet'] === false; - })); - - self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); - - $this->assertEquals($expected, $share->getExpirationDate()); - } - - public function testValidateExpirationDateNoDateNoDefault(): void { - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); - \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); - $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) { - return $data['expirationDate'] === null && $data['passwordSet'] === true; - })); - - $share = $this->manager->newShare(); - $share->setPassword('password'); - - self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); - - $this->assertNull($share->getExpirationDate()); - } - - public function testValidateExpirationDateNoDateDefault(): void { - $share = $this->manager->newShare(); - - $expected = new \DateTime('now', $this->timezone); - $expected->add(new \DateInterval('P3D')); - $expected->setTime(0, 0); - $expected->setTimezone(new \DateTimeZone(date_default_timezone_get())); - - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_default_expire_date', 'no', 'yes'], - ['core', 'shareapi_expire_after_n_days', '7', '3'], - ['core', 'link_defaultExpDays', '3', '3'], - ]); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); - \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); - $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) { - return $data['expirationDate'] == $expected; - })); - - self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); - - $this->assertEquals($expected, $share->getExpirationDate()); - } - - public function testValidateExpirationDateDefault(): void { - $future = new \DateTime('now', $this->timezone); - $future->add(new \DateInterval('P5D')); - $future->setTime(1, 2, 3); - - $expected = clone $future; - $expected->setTime(0, 0); - $expected->setTimezone(new \DateTimeZone(date_default_timezone_get())); - - $share = $this->manager->newShare(); - $share->setExpirationDate($future); - - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_default_expire_date', 'no', 'yes'], - ['core', 'shareapi_expire_after_n_days', '7', '3'], - ['core', 'link_defaultExpDays', '3', '1'], - ]); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); - \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); - $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) { - return $data['expirationDate'] == $expected; - })); - - self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); - - $this->assertEquals($expected, $share->getExpirationDate()); - } - - public function testValidateExpirationNegativeOffsetTimezone(): void { - $this->timezone = new \DateTimeZone('Pacific/Tahiti'); - $future = new \DateTime(); - $future->add(new \DateInterval('P5D')); - - $expected = clone $future; - $expected->setTimezone($this->timezone); - $expected->setTime(0, 0); - $expected->setTimezone(new \DateTimeZone(date_default_timezone_get())); - - $share = $this->manager->newShare(); - $share->setExpirationDate($future); - - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_default_expire_date', 'no', 'yes'], - ['core', 'shareapi_expire_after_n_days', '7', '3'], - ['core', 'link_defaultExpDays', '3', '1'], - ]); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); - \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); - $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) { - return $data['expirationDate'] == $expected; - })); - - self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); - - $this->assertEquals($expected, $share->getExpirationDate()); - } - - public function testValidateExpirationDateHookModification(): void { - $nextWeek = new \DateTime('now', $this->timezone); - $nextWeek->add(new \DateInterval('P7D')); - - $save = clone $nextWeek; - $save->setTime(0, 0); - $save->sub(new \DateInterval('P2D')); - $save->setTimezone(new \DateTimeZone(date_default_timezone_get())); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); - \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); - $hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) { - $data['expirationDate']->sub(new \DateInterval('P2D')); - }); - - $share = $this->manager->newShare(); - $share->setExpirationDate($nextWeek); - - self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); - - $this->assertEquals($save, $share->getExpirationDate()); - } - - public function testValidateExpirationDateHookException(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Invalid date!'); - - $nextWeek = new \DateTime(); - $nextWeek->add(new \DateInterval('P7D')); - $nextWeek->setTime(0, 0, 0); - - $share = $this->manager->newShare(); - $share->setExpirationDate($nextWeek); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); - \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); - $hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) { - $data['accepted'] = false; - $data['message'] = 'Invalid date!'; - }); - - self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); - } - - public function testValidateExpirationDateExistingShareNoDefault(): void { - $share = $this->manager->newShare(); - - $share->setId('42')->setProviderId('foo'); - - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_default_expire_date', 'no', 'yes'], - ['core', 'shareapi_expire_after_n_days', '7', '6'], - ]); - - self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); - - $this->assertEquals(null, $share->getExpirationDate()); - } - - public function testUserCreateChecksShareWithGroupMembersOnlyDifferentGroups(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Sharing is only allowed with group members'); - - $share = $this->manager->newShare(); - - $sharedBy = $this->createMock(IUser::class); - $sharedWith = $this->createMock(IUser::class); - $share->setSharedBy('sharedBy')->setSharedWith('sharedWith'); - - $this->groupManager - ->method('getUserGroupIds') - ->willReturnMap( - [ - [$sharedBy, ['group1']], - [$sharedWith, ['group2']], - ] - ); - - $this->userManager->method('get')->willReturnMap([ - ['sharedBy', $sharedBy], - ['sharedWith', $sharedWith], - ]); - - $this->config - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'], - ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'], - ]); - - self::invokePrivate($this->manager, 'userCreateChecks', [$share]); - } - - public function testUserCreateChecksShareWithGroupMembersOnlySharedGroup(): void { - $share = $this->manager->newShare(); - - $sharedBy = $this->createMock(IUser::class); - $sharedWith = $this->createMock(IUser::class); - $share->setSharedBy('sharedBy')->setSharedWith('sharedWith'); - - $path = $this->createMock(Node::class); - $share->setNode($path); - - $this->groupManager - ->method('getUserGroupIds') - ->willReturnMap( - [ - [$sharedBy, ['group1', 'group3']], - [$sharedWith, ['group2', 'group3']], - ] - ); - - $this->userManager->method('get')->willReturnMap([ - ['sharedBy', $sharedBy], - ['sharedWith', $sharedWith], - ]); - - $this->config - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'], - ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'], - ]); - - $this->defaultProvider - ->method('getSharesByPath') - ->with($path) - ->willReturn([]); - - self::invokePrivate($this->manager, 'userCreateChecks', [$share]); - $this->addToAssertionCount(1); - } - - - public function testUserCreateChecksIdenticalShareExists(): void { - $this->expectException(AlreadySharedException::class); - $this->expectExceptionMessage('Sharing name.txt failed, because this item is already shared with the account user'); - - $share = $this->manager->newShare(); - $share->setSharedWithDisplayName('user'); - $share2 = $this->manager->newShare(); - - $sharedWith = $this->createMock(IUser::class); - $path = $this->createMock(Node::class); - - $share->setSharedWith('sharedWith')->setNode($path) - ->setProviderId('foo')->setId('bar'); - - $share2->setSharedWith('sharedWith')->setNode($path) - ->setProviderId('foo')->setId('baz'); - - $this->defaultProvider - ->method('getSharesByPath') - ->with($path) - ->willReturn([$share2]); - - $path->method('getName') - ->willReturn('name.txt'); - - self::invokePrivate($this->manager, 'userCreateChecks', [$share]); - } - - - public function testUserCreateChecksIdenticalPathSharedViaGroup(): void { - $this->expectException(AlreadySharedException::class); - $this->expectExceptionMessage('Sharing name2.txt failed, because this item is already shared with the account userName'); - - $share = $this->manager->newShare(); - - $sharedWith = $this->createMock(IUser::class); - $sharedWith->method('getUID')->willReturn('sharedWith'); - - $this->userManager->method('get')->with('sharedWith')->willReturn($sharedWith); - - $path = $this->createMock(Node::class); - - $share->setSharedWith('sharedWith') - ->setNode($path) - ->setShareOwner('shareOwner') - ->setSharedWithDisplayName('userName') - ->setProviderId('foo') - ->setId('bar'); - - $share2 = $this->manager->newShare(); - $share2->setShareType(IShare::TYPE_GROUP) - ->setShareOwner('shareOwner2') - ->setProviderId('foo') - ->setId('baz') - ->setSharedWith('group'); - - $group = $this->createMock(IGroup::class); - $group->method('inGroup') - ->with($sharedWith) - ->willReturn(true); - - $this->groupManager->method('get')->with('group')->willReturn($group); - - $this->defaultProvider - ->method('getSharesByPath') - ->with($path) - ->willReturn([$share2]); - - $path->method('getName') - ->willReturn('name2.txt'); - - self::invokePrivate($this->manager, 'userCreateChecks', [$share]); - } - - public function testUserCreateChecksIdenticalPathSharedViaDeletedGroup(): void { - $share = $this->manager->newShare(); - - $sharedWith = $this->createMock(IUser::class); - $sharedWith->method('getUID')->willReturn('sharedWith'); - - $this->userManager->method('get')->with('sharedWith')->willReturn($sharedWith); - - $path = $this->createMock(Node::class); - - $share->setSharedWith('sharedWith') - ->setNode($path) - ->setShareOwner('shareOwner') - ->setProviderId('foo') - ->setId('bar'); - - $share2 = $this->manager->newShare(); - $share2->setShareType(IShare::TYPE_GROUP) - ->setShareOwner('shareOwner2') - ->setProviderId('foo') - ->setId('baz') - ->setSharedWith('group'); - - $this->groupManager->method('get')->with('group')->willReturn(null); - - $this->defaultProvider - ->method('getSharesByPath') - ->with($path) - ->willReturn([$share2]); - - $this->assertNull($this->invokePrivate($this->manager, 'userCreateChecks', [$share])); - } - - public function testUserCreateChecksIdenticalPathNotSharedWithUser(): void { - $share = $this->manager->newShare(); - $sharedWith = $this->createMock(IUser::class); - $path = $this->createMock(Node::class); - $share->setSharedWith('sharedWith') - ->setNode($path) - ->setShareOwner('shareOwner') - ->setProviderId('foo') - ->setId('bar'); - - $this->userManager->method('get')->with('sharedWith')->willReturn($sharedWith); - - $share2 = $this->manager->newShare(); - $share2->setShareType(IShare::TYPE_GROUP) - ->setShareOwner('shareOwner2') - ->setProviderId('foo') - ->setId('baz'); - - $group = $this->createMock(IGroup::class); - $group->method('inGroup') - ->with($sharedWith) - ->willReturn(false); - - $this->groupManager->method('get')->with('group')->willReturn($group); - - $share2->setSharedWith('group'); - - $this->defaultProvider - ->method('getSharesByPath') - ->with($path) - ->willReturn([$share2]); - - self::invokePrivate($this->manager, 'userCreateChecks', [$share]); - $this->addToAssertionCount(1); - } - - - public function testGroupCreateChecksShareWithGroupMembersGroupSharingNotAllowed(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Group sharing is now allowed'); - - $share = $this->manager->newShare(); - - $this->config - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_allow_group_sharing', 'yes', 'no'], - ]); - - self::invokePrivate($this->manager, 'groupCreateChecks', [$share]); - } - - - public function testGroupCreateChecksShareWithGroupMembersOnlyNotInGroup(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Sharing is only allowed within your own groups'); - - $share = $this->manager->newShare(); - - $user = $this->createMock(IUser::class); - $group = $this->createMock(IGroup::class); - $share->setSharedBy('user')->setSharedWith('group'); - - $group->method('inGroup')->with($user)->willReturn(false); - - $this->groupManager->method('get')->with('group')->willReturn($group); - $this->userManager->method('get')->with('user')->willReturn($user); - - $this->config - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'], - ['core', 'shareapi_allow_group_sharing', 'yes', 'yes'], - ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'], - ]); - - self::invokePrivate($this->manager, 'groupCreateChecks', [$share]); - } - - - public function testGroupCreateChecksShareWithGroupMembersOnlyNullGroup(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Sharing is only allowed within your own groups'); - - $share = $this->manager->newShare(); - - $user = $this->createMock(IUser::class); - $share->setSharedBy('user')->setSharedWith('group'); - - $this->groupManager->method('get')->with('group')->willReturn(null); - $this->userManager->method('get')->with('user')->willReturn($user); - - $this->config - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'], - ['core', 'shareapi_allow_group_sharing', 'yes', 'yes'], - ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'], - ]); - - $this->assertNull($this->invokePrivate($this->manager, 'groupCreateChecks', [$share])); - } - - public function testGroupCreateChecksShareWithGroupMembersOnlyInGroup(): void { - $share = $this->manager->newShare(); - - $user = $this->createMock(IUser::class); - $group = $this->createMock(IGroup::class); - $share->setSharedBy('user')->setSharedWith('group'); - - $this->userManager->method('get')->with('user')->willReturn($user); - $this->groupManager->method('get')->with('group')->willReturn($group); - - $group->method('inGroup')->with($user)->willReturn(true); - - $path = $this->createMock(Node::class); - $share->setNode($path); - - $this->defaultProvider->method('getSharesByPath') - ->with($path) - ->willReturn([]); - - $this->config - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'], - ['core', 'shareapi_allow_group_sharing', 'yes', 'yes'], - ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'], - ]); - - self::invokePrivate($this->manager, 'groupCreateChecks', [$share]); - $this->addToAssertionCount(1); - } - - - public function testGroupCreateChecksPathAlreadySharedWithSameGroup(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Path is already shared with this group'); - - $share = $this->manager->newShare(); - - $path = $this->createMock(Node::class); - $share->setSharedWith('sharedWith') - ->setNode($path) - ->setProviderId('foo') - ->setId('bar'); - - $share2 = $this->manager->newShare(); - $share2->setSharedWith('sharedWith') - ->setProviderId('foo') - ->setId('baz'); - - $this->defaultProvider->method('getSharesByPath') - ->with($path) - ->willReturn([$share2]); - - $this->config - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_allow_group_sharing', 'yes', 'yes'], - ]); - - self::invokePrivate($this->manager, 'groupCreateChecks', [$share]); - } - - public function testGroupCreateChecksPathAlreadySharedWithDifferentGroup(): void { - $share = $this->manager->newShare(); - - $share->setSharedWith('sharedWith'); - - $path = $this->createMock(Node::class); - $share->setNode($path); - - $share2 = $this->manager->newShare(); - $share2->setSharedWith('sharedWith2'); - - $this->defaultProvider->method('getSharesByPath') - ->with($path) - ->willReturn([$share2]); - - $this->config - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_allow_group_sharing', 'yes', 'yes'], - ]); - - self::invokePrivate($this->manager, 'groupCreateChecks', [$share]); - $this->addToAssertionCount(1); - } - - - public function testLinkCreateChecksNoLinkSharesAllowed(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Link sharing is not allowed'); - - $share = $this->manager->newShare(); - - $this->config - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_allow_links', 'yes', 'no'], - ]); - - self::invokePrivate($this->manager, 'linkCreateChecks', [$share]); - } - - - public function testFileLinkCreateChecksNoPublicUpload(): void { - $share = $this->manager->newShare(); - - $share->setPermissions(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE); - $share->setNodeType('file'); - - $this->config - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['core', 'shareapi_allow_public_upload', 'yes', 'no'] - ]); - - self::invokePrivate($this->manager, 'linkCreateChecks', [$share]); - $this->addToAssertionCount(1); - } - - public function testFolderLinkCreateChecksNoPublicUpload(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Public upload is not allowed'); - - $share = $this->manager->newShare(); - - $share->setPermissions(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE); - $share->setNodeType('folder'); - - $this->config - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['core', 'shareapi_allow_public_upload', 'yes', 'no'] - ]); - - self::invokePrivate($this->manager, 'linkCreateChecks', [$share]); - } - - public function testLinkCreateChecksPublicUpload(): void { - $share = $this->manager->newShare(); - - $share->setPermissions(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE); - $share->setSharedWith('sharedWith'); - $folder = $this->createMock(\OC\Files\Node\Folder::class); - $share->setNode($folder); - - $this->config - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['core', 'shareapi_allow_public_upload', 'yes', 'yes'] - ]); - - self::invokePrivate($this->manager, 'linkCreateChecks', [$share]); - $this->addToAssertionCount(1); - } - - public function testLinkCreateChecksReadOnly(): void { - $share = $this->manager->newShare(); - - $share->setPermissions(\OCP\Constants::PERMISSION_READ); - $share->setSharedWith('sharedWith'); - $folder = $this->createMock(\OC\Files\Node\Folder::class); - $share->setNode($folder); - - $this->config - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['core', 'shareapi_allow_public_upload', 'yes', 'no'] - ]); - - self::invokePrivate($this->manager, 'linkCreateChecks', [$share]); - $this->addToAssertionCount(1); - } - - - public function testPathCreateChecksContainsSharedMount(): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Path contains files shared with you'); - - $path = $this->createMock(Folder::class); - $path->method('getPath')->willReturn('path'); - - $mount = $this->createMock(IMountPoint::class); - $storage = $this->createMock(Storage::class); - $mount->method('getStorage')->willReturn($storage); - $storage->method('instanceOfStorage')->with('\OCA\Files_Sharing\ISharedStorage')->willReturn(true); - - $this->mountManager->method('findIn')->with('path')->willReturn([$mount]); - - self::invokePrivate($this->manager, 'pathCreateChecks', [$path]); - } - - public function testPathCreateChecksContainsNoSharedMount(): void { - $path = $this->createMock(Folder::class); - $path->method('getPath')->willReturn('path'); - - $mount = $this->createMock(IMountPoint::class); - $storage = $this->createMock(Storage::class); - $mount->method('getStorage')->willReturn($storage); - $storage->method('instanceOfStorage')->with('\OCA\Files_Sharing\ISharedStorage')->willReturn(false); - - $this->mountManager->method('findIn')->with('path')->willReturn([$mount]); - - self::invokePrivate($this->manager, 'pathCreateChecks', [$path]); - $this->addToAssertionCount(1); - } - - public function testPathCreateChecksContainsNoFolder(): void { - $path = $this->createMock(File::class); - - self::invokePrivate($this->manager, 'pathCreateChecks', [$path]); - $this->addToAssertionCount(1); - } - - public function dataIsSharingDisabledForUser() { - $data = []; - - // No exclude groups - $data[] = ['no', null, null, [], false]; - - // empty exclude / allow list, user no groups - $data[] = ['yes', '', json_encode(['']), [], false]; - $data[] = ['allow', '', json_encode(['']), [], true]; - - // empty exclude / allow list, user groups - $data[] = ['yes', '', json_encode(['']), ['group1', 'group2'], false]; - $data[] = ['allow', '', json_encode(['']), ['group1', 'group2'], true]; - - // Convert old list to json - $data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), [], false]; - $data[] = ['allow', 'group1,group2', json_encode(['group1', 'group2']), [], true]; - - // Old list partly groups in common - $data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), ['group1', 'group3'], false]; - $data[] = ['allow', 'group1,group2', json_encode(['group1', 'group2']), ['group1', 'group3'], false]; - - // Old list only groups in common - $data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), ['group1'], true]; - $data[] = ['allow', 'group1,group2', json_encode(['group1', 'group2']), ['group1'], false]; - - // New list partly in common - $data[] = ['yes', json_encode(['group1', 'group2']), null, ['group1', 'group3'], false]; - $data[] = ['allow', json_encode(['group1', 'group2']), null, ['group1', 'group3'], false]; - - // New list only groups in common - $data[] = ['yes', json_encode(['group1', 'group2']), null, ['group2'], true]; - $data[] = ['allow', json_encode(['group1', 'group2']), null, ['group2'], false]; - - return $data; - } - - /** - * @dataProvider dataIsSharingDisabledForUser - * - * @param string $excludeGroups - * @param string $groupList - * @param string $setList - * @param string[] $groupIds - * @param bool $expected - */ - public function testIsSharingDisabledForUser($excludeGroups, $groupList, $setList, $groupIds, $expected): void { - $user = $this->createMock(IUser::class); - - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_exclude_groups', 'no', $excludeGroups], - ['core', 'shareapi_exclude_groups_list', '', $groupList], - ]); - - if ($setList !== null) { - $this->config->expects($this->once()) - ->method('setAppValue') - ->with('core', 'shareapi_exclude_groups_list', $setList); - } else { - $this->config->expects($this->never()) - ->method('setAppValue'); - } - - $this->groupManager->method('getUserGroupIds') - ->with($user) - ->willReturn($groupIds); - - $this->userManager->method('get')->with('user')->willReturn($user); - - $res = $this->manager->sharingDisabledForUser('user'); - $this->assertEquals($expected, $res); - } - - public function dataCanShare() { - $data = []; - - /* - * [expected, sharing enabled, disabled for user] - */ - - $data[] = [false, 'no', false]; - $data[] = [false, 'no', true]; - $data[] = [true, 'yes', false]; - $data[] = [false, 'yes', true]; - - return $data; - } - - /** - * @dataProvider dataCanShare - * - * @param bool $expected - * @param string $sharingEnabled - * @param bool $disabledForUser - */ - public function testCanShare($expected, $sharingEnabled, $disabledForUser): void { - $this->config->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_enabled', 'yes', $sharingEnabled], - ]); - - $manager = $this->createManagerMock() - ->setMethods(['sharingDisabledForUser']) - ->getMock(); - - $manager->method('sharingDisabledForUser') - ->with('user') - ->willReturn($disabledForUser); - - $share = $this->manager->newShare(); - $share->setSharedBy('user'); - - $exception = false; - try { - $res = self::invokePrivate($manager, 'canShare', [$share]); - } catch (\Exception $e) { - $exception = true; - } - - $this->assertEquals($expected, !$exception); - } - - public function testCreateShareUser(): void { - $manager = $this->createManagerMock() - ->setMethods(['canShare', 'generalCreateChecks', 'userCreateChecks', 'pathCreateChecks']) - ->getMock(); - - $shareOwner = $this->createMock(IUser::class); - $shareOwner->method('getUID')->willReturn('shareOwner'); - - $storage = $this->createMock(Storage::class); - $path = $this->createMock(File::class); - $path->method('getOwner')->willReturn($shareOwner); - $path->method('getName')->willReturn('target'); - $path->method('getStorage')->willReturn($storage); - - $share = $this->createShare( - null, - IShare::TYPE_USER, - $path, - 'sharedWith', - 'sharedBy', - null, - \OCP\Constants::PERMISSION_ALL); - - $manager->expects($this->once()) - ->method('canShare') - ->with($share) - ->willReturn(true); - $manager->expects($this->once()) - ->method('generalCreateChecks') - ->with($share); - ; - $manager->expects($this->once()) - ->method('userCreateChecks') - ->with($share); - ; - $manager->expects($this->once()) - ->method('pathCreateChecks') - ->with($path); - - $this->defaultProvider - ->expects($this->once()) - ->method('create') - ->with($share) - ->willReturnArgument(0); - - $share->expects($this->once()) - ->method('setShareOwner') - ->with('shareOwner'); - $share->expects($this->once()) - ->method('setTarget') - ->with('/target'); - - $manager->createShare($share); - } - - public function testCreateShareGroup(): void { - $manager = $this->createManagerMock() - ->setMethods(['canShare', 'generalCreateChecks', 'groupCreateChecks', 'pathCreateChecks']) - ->getMock(); - - $shareOwner = $this->createMock(IUser::class); - $shareOwner->method('getUID')->willReturn('shareOwner'); - - $storage = $this->createMock(Storage::class); - $path = $this->createMock(File::class); - $path->method('getOwner')->willReturn($shareOwner); - $path->method('getName')->willReturn('target'); - $path->method('getStorage')->willReturn($storage); - - $share = $this->createShare( - null, - IShare::TYPE_GROUP, - $path, - 'sharedWith', - 'sharedBy', - null, - \OCP\Constants::PERMISSION_ALL); - - $manager->expects($this->once()) - ->method('canShare') - ->with($share) - ->willReturn(true); - $manager->expects($this->once()) - ->method('generalCreateChecks') - ->with($share); - ; - $manager->expects($this->once()) - ->method('groupCreateChecks') - ->with($share); - ; - $manager->expects($this->once()) - ->method('pathCreateChecks') - ->with($path); - - $this->defaultProvider - ->expects($this->once()) - ->method('create') - ->with($share) - ->willReturnArgument(0); - - $share->expects($this->once()) - ->method('setShareOwner') - ->with('shareOwner'); - $share->expects($this->once()) - ->method('setTarget') - ->with('/target'); - - $manager->createShare($share); - } - - public function testCreateShareLink(): void { - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'generalCreateChecks', - 'linkCreateChecks', - 'pathCreateChecks', - 'validateExpirationDateLink', - 'verifyPassword', - 'setLinkParent', - ]) - ->getMock(); - - $shareOwner = $this->createMock(IUser::class); - $shareOwner->method('getUID')->willReturn('shareOwner'); - - $storage = $this->createMock(Storage::class); - $path = $this->createMock(File::class); - $path->method('getOwner')->willReturn($shareOwner); - $path->method('getName')->willReturn('target'); - $path->method('getId')->willReturn(1); - $path->method('getStorage')->willReturn($storage); - - $date = new \DateTime(); - - $share = $this->manager->newShare(); - $share->setShareType(IShare::TYPE_LINK) - ->setNode($path) - ->setSharedBy('sharedBy') - ->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setExpirationDate($date) - ->setPassword('password'); - - $manager->expects($this->once()) - ->method('canShare') - ->with($share) - ->willReturn(true); - $manager->expects($this->once()) - ->method('generalCreateChecks') - ->with($share); - ; - $manager->expects($this->once()) - ->method('linkCreateChecks') - ->with($share); - ; - $manager->expects($this->once()) - ->method('pathCreateChecks') - ->with($path); - $manager->expects($this->once()) - ->method('validateExpirationDateLink') - ->with($share) - ->willReturn($share); - $manager->expects($this->once()) - ->method('verifyPassword') - ->with('password'); - $manager->expects($this->once()) - ->method('setLinkParent') - ->with($share); - - $this->hasher->expects($this->once()) - ->method('hash') - ->with('password') - ->willReturn('hashed'); - - $this->secureRandom->method('generate') - ->willReturn('token'); - - $this->defaultProvider - ->expects($this->once()) - ->method('create') - ->with($share) - ->willReturnCallback(function (Share $share) { - return $share->setId(42); - }); - - $this->dispatcher->expects($this->exactly(2)) - ->method('dispatchTyped') - ->withConsecutive( - // Pre share - [ - $this->callback(function (BeforeShareCreatedEvent $e) use ($path, $date) { - $share = $e->getShare(); - - return $share->getShareType() === IShare::TYPE_LINK && - $share->getNode() === $path && - $share->getSharedBy() === 'sharedBy' && - $share->getPermissions() === \OCP\Constants::PERMISSION_ALL && - $share->getExpirationDate() === $date && - $share->getPassword() === 'hashed' && - $share->getToken() === 'token'; - }) - ], - // Post share - [ - $this->callback(function (ShareCreatedEvent $e) use ($path, $date) { - $share = $e->getShare(); - - return $share->getShareType() === IShare::TYPE_LINK && - $share->getNode() === $path && - $share->getSharedBy() === 'sharedBy' && - $share->getPermissions() === \OCP\Constants::PERMISSION_ALL && - $share->getExpirationDate() === $date && - $share->getPassword() === 'hashed' && - $share->getToken() === 'token' && - $share->getId() === '42' && - $share->getTarget() === '/target'; - }) - ] - ); - - /** @var IShare $share */ - $share = $manager->createShare($share); - - $this->assertSame('shareOwner', $share->getShareOwner()); - $this->assertEquals('/target', $share->getTarget()); - $this->assertSame($date, $share->getExpirationDate()); - $this->assertEquals('token', $share->getToken()); - $this->assertEquals('hashed', $share->getPassword()); - } - - public function testCreateShareMail(): void { - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'generalCreateChecks', - 'linkCreateChecks', - 'pathCreateChecks', - 'validateExpirationDateLink', - 'verifyPassword', - 'setLinkParent', - ]) - ->getMock(); - - $shareOwner = $this->createMock(IUser::class); - $shareOwner->method('getUID')->willReturn('shareOwner'); - - $storage = $this->createMock(Storage::class); - $path = $this->createMock(File::class); - $path->method('getOwner')->willReturn($shareOwner); - $path->method('getName')->willReturn('target'); - $path->method('getId')->willReturn(1); - $path->method('getStorage')->willReturn($storage); - - $share = $this->manager->newShare(); - $share->setShareType(IShare::TYPE_EMAIL) - ->setNode($path) - ->setSharedBy('sharedBy') - ->setPermissions(\OCP\Constants::PERMISSION_ALL); - - $manager->expects($this->once()) - ->method('canShare') - ->with($share) - ->willReturn(true); - $manager->expects($this->once()) - ->method('generalCreateChecks') - ->with($share); - - $manager->expects($this->once()) - ->method('linkCreateChecks'); - $manager->expects($this->once()) - ->method('pathCreateChecks') - ->with($path); - $manager->expects($this->once()) - ->method('validateExpirationDateLink') - ->with($share) - ->willReturn($share); - $manager->expects($this->once()) - ->method('verifyPassword'); - $manager->expects($this->once()) - ->method('setLinkParent'); - - $this->secureRandom->method('generate') - ->willReturn('token'); - - $this->defaultProvider - ->expects($this->once()) - ->method('create') - ->with($share) - ->willReturnCallback(function (Share $share) { - return $share->setId(42); - }); - - $this->dispatcher->expects($this->exactly(2)) - ->method('dispatchTyped') - ->withConsecutive( - [ - $this->callback(function (BeforeShareCreatedEvent $e) use ($path) { - $share = $e->getShare(); - - return $share->getShareType() === IShare::TYPE_EMAIL && - $share->getNode() === $path && - $share->getSharedBy() === 'sharedBy' && - $share->getPermissions() === \OCP\Constants::PERMISSION_ALL && - $share->getExpirationDate() === null && - $share->getPassword() === null && - $share->getToken() === 'token'; - }) - ], - [ - $this->callback(function (ShareCreatedEvent $e) use ($path) { - $share = $e->getShare(); - - return $share->getShareType() === IShare::TYPE_EMAIL && - $share->getNode() === $path && - $share->getSharedBy() === 'sharedBy' && - $share->getPermissions() === \OCP\Constants::PERMISSION_ALL && - $share->getExpirationDate() === null && - $share->getPassword() === null && - $share->getToken() === 'token' && - $share->getId() === '42' && - $share->getTarget() === '/target'; - }) - ], - ); - - /** @var IShare $share */ - $share = $manager->createShare($share); - - $this->assertSame('shareOwner', $share->getShareOwner()); - $this->assertEquals('/target', $share->getTarget()); - $this->assertEquals('token', $share->getToken()); - } - - - public function testCreateShareHookError(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('I won\'t let you share'); - - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'generalCreateChecks', - 'userCreateChecks', - 'pathCreateChecks', - ]) - ->getMock(); - - $shareOwner = $this->createMock(IUser::class); - $shareOwner->method('getUID')->willReturn('shareOwner'); - - $storage = $this->createMock(Storage::class); - $path = $this->createMock(File::class); - $path->method('getOwner')->willReturn($shareOwner); - $path->method('getName')->willReturn('target'); - $path->method('getStorage')->willReturn($storage); - - $share = $this->createShare( - null, - IShare::TYPE_USER, - $path, - 'sharedWith', - 'sharedBy', - null, - \OCP\Constants::PERMISSION_ALL); - - $manager->expects($this->once()) - ->method('canShare') - ->with($share) - ->willReturn(true); - $manager->expects($this->once()) - ->method('generalCreateChecks') - ->with($share); - ; - $manager->expects($this->once()) - ->method('userCreateChecks') - ->with($share); - ; - $manager->expects($this->once()) - ->method('pathCreateChecks') - ->with($path); - - $share->expects($this->once()) - ->method('setShareOwner') - ->with('shareOwner'); - $share->expects($this->once()) - ->method('setTarget') - ->with('/target'); - - // Pre share - $this->dispatcher->expects($this->once()) - ->method('dispatchTyped') - ->with( - $this->isInstanceOf(BeforeShareCreatedEvent::class) - )->willReturnCallback(function (BeforeShareCreatedEvent $e) { - $e->setError('I won\'t let you share!'); - $e->stopPropagation(); - } - ); - - $manager->createShare($share); - } - - public function testCreateShareOfIncomingFederatedShare(): void { - $manager = $this->createManagerMock() - ->setMethods(['canShare', 'generalCreateChecks', 'userCreateChecks', 'pathCreateChecks']) - ->getMock(); - - $shareOwner = $this->createMock(IUser::class); - $shareOwner->method('getUID')->willReturn('shareOwner'); - - $storage = $this->createMock(Storage::class); - $storage->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(true); - - $storage2 = $this->createMock(Storage::class); - $storage2->method('instanceOfStorage') - ->with('OCA\Files_Sharing\External\Storage') - ->willReturn(false); - - $path = $this->createMock(File::class); - $path->expects($this->never())->method('getOwner'); - $path->method('getName')->willReturn('target'); - $path->method('getStorage')->willReturn($storage); - - $parent = $this->createMock(Folder::class); - $parent->method('getStorage')->willReturn($storage); - - $parentParent = $this->createMock(Folder::class); - $parentParent->method('getStorage')->willReturn($storage2); - $parentParent->method('getOwner')->willReturn($shareOwner); - - $path->method('getParent')->willReturn($parent); - $parent->method('getParent')->willReturn($parentParent); - - $share = $this->createShare( - null, - IShare::TYPE_USER, - $path, - 'sharedWith', - 'sharedBy', - null, - \OCP\Constants::PERMISSION_ALL); - - $manager->expects($this->once()) - ->method('canShare') - ->with($share) - ->willReturn(true); - $manager->expects($this->once()) - ->method('generalCreateChecks') - ->with($share); - ; - $manager->expects($this->once()) - ->method('userCreateChecks') - ->with($share); - ; - $manager->expects($this->once()) - ->method('pathCreateChecks') - ->with($path); - - $this->defaultProvider - ->expects($this->once()) - ->method('create') - ->with($share) - ->willReturnArgument(0); - - $share->expects($this->once()) - ->method('setShareOwner') - ->with('shareOwner'); - $share->expects($this->once()) - ->method('setTarget') - ->with('/target'); - - $manager->createShare($share); - } - - public function testGetSharesBy(): void { - $share = $this->manager->newShare(); - - $node = $this->createMock(Folder::class); - - $this->defaultProvider->expects($this->once()) - ->method('getSharesBy') - ->with( - $this->equalTo('user'), - $this->equalTo(IShare::TYPE_USER), - $this->equalTo($node), - $this->equalTo(true), - $this->equalTo(1), - $this->equalTo(1) - )->willReturn([$share]); - - $shares = $this->manager->getSharesBy('user', IShare::TYPE_USER, $node, true, 1, 1); - - $this->assertCount(1, $shares); - $this->assertSame($share, $shares[0]); - } - - /** - * Test to ensure we correctly remove expired link shares - * - * We have 8 Shares and we want the 3 first valid shares. - * share 3-6 and 8 are expired. Thus at the end of this test we should - * have received share 1,2 and 7. And from the manager. Share 3-6 should be - * deleted (as they are evaluated). but share 8 should still be there. - */ - public function testGetSharesByExpiredLinkShares(): void { - $manager = $this->createManagerMock() - ->setMethods(['deleteShare']) - ->getMock(); - - /** @var \OCP\Share\IShare[] $shares */ - $shares = []; - - /* - * This results in an array of 8 IShare elements - */ - for ($i = 0; $i < 8; $i++) { - $share = $this->manager->newShare(); - $share->setId($i); - $shares[] = $share; - } - - $today = new \DateTime(); - $today->setTime(0, 0, 0); - - /* - * Set the expiration date to today for some shares - */ - $shares[2]->setExpirationDate($today); - $shares[3]->setExpirationDate($today); - $shares[4]->setExpirationDate($today); - $shares[5]->setExpirationDate($today); - - /** @var \OCP\Share\IShare[] $i */ - $shares2 = []; - for ($i = 0; $i < 8; $i++) { - $shares2[] = clone $shares[$i]; - } - - $node = $this->createMock(File::class); - - /* - * Simulate the getSharesBy call. - */ - $this->defaultProvider - ->method('getSharesBy') - ->willReturnCallback(function ($uid, $type, $node, $reshares, $limit, $offset) use (&$shares2) { - return array_slice($shares2, $offset, $limit); - }); - - /* - * Simulate the deleteShare call. - */ - $manager->method('deleteShare') - ->willReturnCallback(function ($share) use (&$shares2) { - for ($i = 0; $i < count($shares2); $i++) { - if ($shares2[$i]->getId() === $share->getId()) { - array_splice($shares2, $i, 1); - break; - } - } - }); - - $res = $manager->getSharesBy('user', IShare::TYPE_LINK, $node, true, 3, 0); - - $this->assertCount(3, $res); - $this->assertEquals($shares[0]->getId(), $res[0]->getId()); - $this->assertEquals($shares[1]->getId(), $res[1]->getId()); - $this->assertEquals($shares[6]->getId(), $res[2]->getId()); - - $this->assertCount(4, $shares2); - $this->assertEquals(0, $shares2[0]->getId()); - $this->assertEquals(1, $shares2[1]->getId()); - $this->assertEquals(6, $shares2[2]->getId()); - $this->assertEquals(7, $shares2[3]->getId()); - $this->assertSame($today, $shares[3]->getExpirationDate()); - } - - public function testGetShareByToken(): void { - $this->config - ->expects($this->exactly(2)) - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['files_sharing', 'hide_disabled_user_shares', 'no', 'no'], - ]); - - $factory = $this->createMock(IProviderFactory::class); - - $manager = $this->createManager($factory); - - $share = $this->createMock(IShare::class); - - $factory->expects($this->once()) - ->method('getProviderForType') - ->with(IShare::TYPE_LINK) - ->willReturn($this->defaultProvider); - - $this->defaultProvider->expects($this->once()) - ->method('getShareByToken') - ->with('token') - ->willReturn($share); - - $ret = $manager->getShareByToken('token'); - $this->assertSame($share, $ret); - } - - public function testGetShareByTokenRoom(): void { - $this->config - ->expects($this->exactly(2)) - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_allow_links', 'yes', 'no'], - ['files_sharing', 'hide_disabled_user_shares', 'no', 'no'], - ]); - - $factory = $this->createMock(IProviderFactory::class); - - $manager = $this->createManager($factory); - - $share = $this->createMock(IShare::class); - - $roomShareProvider = $this->createMock(IShareProvider::class); - - $factory->expects($this->any()) - ->method('getProviderForType') - ->willReturnCallback(function ($shareType) use ($roomShareProvider) { - if ($shareType !== IShare::TYPE_ROOM) { - throw new Exception\ProviderException(); - } - - return $roomShareProvider; - }); - - $roomShareProvider->expects($this->once()) - ->method('getShareByToken') - ->with('token') - ->willReturn($share); - - $ret = $manager->getShareByToken('token'); - $this->assertSame($share, $ret); - } - - public function testGetShareByTokenWithException(): void { - $this->config - ->expects($this->exactly(2)) - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['files_sharing', 'hide_disabled_user_shares', 'no', 'no'], - ]); - - $factory = $this->createMock(IProviderFactory::class); - - $manager = $this->createManager($factory); - - $share = $this->createMock(IShare::class); - - $factory->expects($this->exactly(2)) - ->method('getProviderForType') - ->withConsecutive( - [IShare::TYPE_LINK], - [IShare::TYPE_REMOTE] - ) - ->willReturn($this->defaultProvider); - - $this->defaultProvider->expects($this->exactly(2)) - ->method('getShareByToken') - ->with('token') - ->willReturnOnConsecutiveCalls( - $this->throwException(new ShareNotFound()), - $share - ); - - $ret = $manager->getShareByToken('token'); - $this->assertSame($share, $ret); - } - - - public function testGetShareByTokenHideDisabledUser(): void { - $this->expectException(\OCP\Share\Exceptions\ShareNotFound::class); - $this->expectExceptionMessage('The requested share comes from a disabled user'); - - $this->config - ->expects($this->exactly(2)) - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['files_sharing', 'hide_disabled_user_shares', 'no', 'yes'], - ]); - - $this->l->expects($this->once()) - ->method('t') - ->willReturnArgument(0); - - $manager = $this->createManagerMock() - ->setMethods(['deleteShare']) - ->getMock(); - - $date = new \DateTime(); - $date->setTime(0, 0, 0); - $date->add(new \DateInterval('P2D')); - $share = $this->manager->newShare(); - $share->setExpirationDate($date); - $share->setShareOwner('owner'); - $share->setSharedBy('sharedBy'); - - $sharedBy = $this->createMock(IUser::class); - $owner = $this->createMock(IUser::class); - - $this->userManager->method('get')->willReturnMap([ - ['sharedBy', $sharedBy], - ['owner', $owner], - ]); - - $owner->expects($this->once()) - ->method('isEnabled') - ->willReturn(true); - $sharedBy->expects($this->once()) - ->method('isEnabled') - ->willReturn(false); - - $this->defaultProvider->expects($this->once()) - ->method('getShareByToken') - ->with('expiredToken') - ->willReturn($share); - - $manager->expects($this->never()) - ->method('deleteShare'); - - $manager->getShareByToken('expiredToken'); - } - - - public function testGetShareByTokenExpired(): void { - $this->expectException(\OCP\Share\Exceptions\ShareNotFound::class); - $this->expectExceptionMessage('The requested share does not exist anymore'); - - $this->config - ->expects($this->once()) - ->method('getAppValue') - ->with('core', 'shareapi_allow_links', 'yes') - ->willReturn('yes'); - - $this->l->expects($this->once()) - ->method('t') - ->willReturnArgument(0); - - $manager = $this->createManagerMock() - ->setMethods(['deleteShare']) - ->getMock(); - - $date = new \DateTime(); - $date->setTime(0, 0, 0); - $share = $this->manager->newShare(); - $share->setExpirationDate($date); - - $this->defaultProvider->expects($this->once()) - ->method('getShareByToken') - ->with('expiredToken') - ->willReturn($share); - - $manager->expects($this->once()) - ->method('deleteShare') - ->with($this->equalTo($share)); - - $manager->getShareByToken('expiredToken'); - } - - public function testGetShareByTokenNotExpired(): void { - $this->config - ->expects($this->exactly(2)) - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['files_sharing', 'hide_disabled_user_shares', 'no', 'no'], - ]); - - $date = new \DateTime(); - $date->setTime(0, 0, 0); - $date->add(new \DateInterval('P2D')); - $share = $this->manager->newShare(); - $share->setExpirationDate($date); - - $this->defaultProvider->expects($this->once()) - ->method('getShareByToken') - ->with('expiredToken') - ->willReturn($share); - - $res = $this->manager->getShareByToken('expiredToken'); - - $this->assertSame($share, $res); - } - - - public function testGetShareByTokenWithPublicLinksDisabled(): void { - $this->expectException(\OCP\Share\Exceptions\ShareNotFound::class); - - $this->config - ->expects($this->once()) - ->method('getAppValue') - ->with('core', 'shareapi_allow_links', 'yes') - ->willReturn('no'); - $this->manager->getShareByToken('validToken'); - } - - public function testGetShareByTokenPublicUploadDisabled(): void { - $this->config - ->expects($this->exactly(3)) - ->method('getAppValue') - ->willReturnMap([ - ['core', 'shareapi_allow_links', 'yes', 'yes'], - ['core', 'shareapi_allow_public_upload', 'yes', 'no'], - ['files_sharing', 'hide_disabled_user_shares', 'no', 'no'], - ]); - - $share = $this->manager->newShare(); - $share->setShareType(IShare::TYPE_LINK) - ->setPermissions(\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE); - $share->setSharedWith('sharedWith'); - $folder = $this->createMock(\OC\Files\Node\Folder::class); - $share->setNode($folder); - - $this->defaultProvider->expects($this->once()) - ->method('getShareByToken') - ->willReturn('validToken') - ->willReturn($share); - - $res = $this->manager->getShareByToken('validToken'); - - $this->assertSame(\OCP\Constants::PERMISSION_READ, $res->getPermissions()); - } - - public function testCheckPasswordNoLinkShare(): void { - $share = $this->createMock(IShare::class); - $share->method('getShareType')->willReturn(IShare::TYPE_USER); - $this->assertFalse($this->manager->checkPassword($share, 'password')); - } - - public function testCheckPasswordNoPassword(): void { - $share = $this->createMock(IShare::class); - $share->method('getShareType')->willReturn(IShare::TYPE_LINK); - $this->assertFalse($this->manager->checkPassword($share, 'password')); - - $share->method('getPassword')->willReturn('password'); - $this->assertFalse($this->manager->checkPassword($share, null)); - } - - public function testCheckPasswordInvalidPassword(): void { - $share = $this->createMock(IShare::class); - $share->method('getShareType')->willReturn(IShare::TYPE_LINK); - $share->method('getPassword')->willReturn('password'); - - $this->hasher->method('verify')->with('invalidpassword', 'password', '')->willReturn(false); - - $this->assertFalse($this->manager->checkPassword($share, 'invalidpassword')); - } - - public function testCheckPasswordValidPassword(): void { - $share = $this->createMock(IShare::class); - $share->method('getShareType')->willReturn(IShare::TYPE_LINK); - $share->method('getPassword')->willReturn('passwordHash'); - - $this->hasher->method('verify')->with('password', 'passwordHash', '')->willReturn(true); - - $this->assertTrue($this->manager->checkPassword($share, 'password')); - } - - public function testCheckPasswordUpdateShare(): void { - $share = $this->manager->newShare(); - $share->setShareType(IShare::TYPE_LINK) - ->setPassword('passwordHash'); - - $this->hasher->method('verify')->with('password', 'passwordHash', '') - ->willReturnCallback(function ($pass, $hash, &$newHash) { - $newHash = 'newHash'; - - return true; - }); - - $this->defaultProvider->expects($this->once()) - ->method('update') - ->with($this->callback(function (\OCP\Share\IShare $share) { - return $share->getPassword() === 'newHash'; - })); - - $this->assertTrue($this->manager->checkPassword($share, 'password')); - } - - - public function testUpdateShareCantChangeShareType(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Cannot change share type'); - - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'getShareById' - ]) - ->getMock(); - - $originalShare = $this->manager->newShare(); - $originalShare->setShareType(IShare::TYPE_GROUP); - - $manager->expects($this->once())->method('canShare')->willReturn(true); - $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); - - $share = $this->manager->newShare(); - $attrs = $this->manager->newShare()->newAttributes(); - $attrs->setAttribute('app1', 'perm1', true); - $share->setProviderId('foo') - ->setId('42') - ->setShareType(IShare::TYPE_USER); - - $manager->updateShare($share); - } - - - public function testUpdateShareCantChangeRecipientForGroupShare(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Can only update recipient on user shares'); - - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'getShareById' - ]) - ->getMock(); - - $originalShare = $this->manager->newShare(); - $originalShare->setShareType(IShare::TYPE_GROUP) - ->setSharedWith('origGroup'); - - $manager->expects($this->once())->method('canShare')->willReturn(true); - $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); - - $share = $this->manager->newShare(); - $share->setProviderId('foo') - ->setId('42') - ->setShareType(IShare::TYPE_GROUP) - ->setSharedWith('newGroup'); - - $manager->updateShare($share); - } - - - public function testUpdateShareCantShareWithOwner(): void { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Cannot share with the share owner'); - - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'getShareById' - ]) - ->getMock(); - - $originalShare = $this->manager->newShare(); - $originalShare->setShareType(IShare::TYPE_USER) - ->setSharedWith('sharedWith'); - - $manager->expects($this->once())->method('canShare')->willReturn(true); - $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); - - $share = $this->manager->newShare(); - $share->setProviderId('foo') - ->setId('42') - ->setShareType(IShare::TYPE_USER) - ->setSharedWith('newUser') - ->setShareOwner('newUser'); - - $manager->updateShare($share); - } - - public function testUpdateShareUser(): void { - $this->userManager->expects($this->any())->method('userExists')->willReturn(true); - - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'getShareById', - 'generalCreateChecks', - 'userCreateChecks', - 'pathCreateChecks', - ]) - ->getMock(); - - $originalShare = $this->manager->newShare(); - $originalShare->setShareType(IShare::TYPE_USER) - ->setSharedWith('origUser') - ->setPermissions(1); - - $node = $this->createMock(File::class); - $node->method('getId')->willReturn(100); - $node->method('getPath')->willReturn('/newUser/files/myPath'); - - $manager->expects($this->once())->method('canShare')->willReturn(true); - $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); - - $share = $this->manager->newShare(); - $attrs = $this->manager->newShare()->newAttributes(); - $attrs->setAttribute('app1', 'perm1', true); - $share->setProviderId('foo') - ->setId('42') - ->setShareType(IShare::TYPE_USER) - ->setSharedWith('origUser') - ->setShareOwner('newUser') - ->setSharedBy('sharer') - ->setPermissions(31) - ->setAttributes($attrs) - ->setNode($node); - - $this->defaultProvider->expects($this->once()) - ->method('update') - ->with($share) - ->willReturn($share); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post'); - $hookListener->expects($this->never())->method('post'); - - $this->rootFolder->method('getUserFolder')->with('newUser')->willReturnSelf(); - $this->rootFolder->method('getRelativePath')->with('/newUser/files/myPath')->willReturn('/myPath'); - - $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener2, 'post'); - $hookListener2->expects($this->once())->method('post')->with([ - 'itemType' => 'file', - 'itemSource' => 100, - 'shareType' => IShare::TYPE_USER, - 'shareWith' => 'origUser', - 'uidOwner' => 'sharer', - 'permissions' => 31, - 'path' => '/myPath', - 'attributes' => $attrs->toArray(), - ]); - - $manager->updateShare($share); - } - - public function testUpdateShareGroup(): void { - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'getShareById', - 'generalCreateChecks', - 'groupCreateChecks', - 'pathCreateChecks', - ]) - ->getMock(); - - $originalShare = $this->manager->newShare(); - $originalShare->setShareType(IShare::TYPE_GROUP) - ->setSharedWith('origUser') - ->setPermissions(31); - - $manager->expects($this->once())->method('canShare')->willReturn(true); - $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); - - $node = $this->createMock(File::class); - - $share = $this->manager->newShare(); - $share->setProviderId('foo') - ->setId('42') - ->setShareType(IShare::TYPE_GROUP) - ->setSharedWith('origUser') - ->setShareOwner('owner') - ->setNode($node) - ->setPermissions(31); - - $this->defaultProvider->expects($this->once()) - ->method('update') - ->with($share) - ->willReturn($share); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post'); - $hookListener->expects($this->never())->method('post'); - - $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener2, 'post'); - $hookListener2->expects($this->never())->method('post'); - - $manager->updateShare($share); - } - - public function testUpdateShareLink(): void { - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'getShareById', - 'generalCreateChecks', - 'linkCreateChecks', - 'pathCreateChecks', - 'verifyPassword', - 'validateExpirationDateLink', - ]) - ->getMock(); - - $originalShare = $this->manager->newShare(); - $originalShare->setShareType(IShare::TYPE_LINK) - ->setPermissions(15); - - $tomorrow = new \DateTime(); - $tomorrow->setTime(0, 0, 0); - $tomorrow->add(new \DateInterval('P1D')); - - $file = $this->createMock(File::class); - $file->method('getId')->willReturn(100); - - $share = $this->manager->newShare(); - $share->setProviderId('foo') - ->setId('42') - ->setShareType(IShare::TYPE_LINK) - ->setToken('token') - ->setSharedBy('owner') - ->setShareOwner('owner') - ->setPassword('password') - ->setExpirationDate($tomorrow) - ->setNode($file) - ->setPermissions(15); - - $manager->expects($this->once())->method('canShare')->willReturn(true); - $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); - $manager->expects($this->once())->method('validateExpirationDateLink')->with($share); - $manager->expects($this->once())->method('verifyPassword')->with('password'); - - $this->hasher->expects($this->once()) - ->method('hash') - ->with('password') - ->willReturn('hashed'); - - $this->defaultProvider->expects($this->once()) - ->method('update') - ->with($share) - ->willReturn($share); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post'); - $hookListener->expects($this->once())->method('post')->with([ - 'itemType' => 'file', - 'itemSource' => 100, - 'date' => $tomorrow, - 'uidOwner' => 'owner', - ]); - - $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post'); - $hookListener2->expects($this->once())->method('post')->with([ - 'itemType' => 'file', - 'itemSource' => 100, - 'uidOwner' => 'owner', - 'token' => 'token', - 'disabled' => false, - ]); - - $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post'); - $hookListener3->expects($this->never())->method('post'); - - - $manager->updateShare($share); - } - - public function testUpdateShareLinkEnableSendPasswordByTalkWithNoPassword(): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Cannot enable sending the password by Talk with an empty password'); - - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'getShareById', - 'generalCreateChecks', - 'linkCreateChecks', - 'pathCreateChecks', - 'verifyPassword', - 'validateExpirationDateLink', - ]) - ->getMock(); - - $originalShare = $this->manager->newShare(); - $originalShare->setShareType(IShare::TYPE_LINK) - ->setPermissions(15); - - $tomorrow = new \DateTime(); - $tomorrow->setTime(0, 0, 0); - $tomorrow->add(new \DateInterval('P1D')); - - $file = $this->createMock(File::class); - $file->method('getId')->willReturn(100); - - $share = $this->manager->newShare(); - $share->setProviderId('foo') - ->setId('42') - ->setShareType(IShare::TYPE_LINK) - ->setToken('token') - ->setSharedBy('owner') - ->setShareOwner('owner') - ->setPassword(null) - ->setSendPasswordByTalk(true) - ->setExpirationDate($tomorrow) - ->setNode($file) - ->setPermissions(15); - - $manager->expects($this->once())->method('canShare')->willReturn(true); - $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); - $manager->expects($this->once())->method('generalCreateChecks')->with($share); - $manager->expects($this->once())->method('linkCreateChecks')->with($share); - $manager->expects($this->never())->method('verifyPassword'); - $manager->expects($this->never())->method('pathCreateChecks'); - $manager->expects($this->never())->method('validateExpirationDateLink'); - - $this->hasher->expects($this->never()) - ->method('hash'); - - $this->defaultProvider->expects($this->never()) - ->method('update'); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post'); - $hookListener->expects($this->never())->method('post'); - - $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post'); - $hookListener2->expects($this->never())->method('post'); - - $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post'); - $hookListener3->expects($this->never())->method('post'); - - $manager->updateShare($share); - } - - public function testUpdateShareMail(): void { - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'getShareById', - 'generalCreateChecks', - 'verifyPassword', - 'pathCreateChecks', - 'linkCreateChecks', - 'validateExpirationDateLink', - ]) - ->getMock(); - - $originalShare = $this->manager->newShare(); - $originalShare->setShareType(IShare::TYPE_EMAIL) - ->setPermissions(\OCP\Constants::PERMISSION_ALL); - - $tomorrow = new \DateTime(); - $tomorrow->setTime(0, 0, 0); - $tomorrow->add(new \DateInterval('P1D')); - - $file = $this->createMock(File::class); - $file->method('getId')->willReturn(100); - - $share = $this->manager->newShare(); - $share->setProviderId('foo') - ->setId('42') - ->setShareType(IShare::TYPE_EMAIL) - ->setToken('token') - ->setSharedBy('owner') - ->setShareOwner('owner') - ->setPassword('password') - ->setExpirationDate($tomorrow) - ->setNode($file) - ->setPermissions(\OCP\Constants::PERMISSION_ALL); - - $manager->expects($this->once())->method('canShare')->willReturn(true); - $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); - $manager->expects($this->once())->method('generalCreateChecks')->with($share); - $manager->expects($this->once())->method('verifyPassword')->with('password'); - $manager->expects($this->once())->method('pathCreateChecks')->with($file); - $manager->expects($this->once())->method('linkCreateChecks'); - $manager->expects($this->once())->method('validateExpirationDateLink'); - - $this->hasher->expects($this->once()) - ->method('hash') - ->with('password') - ->willReturn('hashed'); - - $this->defaultProvider->expects($this->once()) - ->method('update') - ->with($share, 'password') - ->willReturn($share); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post'); - $hookListener->expects($this->once())->method('post')->with([ - 'itemType' => 'file', - 'itemSource' => 100, - 'date' => $tomorrow, - 'uidOwner' => 'owner', - ]); - - $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post'); - $hookListener2->expects($this->once())->method('post')->with([ - 'itemType' => 'file', - 'itemSource' => 100, - 'uidOwner' => 'owner', - 'token' => 'token', - 'disabled' => false, - ]); - - $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post'); - $hookListener3->expects($this->never())->method('post'); - - $manager->updateShare($share); - } - - public function testUpdateShareMailEnableSendPasswordByTalk(): void { - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'getShareById', - 'generalCreateChecks', - 'verifyPassword', - 'pathCreateChecks', - 'linkCreateChecks', - 'validateExpirationDateLink', - ]) - ->getMock(); - - $originalShare = $this->manager->newShare(); - $originalShare->setShareType(IShare::TYPE_EMAIL) - ->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setPassword(null) - ->setSendPasswordByTalk(false); - - $tomorrow = new \DateTime(); - $tomorrow->setTime(0, 0, 0); - $tomorrow->add(new \DateInterval('P1D')); - - $file = $this->createMock(File::class); - $file->method('getId')->willReturn(100); - - $share = $this->manager->newShare(); - $share->setProviderId('foo') - ->setId('42') - ->setShareType(IShare::TYPE_EMAIL) - ->setToken('token') - ->setSharedBy('owner') - ->setShareOwner('owner') - ->setPassword('password') - ->setSendPasswordByTalk(true) - ->setExpirationDate($tomorrow) - ->setNode($file) - ->setPermissions(\OCP\Constants::PERMISSION_ALL); - - $manager->expects($this->once())->method('canShare')->willReturn(true); - $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); - $manager->expects($this->once())->method('generalCreateChecks')->with($share); - $manager->expects($this->once())->method('verifyPassword')->with('password'); - $manager->expects($this->once())->method('pathCreateChecks')->with($file); - $manager->expects($this->once())->method('linkCreateChecks'); - $manager->expects($this->once())->method('validateExpirationDateLink'); - - $this->hasher->expects($this->once()) - ->method('hash') - ->with('password') - ->willReturn('hashed'); - - $this->defaultProvider->expects($this->once()) - ->method('update') - ->with($share, 'password') - ->willReturn($share); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post'); - $hookListener->expects($this->once())->method('post')->with([ - 'itemType' => 'file', - 'itemSource' => 100, - 'date' => $tomorrow, - 'uidOwner' => 'owner', - ]); - - $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post'); - $hookListener2->expects($this->once())->method('post')->with([ - 'itemType' => 'file', - 'itemSource' => 100, - 'uidOwner' => 'owner', - 'token' => 'token', - 'disabled' => false, - ]); - - $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post'); - $hookListener3->expects($this->never())->method('post'); - - $manager->updateShare($share); - } - - public function testUpdateShareMailEnableSendPasswordByTalkWithDifferentPassword(): void { - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'getShareById', - 'generalCreateChecks', - 'verifyPassword', - 'pathCreateChecks', - 'linkCreateChecks', - 'validateExpirationDateLink', - ]) - ->getMock(); - - $originalShare = $this->manager->newShare(); - $originalShare->setShareType(IShare::TYPE_EMAIL) - ->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setPassword('anotherPasswordHash') - ->setSendPasswordByTalk(false); - - $tomorrow = new \DateTime(); - $tomorrow->setTime(0, 0, 0); - $tomorrow->add(new \DateInterval('P1D')); - - $file = $this->createMock(File::class); - $file->method('getId')->willReturn(100); - - $share = $this->manager->newShare(); - $share->setProviderId('foo') - ->setId('42') - ->setShareType(IShare::TYPE_EMAIL) - ->setToken('token') - ->setSharedBy('owner') - ->setShareOwner('owner') - ->setPassword('password') - ->setSendPasswordByTalk(true) - ->setExpirationDate($tomorrow) - ->setNode($file) - ->setPermissions(\OCP\Constants::PERMISSION_ALL); - - $manager->expects($this->once())->method('canShare')->willReturn(true); - $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); - $manager->expects($this->once())->method('generalCreateChecks')->with($share); - $manager->expects($this->once())->method('verifyPassword')->with('password'); - $manager->expects($this->once())->method('pathCreateChecks')->with($file); - $manager->expects($this->once())->method('linkCreateChecks'); - $manager->expects($this->once())->method('validateExpirationDateLink'); - - $this->hasher->expects($this->once()) - ->method('verify') - ->with('password', 'anotherPasswordHash') - ->willReturn(false); - - $this->hasher->expects($this->once()) - ->method('hash') - ->with('password') - ->willReturn('hashed'); - - $this->defaultProvider->expects($this->once()) - ->method('update') - ->with($share, 'password') - ->willReturn($share); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post'); - $hookListener->expects($this->once())->method('post')->with([ - 'itemType' => 'file', - 'itemSource' => 100, - 'date' => $tomorrow, - 'uidOwner' => 'owner', - ]); - - $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post'); - $hookListener2->expects($this->once())->method('post')->with([ - 'itemType' => 'file', - 'itemSource' => 100, - 'uidOwner' => 'owner', - 'token' => 'token', - 'disabled' => false, - ]); - - $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post'); - $hookListener3->expects($this->never())->method('post'); - - $manager->updateShare($share); - } - - public function testUpdateShareMailEnableSendPasswordByTalkWithNoPassword(): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Cannot enable sending the password by Talk with an empty password'); - - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'getShareById', - 'generalCreateChecks', - 'verifyPassword', - 'pathCreateChecks', - 'linkCreateChecks', - 'validateExpirationDateLink', - ]) - ->getMock(); - - $originalShare = $this->manager->newShare(); - $originalShare->setShareType(IShare::TYPE_EMAIL) - ->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setPassword(null) - ->setSendPasswordByTalk(false); - - $tomorrow = new \DateTime(); - $tomorrow->setTime(0, 0, 0); - $tomorrow->add(new \DateInterval('P1D')); - - $file = $this->createMock(File::class); - $file->method('getId')->willReturn(100); - - $share = $this->manager->newShare(); - $share->setProviderId('foo') - ->setId('42') - ->setShareType(IShare::TYPE_EMAIL) - ->setToken('token') - ->setSharedBy('owner') - ->setShareOwner('owner') - ->setPassword(null) - ->setSendPasswordByTalk(true) - ->setExpirationDate($tomorrow) - ->setNode($file) - ->setPermissions(\OCP\Constants::PERMISSION_ALL); - - $manager->expects($this->once())->method('canShare')->willReturn(true); - $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); - $manager->expects($this->once())->method('generalCreateChecks')->with($share); - $manager->expects($this->never())->method('verifyPassword'); - $manager->expects($this->never())->method('pathCreateChecks'); - $manager->expects($this->once())->method('linkCreateChecks'); - $manager->expects($this->never())->method('validateExpirationDateLink'); - - // If the password is empty, we have nothing to hash - $this->hasher->expects($this->never()) - ->method('hash'); - - $this->defaultProvider->expects($this->never()) - ->method('update'); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post'); - $hookListener->expects($this->never())->method('post'); - - $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post'); - $hookListener2->expects($this->never())->method('post'); - - $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post'); - $hookListener3->expects($this->never())->method('post'); - - $manager->updateShare($share); - } - - - public function testUpdateShareMailEnableSendPasswordByTalkRemovingPassword(): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Cannot enable sending the password by Talk with an empty password'); - - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'getShareById', - 'generalCreateChecks', - 'verifyPassword', - 'pathCreateChecks', - 'linkCreateChecks', - 'validateExpirationDateLink', - ]) - ->getMock(); - - $originalShare = $this->manager->newShare(); - $originalShare->setShareType(IShare::TYPE_EMAIL) - ->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setPassword('passwordHash') - ->setSendPasswordByTalk(false); - - $tomorrow = new \DateTime(); - $tomorrow->setTime(0, 0, 0); - $tomorrow->add(new \DateInterval('P1D')); - - $file = $this->createMock(File::class); - $file->method('getId')->willReturn(100); - - $share = $this->manager->newShare(); - $share->setProviderId('foo') - ->setId('42') - ->setShareType(IShare::TYPE_EMAIL) - ->setToken('token') - ->setSharedBy('owner') - ->setShareOwner('owner') - ->setPassword(null) - ->setSendPasswordByTalk(true) - ->setExpirationDate($tomorrow) - ->setNode($file) - ->setPermissions(\OCP\Constants::PERMISSION_ALL); - - $manager->expects($this->once())->method('canShare')->willReturn(true); - $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); - $manager->expects($this->once())->method('generalCreateChecks')->with($share); - $manager->expects($this->once())->method('verifyPassword'); - $manager->expects($this->never())->method('pathCreateChecks'); - $manager->expects($this->once())->method('linkCreateChecks'); - $manager->expects($this->never())->method('validateExpirationDateLink'); - - // If the password is empty, we have nothing to hash - $this->hasher->expects($this->never()) - ->method('hash'); - - $this->defaultProvider->expects($this->never()) - ->method('update'); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post'); - $hookListener->expects($this->never())->method('post'); - - $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post'); - $hookListener2->expects($this->never())->method('post'); - - $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post'); - $hookListener3->expects($this->never())->method('post'); - - $manager->updateShare($share); - } - - - public function testUpdateShareMailEnableSendPasswordByTalkRemovingPasswordWithEmptyString(): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Cannot enable sending the password by Talk with an empty password'); - - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'getShareById', - 'generalCreateChecks', - 'verifyPassword', - 'pathCreateChecks', - 'linkCreateChecks', - 'validateExpirationDateLink', - ]) - ->getMock(); - - $originalShare = $this->manager->newShare(); - $originalShare->setShareType(IShare::TYPE_EMAIL) - ->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setPassword('passwordHash') - ->setSendPasswordByTalk(false); - - $tomorrow = new \DateTime(); - $tomorrow->setTime(0, 0, 0); - $tomorrow->add(new \DateInterval('P1D')); - - $file = $this->createMock(File::class); - $file->method('getId')->willReturn(100); - - $share = $this->manager->newShare(); - $share->setProviderId('foo') - ->setId('42') - ->setShareType(IShare::TYPE_EMAIL) - ->setToken('token') - ->setSharedBy('owner') - ->setShareOwner('owner') - ->setPassword('') - ->setSendPasswordByTalk(true) - ->setExpirationDate($tomorrow) - ->setNode($file) - ->setPermissions(\OCP\Constants::PERMISSION_ALL); - - $manager->expects($this->once())->method('canShare')->willReturn(true); - $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); - $manager->expects($this->once())->method('generalCreateChecks')->with($share); - $manager->expects($this->once())->method('verifyPassword'); - $manager->expects($this->never())->method('pathCreateChecks'); - $manager->expects($this->once())->method('linkCreateChecks'); - $manager->expects($this->never())->method('validateExpirationDateLink'); - - // If the password is empty, we have nothing to hash - $this->hasher->expects($this->never()) - ->method('hash'); - - $this->defaultProvider->expects($this->never()) - ->method('update'); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post'); - $hookListener->expects($this->never())->method('post'); - - $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post'); - $hookListener2->expects($this->never())->method('post'); - - $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post'); - $hookListener3->expects($this->never())->method('post'); - - $manager->updateShare($share); - } - - - public function testUpdateShareMailEnableSendPasswordByTalkWithPreviousPassword(): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Cannot enable sending the password by Talk without setting a new password'); - - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'getShareById', - 'generalCreateChecks', - 'verifyPassword', - 'pathCreateChecks', - 'linkCreateChecks', - 'validateExpirationDateLink', - ]) - ->getMock(); - - $originalShare = $this->manager->newShare(); - $originalShare->setShareType(IShare::TYPE_EMAIL) - ->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setPassword('password') - ->setSendPasswordByTalk(false); - - $tomorrow = new \DateTime(); - $tomorrow->setTime(0, 0, 0); - $tomorrow->add(new \DateInterval('P1D')); - - $file = $this->createMock(File::class); - $file->method('getId')->willReturn(100); - - $share = $this->manager->newShare(); - $share->setProviderId('foo') - ->setId('42') - ->setShareType(IShare::TYPE_EMAIL) - ->setToken('token') - ->setSharedBy('owner') - ->setShareOwner('owner') - ->setPassword('password') - ->setSendPasswordByTalk(true) - ->setExpirationDate($tomorrow) - ->setNode($file) - ->setPermissions(\OCP\Constants::PERMISSION_ALL); - - $manager->expects($this->once())->method('canShare')->willReturn(true); - $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); - $manager->expects($this->once())->method('generalCreateChecks')->with($share); - $manager->expects($this->never())->method('verifyPassword'); - $manager->expects($this->never())->method('pathCreateChecks'); - $manager->expects($this->once())->method('linkCreateChecks'); - $manager->expects($this->never())->method('validateExpirationDateLink'); - - // If the old & new passwords are the same, we don't do anything - $this->hasher->expects($this->never()) - ->method('verify'); - $this->hasher->expects($this->never()) - ->method('hash'); - - $this->defaultProvider->expects($this->never()) - ->method('update'); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post'); - $hookListener->expects($this->never())->method('post'); - - $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post'); - $hookListener2->expects($this->never())->method('post'); - - $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post'); - $hookListener3->expects($this->never())->method('post'); - - $manager->updateShare($share); - } - - public function testUpdateShareMailDisableSendPasswordByTalkWithPreviousPassword(): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Cannot disable sending the password by Talk without setting a new password'); - - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'getShareById', - 'generalCreateChecks', - 'verifyPassword', - 'pathCreateChecks', - 'linkCreateChecks', - 'validateExpirationDateLink', - ]) - ->getMock(); - - $originalShare = $this->manager->newShare(); - $originalShare->setShareType(IShare::TYPE_EMAIL) - ->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setPassword('passwordHash') - ->setSendPasswordByTalk(true); - - $tomorrow = new \DateTime(); - $tomorrow->setTime(0, 0, 0); - $tomorrow->add(new \DateInterval('P1D')); - - $file = $this->createMock(File::class); - $file->method('getId')->willReturn(100); - - $share = $this->manager->newShare(); - $share->setProviderId('foo') - ->setId('42') - ->setShareType(IShare::TYPE_EMAIL) - ->setToken('token') - ->setSharedBy('owner') - ->setShareOwner('owner') - ->setPassword('passwordHash') - ->setSendPasswordByTalk(false) - ->setExpirationDate($tomorrow) - ->setNode($file) - ->setPermissions(\OCP\Constants::PERMISSION_ALL); - - $manager->expects($this->once())->method('canShare')->willReturn(true); - $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); - $manager->expects($this->once())->method('generalCreateChecks')->with($share); - $manager->expects($this->never())->method('verifyPassword'); - $manager->expects($this->never())->method('pathCreateChecks'); - $manager->expects($this->once())->method('linkCreateChecks'); - $manager->expects($this->never())->method('validateExpirationDateLink'); - - // If the old & new passwords are the same, we don't do anything - $this->hasher->expects($this->never()) - ->method('verify'); - $this->hasher->expects($this->never()) - ->method('hash'); - - $this->defaultProvider->expects($this->never()) - ->method('update'); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post'); - $hookListener->expects($this->never())->method('post'); - - $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post'); - $hookListener2->expects($this->never())->method('post'); - - $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post'); - $hookListener3->expects($this->never())->method('post'); - - $manager->updateShare($share); - } - - public function testUpdateShareMailDisableSendPasswordByTalkWithoutChangingPassword(): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Cannot disable sending the password by Talk without setting a new password'); - - $manager = $this->createManagerMock() - ->setMethods([ - 'canShare', - 'getShareById', - 'generalCreateChecks', - 'verifyPassword', - 'pathCreateChecks', - 'linkCreateChecks', - 'validateExpirationDateLink', - ]) - ->getMock(); - - $originalShare = $this->manager->newShare(); - $originalShare->setShareType(IShare::TYPE_EMAIL) - ->setPermissions(\OCP\Constants::PERMISSION_ALL) - ->setPassword('passwordHash') - ->setSendPasswordByTalk(true); - - $tomorrow = new \DateTime(); - $tomorrow->setTime(0, 0, 0); - $tomorrow->add(new \DateInterval('P1D')); - - $file = $this->createMock(File::class); - $file->method('getId')->willReturn(100); - - $share = $this->manager->newShare(); - $share->setProviderId('foo') - ->setId('42') - ->setShareType(IShare::TYPE_EMAIL) - ->setToken('token') - ->setSharedBy('owner') - ->setShareOwner('owner') - ->setPassword('passwordHash') - ->setSendPasswordByTalk(false) - ->setExpirationDate($tomorrow) - ->setNode($file) - ->setPermissions(\OCP\Constants::PERMISSION_ALL); - - $manager->expects($this->once())->method('canShare')->willReturn(true); - $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); - $manager->expects($this->once())->method('generalCreateChecks')->with($share); - $manager->expects($this->never())->method('verifyPassword'); - $manager->expects($this->never())->method('pathCreateChecks'); - $manager->expects($this->once())->method('linkCreateChecks'); - $manager->expects($this->never())->method('validateExpirationDateLink'); - - // If the old & new passwords are the same, we don't do anything - $this->hasher->expects($this->never()) - ->method('verify'); - $this->hasher->expects($this->never()) - ->method('hash'); - - $this->defaultProvider->expects($this->never()) - ->method('update'); - - $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post'); - $hookListener->expects($this->never())->method('post'); - - $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post'); - $hookListener2->expects($this->never())->method('post'); - - $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post'); - $hookListener3->expects($this->never())->method('post'); - - $manager->updateShare($share); - } - - public function testMoveShareLink(): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Cannot change target of link share'); - - $share = $this->manager->newShare(); - $share->setShareType(IShare::TYPE_LINK); - - $recipient = $this->createMock(IUser::class); - - $this->manager->moveShare($share, $recipient); - } - - - public function testMoveShareUserNotRecipient(): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid recipient'); - - $share = $this->manager->newShare(); - $share->setShareType(IShare::TYPE_USER); - - $share->setSharedWith('sharedWith'); - - $this->manager->moveShare($share, 'recipient'); - } - - public function testMoveShareUser(): void { - $share = $this->manager->newShare(); - $share->setShareType(IShare::TYPE_USER) - ->setId('42') - ->setProviderId('foo'); - - $share->setSharedWith('recipient'); - - $this->defaultProvider->method('move')->with($share, 'recipient')->willReturnArgument(0); - - $this->manager->moveShare($share, 'recipient'); - $this->addToAssertionCount(1); - } - - - public function testMoveShareGroupNotRecipient(): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid recipient'); - - $share = $this->manager->newShare(); - $share->setShareType(IShare::TYPE_GROUP); - - $sharedWith = $this->createMock(IGroup::class); - $share->setSharedWith('shareWith'); - - $recipient = $this->createMock(IUser::class); - $sharedWith->method('inGroup')->with($recipient)->willReturn(false); - - $this->groupManager->method('get')->with('shareWith')->willReturn($sharedWith); - $this->userManager->method('get')->with('recipient')->willReturn($recipient); - - $this->manager->moveShare($share, 'recipient'); - } - - - public function testMoveShareGroupNull(): void { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Group "shareWith" does not exist'); - - $share = $this->manager->newShare(); - $share->setShareType(IShare::TYPE_GROUP); - $share->setSharedWith('shareWith'); - - $recipient = $this->createMock(IUser::class); - - $this->groupManager->method('get')->with('shareWith')->willReturn(null); - $this->userManager->method('get')->with('recipient')->willReturn($recipient); - - $this->manager->moveShare($share, 'recipient'); - } - - public function testMoveShareGroup(): void { - $share = $this->manager->newShare(); - $share->setShareType(IShare::TYPE_GROUP) - ->setId('42') - ->setProviderId('foo'); - - $group = $this->createMock(IGroup::class); - $share->setSharedWith('group'); - - $recipient = $this->createMock(IUser::class); - $group->method('inGroup')->with($recipient)->willReturn(true); - - $this->groupManager->method('get')->with('group')->willReturn($group); - $this->userManager->method('get')->with('recipient')->willReturn($recipient); - - $this->defaultProvider->method('move')->with($share, 'recipient')->willReturnArgument(0); - - $this->manager->moveShare($share, 'recipient'); - $this->addToAssertionCount(1); - } - - /** - * @dataProvider dataTestShareProviderExists - */ - public function testShareProviderExists($shareType, $expected): void { - $factory = $this->getMockBuilder('OCP\Share\IProviderFactory')->getMock(); - $factory->expects($this->any())->method('getProviderForType') - ->willReturnCallback(function ($id) { - if ($id === IShare::TYPE_USER) { - return true; - } - throw new Exception\ProviderException(); - }); - - $manager = $this->createManager($factory); - $this->assertSame($expected, - $manager->shareProviderExists($shareType) - ); - } - - public function dataTestShareProviderExists() { - return [ - [IShare::TYPE_USER, true], - [42, false], - ]; - } - - public function testGetSharesInFolder(): void { - $factory = new DummyFactory2($this->createMock(IServerContainer::class)); - - $manager = $this->createManager($factory); - - $factory->setProvider($this->defaultProvider); - $extraProvider = $this->createMock(IShareProvider::class); - $factory->setSecondProvider($extraProvider); - - $share1 = $this->createMock(IShare::class); - $share2 = $this->createMock(IShare::class); - $share3 = $this->createMock(IShare::class); - $share4 = $this->createMock(IShare::class); - - $folder = $this->createMock(Folder::class); - - $this->defaultProvider->method('getSharesInFolder') - ->with( - $this->equalTo('user'), - $this->equalTo($folder), - $this->equalTo(false) - )->willReturn([ - 1 => [$share1], - 2 => [$share2], - ]); - - $extraProvider->method('getSharesInFolder') - ->with( - $this->equalTo('user'), - $this->equalTo($folder), - $this->equalTo(false) - )->willReturn([ - 2 => [$share3], - 3 => [$share4], - ]); - - $result = $manager->getSharesInFolder('user', $folder, false); - - $expects = [ - 1 => [$share1], - 2 => [$share2, $share3], - 3 => [$share4], - ]; - - $this->assertSame($expects, $result); - } - - public function testGetAccessList(): void { - $factory = new DummyFactory2($this->createMock(IServerContainer::class)); - - $manager = $this->createManager($factory); - - $factory->setProvider($this->defaultProvider); - $extraProvider = $this->createMock(IShareProvider::class); - $factory->setSecondProvider($extraProvider); - - $nodeOwner = $this->createMock(IUser::class); - $nodeOwner->expects($this->once()) - ->method('getUID') - ->willReturn('user1'); - - $node = $this->createMock(Node::class); - $node->expects($this->once()) - ->method('getOwner') - ->willReturn($nodeOwner); - $node->method('getId') - ->willReturn(42); - - $userFolder = $this->createMock(Folder::class); - $file = $this->createMock(File::class); - $folder = $this->createMock(Folder::class); - - $owner = $this->createMock(IUser::class); - $owner->expects($this->once()) - ->method('getUID') - ->willReturn('owner'); - - $file->method('getParent') - ->willReturn($folder); - $file->method('getPath') - ->willReturn('/owner/files/folder/file'); - $file->method('getOwner') - ->willReturn($owner); - $file->method('getId') - ->willReturn(23); - $folder->method('getParent') - ->willReturn($userFolder); - $folder->method('getPath') - ->willReturn('/owner/files/folder'); - $userFolder->method('getFirstNodeById') - ->with($this->equalTo(42)) - ->willReturn($file); - $userFolder->method('getPath') - ->willReturn('/user1/files'); - - $this->userManager->method('userExists') - ->with($this->equalTo('user1')) - ->willReturn(true); - - $this->defaultProvider->method('getAccessList') - ->with( - $this->equalTo([$file, $folder]), - false - ) - ->willReturn([ - 'users' => [ - 'user1', - 'user2', - 'user3', - '123456', - ], - 'public' => true, - ]); - - $extraProvider->method('getAccessList') - ->with( - $this->equalTo([$file, $folder]), - false - ) - ->willReturn([ - 'users' => [ - 'user3', - 'user4', - 'user5', - '234567', - ], - 'remote' => true, - ]); - - $this->rootFolder->method('getUserFolder') - ->with($this->equalTo('user1')) - ->willReturn($userFolder); - - $expected = [ - 'users' => ['owner', 'user1', 'user2', 'user3', '123456','user4', 'user5', '234567'], - 'remote' => true, - 'public' => true, - ]; - - $result = $manager->getAccessList($node, true, false); - - $this->assertSame($expected['public'], $result['public']); - $this->assertSame($expected['remote'], $result['remote']); - $this->assertSame($expected['users'], $result['users']); - } - - public function testGetAccessListWithCurrentAccess(): void { - $factory = new DummyFactory2($this->createMock(IServerContainer::class)); - - $manager = $this->createManager($factory); - - $factory->setProvider($this->defaultProvider); - $extraProvider = $this->createMock(IShareProvider::class); - $factory->setSecondProvider($extraProvider); - - $nodeOwner = $this->createMock(IUser::class); - $nodeOwner->expects($this->once()) - ->method('getUID') - ->willReturn('user1'); - - $node = $this->createMock(Node::class); - $node->expects($this->once()) - ->method('getOwner') - ->willReturn($nodeOwner); - $node->method('getId') - ->willReturn(42); - - $userFolder = $this->createMock(Folder::class); - $file = $this->createMock(File::class); - - $owner = $this->createMock(IUser::class); - $owner->expects($this->once()) - ->method('getUID') - ->willReturn('owner'); - $folder = $this->createMock(Folder::class); - - $file->method('getParent') - ->willReturn($folder); - $file->method('getPath') - ->willReturn('/owner/files/folder/file'); - $file->method('getOwner') - ->willReturn($owner); - $file->method('getId') - ->willReturn(23); - $folder->method('getParent') - ->willReturn($userFolder); - $folder->method('getPath') - ->willReturn('/owner/files/folder'); - $userFolder->method('getFirstNodeById') - ->with($this->equalTo(42)) - ->willReturn($file); - $userFolder->method('getPath') - ->willReturn('/user1/files'); - - $this->userManager->method('userExists') - ->with($this->equalTo('user1')) - ->willReturn(true); - - $this->defaultProvider->method('getAccessList') - ->with( - $this->equalTo([$file, $folder]), - true - ) - ->willReturn([ - 'users' => [ - 'user1' => [], - 'user2' => [], - 'user3' => [], - '123456' => [], - ], - 'public' => true, - ]); - - $extraProvider->method('getAccessList') - ->with( - $this->equalTo([$file, $folder]), - true - ) - ->willReturn([ - 'users' => [ - 'user3' => [], - 'user4' => [], - 'user5' => [], - '234567' => [], - ], - 'remote' => [ - 'remote1', - ], - ]); - - $this->rootFolder->method('getUserFolder') - ->with($this->equalTo('user1')) - ->willReturn($userFolder); - - $expected = [ - 'users' => [ - 'owner' => [ - 'node_id' => 23, - 'node_path' => '/folder/file' - ] - , 'user1' => [], 'user2' => [], 'user3' => [], '123456' => [], 'user4' => [], 'user5' => [], '234567' => []], - 'remote' => [ - 'remote1', - ], - 'public' => true, - ]; - - $result = $manager->getAccessList($node, true, true); - - $this->assertSame($expected['public'], $result['public']); - $this->assertSame($expected['remote'], $result['remote']); - $this->assertSame($expected['users'], $result['users']); - } - - public function testGetAllShares(): void { - $factory = new DummyFactory2($this->createMock(IServerContainer::class)); - - $manager = $this->createManager($factory); - - $factory->setProvider($this->defaultProvider); - $extraProvider = $this->createMock(IShareProvider::class); - $factory->setSecondProvider($extraProvider); - - $share1 = $this->createMock(IShare::class); - $share2 = $this->createMock(IShare::class); - $share3 = $this->createMock(IShare::class); - $share4 = $this->createMock(IShare::class); - - $this->defaultProvider->method('getAllShares') - ->willReturnCallback(function () use ($share1, $share2) { - yield $share1; - yield $share2; - }); - $extraProvider->method('getAllShares') - ->willReturnCallback(function () use ($share3, $share4) { - yield $share3; - yield $share4; - }); - - // "yield from", used in "getAllShares()", does not reset the keys, so - // "use_keys" has to be disabled to collect all the values while - // ignoring the keys returned by the generator. - $result = iterator_to_array($manager->getAllShares(), $use_keys = false); - - $expects = [$share1, $share2, $share3, $share4]; - - $this->assertSame($expects, $result); - } - - public function dataCurrentUserCanEnumerateTargetUser(): array { - return [ - 'Full match guest' => [true, true, false, false, false, false, false, true], - 'Full match user' => [false, true, false, false, false, false, false, true], - 'Enumeration off guest' => [true, false, false, false, false, false, false, false], - 'Enumeration off user' => [false, false, false, false, false, false, false, false], - 'Enumeration guest' => [true, false, true, false, false, false, false, true], - 'Enumeration user' => [false, false, true, false, false, false, false, true], - - // Restricted enumerations guests never works - 'Guest phone' => [true, false, true, true, false, false, false, false], - 'Guest group' => [true, false, true, false, true, false, false, false], - 'Guest both' => [true, false, true, true, true, false, false, false], - - // Restricted enumerations users - 'User phone but not known' => [false, false, true, true, false, false, false, false], - 'User phone known' => [false, false, true, true, false, true, false, true], - 'User group but no match' => [false, false, true, false, true, false, false, false], - 'User group with match' => [false, false, true, false, true, false, true, true], - ]; - } - - /** - * @dataProvider dataCurrentUserCanEnumerateTargetUser - * @param bool $expected - */ - public function testCurrentUserCanEnumerateTargetUser(bool $currentUserIsGuest, bool $allowEnumerationFullMatch, bool $allowEnumeration, bool $limitEnumerationToPhone, bool $limitEnumerationToGroups, bool $isKnownToUser, bool $haveCommonGroup, bool $expected): void { - /** @var IManager|MockObject $manager */ - $manager = $this->createManagerMock() - ->setMethods([ - 'allowEnumerationFullMatch', - 'allowEnumeration', - 'limitEnumerationToPhone', - 'limitEnumerationToGroups', - ]) - ->getMock(); - - $manager->method('allowEnumerationFullMatch') - ->willReturn($allowEnumerationFullMatch); - $manager->method('allowEnumeration') - ->willReturn($allowEnumeration); - $manager->method('limitEnumerationToPhone') - ->willReturn($limitEnumerationToPhone); - $manager->method('limitEnumerationToGroups') - ->willReturn($limitEnumerationToGroups); - - $this->knownUserService->method('isKnownToUser') - ->with('current', 'target') - ->willReturn($isKnownToUser); - - $currentUser = null; - if (!$currentUserIsGuest) { - $currentUser = $this->createMock(IUser::class); - $currentUser->method('getUID') - ->willReturn('current'); - } - $targetUser = $this->createMock(IUser::class); - $targetUser->method('getUID') - ->willReturn('target'); - - if ($haveCommonGroup) { - $this->groupManager->method('getUserGroupIds') - ->willReturnMap([ - [$targetUser, ['gid1', 'gid2']], - [$currentUser, ['gid2', 'gid3']], - ]); - } else { - $this->groupManager->method('getUserGroupIds') - ->willReturnMap([ - [$targetUser, ['gid1', 'gid2']], - [$currentUser, ['gid3', 'gid4']], - ]); - } - - $this->assertSame($expected, $manager->currentUserCanEnumerateTargetUser($currentUser, $targetUser)); - } -} - -class DummyFactory implements IProviderFactory { - /** @var IShareProvider */ - protected $provider; - - public function __construct(\OCP\IServerContainer $serverContainer) { - } - - /** - * @param IShareProvider $provider - */ - public function setProvider($provider) { - $this->provider = $provider; - } - - /** - * @param string $id - * @return IShareProvider - */ - public function getProvider($id) { - return $this->provider; - } - - /** - * @param int $shareType - * @return IShareProvider - */ - public function getProviderForType($shareType) { - return $this->provider; - } - - /** - * @return IShareProvider[] - */ - public function getAllProviders() { - return [$this->provider]; - } - - public function registerProvider(string $shareProvier): void { - } -} - -class DummyFactory2 extends DummyFactory { - /** @var IShareProvider */ - private $provider2; - - /** - * @param IShareProvider $provider - */ - public function setSecondProvider($provider) { - $this->provider2 = $provider; - } - - public function getAllProviders() { - return [$this->provider, $this->provider2]; - } - - public function registerProvider(string $shareProvier): void { - } -} +<?php +/** + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace Test\Share20; + +use DateTimeZone; +use OC\Files\Mount\MoveableMount; +use OC\KnownUser\KnownUserService; +use OC\Share20\DefaultShareProvider; +use OC\Share20\Exception; +use OC\Share20\Manager; +use OC\Share20\Share; +use OC\Share20\ShareDisableChecker; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\File; +use OCP\Files\Folder; +use OCP\Files\IRootFolder; +use OCP\Files\Mount\IMountManager; +use OCP\Files\Mount\IMountPoint; +use OCP\Files\Node; +use OCP\Files\Storage; +use OCP\HintException; +use OCP\IConfig; +use OCP\IDateTimeZone; +use OCP\IGroup; +use OCP\IGroupManager; +use OCP\IL10N; +use OCP\IServerContainer; +use OCP\IURLGenerator; +use OCP\IUser; +use OCP\IUserManager; +use OCP\IUserSession; +use OCP\L10N\IFactory; +use OCP\Mail\IMailer; +use OCP\Security\Events\ValidatePasswordPolicyEvent; +use OCP\Security\IHasher; +use OCP\Security\ISecureRandom; +use OCP\Share\Events\BeforeShareCreatedEvent; +use OCP\Share\Events\BeforeShareDeletedEvent; +use OCP\Share\Events\ShareCreatedEvent; +use OCP\Share\Events\ShareDeletedEvent; +use OCP\Share\Events\ShareDeletedFromSelfEvent; +use OCP\Share\Exceptions\AlreadySharedException; +use OCP\Share\Exceptions\ShareNotFound; +use OCP\Share\IManager; +use OCP\Share\IProviderFactory; +use OCP\Share\IShare; +use OCP\Share\IShareProvider; +use PHPUnit\Framework\MockObject\MockBuilder; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; + +/** + * Class ManagerTest + * + * @package Test\Share20 + * @group DB + */ +class ManagerTest extends \Test\TestCase { + /** @var Manager */ + protected $manager; + /** @var LoggerInterface|MockObject */ + protected $logger; + /** @var IConfig|MockObject */ + protected $config; + /** @var ISecureRandom|MockObject */ + protected $secureRandom; + /** @var IHasher|MockObject */ + protected $hasher; + /** @var IShareProvider|MockObject */ + protected $defaultProvider; + /** @var IMountManager|MockObject */ + protected $mountManager; + /** @var IGroupManager|MockObject */ + protected $groupManager; + /** @var IL10N|MockObject */ + protected $l; + /** @var IFactory|MockObject */ + protected $l10nFactory; + /** @var DummyFactory */ + protected $factory; + /** @var IUserManager|MockObject */ + protected $userManager; + /** @var IRootFolder | MockObject */ + protected $rootFolder; + /** @var IEventDispatcher|MockObject */ + protected $dispatcher; + /** @var IMailer|MockObject */ + protected $mailer; + /** @var IURLGenerator|MockObject */ + protected $urlGenerator; + /** @var \OC_Defaults|MockObject */ + protected $defaults; + /** @var IUserSession|MockObject */ + protected $userSession; + /** @var KnownUserService|MockObject */ + protected $knownUserService; + /** @var ShareDisableChecker|MockObject */ + protected $shareDisabledChecker; + private DateTimeZone $timezone; + /** @var IDateTimeZone|MockObject */ + protected $dateTimeZone; + + protected function setUp(): void { + $this->logger = $this->createMock(LoggerInterface::class); + $this->config = $this->createMock(IConfig::class); + $this->secureRandom = $this->createMock(ISecureRandom::class); + $this->hasher = $this->createMock(IHasher::class); + $this->mountManager = $this->createMock(IMountManager::class); + $this->groupManager = $this->createMock(IGroupManager::class); + $this->userManager = $this->createMock(IUserManager::class); + $this->rootFolder = $this->createMock(IRootFolder::class); + $this->mailer = $this->createMock(IMailer::class); + $this->urlGenerator = $this->createMock(IURLGenerator::class); + $this->defaults = $this->createMock(\OC_Defaults::class); + $this->dispatcher = $this->createMock(IEventDispatcher::class); + $this->userSession = $this->createMock(IUserSession::class); + $this->knownUserService = $this->createMock(KnownUserService::class); + + $this->shareDisabledChecker = new ShareDisableChecker($this->config, $this->userManager, $this->groupManager); + $this->dateTimeZone = $this->createMock(IDateTimeZone::class); + $this->timezone = new \DateTimeZone('Pacific/Auckland'); + $this->dateTimeZone->method('getTimeZone')->willReturnCallback(fn () => $this->timezone); + + $this->l10nFactory = $this->createMock(IFactory::class); + $this->l = $this->createMock(IL10N::class); + $this->l->method('t') + ->willReturnCallback(function ($text, $parameters = []) { + return vsprintf($text, $parameters); + }); + $this->l->method('n') + ->willReturnCallback(function ($singular, $plural, $count, $parameters = []) { + return vsprintf(str_replace('%n', $count, ($count === 1) ? $singular : $plural), $parameters); + }); + $this->l10nFactory->method('get')->willReturn($this->l); + + $this->factory = new DummyFactory(\OC::$server); + + $this->manager = $this->createManager($this->factory); + + $this->defaultProvider = $this->createMock(DefaultShareProvider::class); + $this->defaultProvider->method('identifier')->willReturn('default'); + $this->factory->setProvider($this->defaultProvider); + } + + private function createManager(IProviderFactory $factory): Manager { + return new Manager( + $this->logger, + $this->config, + $this->secureRandom, + $this->hasher, + $this->mountManager, + $this->groupManager, + $this->l10nFactory, + $factory, + $this->userManager, + $this->rootFolder, + $this->mailer, + $this->urlGenerator, + $this->defaults, + $this->dispatcher, + $this->userSession, + $this->knownUserService, + $this->shareDisabledChecker, + $this->dateTimeZone, + ); + } + + /** + * @return MockBuilder + */ + private function createManagerMock() { + return $this->getMockBuilder(Manager::class) + ->setConstructorArgs([ + $this->logger, + $this->config, + $this->secureRandom, + $this->hasher, + $this->mountManager, + $this->groupManager, + $this->l10nFactory, + $this->factory, + $this->userManager, + $this->rootFolder, + $this->mailer, + $this->urlGenerator, + $this->defaults, + $this->dispatcher, + $this->userSession, + $this->knownUserService, + $this->shareDisabledChecker, + $this->dateTimeZone, + ]); + } + + + public function testDeleteNoShareId(): void { + $this->expectException(\InvalidArgumentException::class); + + $share = $this->manager->newShare(); + + $this->manager->deleteShare($share); + } + + public function dataTestDelete() { + $user = $this->createMock(IUser::class); + $user->method('getUID')->willReturn('sharedWithUser'); + + $group = $this->createMock(IGroup::class); + $group->method('getGID')->willReturn('sharedWithGroup'); + + return [ + [IShare::TYPE_USER, 'sharedWithUser'], + [IShare::TYPE_GROUP, 'sharedWithGroup'], + [IShare::TYPE_LINK, ''], + [IShare::TYPE_REMOTE, 'foo@bar.com'], + ]; + } + + /** + * @dataProvider dataTestDelete + */ + public function testDelete($shareType, $sharedWith): void { + $manager = $this->createManagerMock() + ->setMethods(['getShareById', 'deleteChildren']) + ->getMock(); + + $manager->method('deleteChildren')->willReturn([]); + + $path = $this->createMock(File::class); + $path->method('getId')->willReturn(1); + + $share = $this->manager->newShare(); + $share->setId(42) + ->setProviderId('prov') + ->setShareType($shareType) + ->setSharedWith($sharedWith) + ->setSharedBy('sharedBy') + ->setNode($path) + ->setTarget('myTarget'); + + $manager->expects($this->once())->method('deleteChildren')->with($share); + + $this->defaultProvider + ->expects($this->once()) + ->method('delete') + ->with($share); + + $this->dispatcher->expects($this->exactly(2)) + ->method('dispatchTyped') + ->withConsecutive( + [ + $this->callBack(function (BeforeShareDeletedEvent $e) use ($share) { + return $e->getShare() === $share; + })], + [ + $this->callBack(function (ShareDeletedEvent $e) use ($share) { + return $e->getShare() === $share; + })] + ); + + $manager->deleteShare($share); + } + + public function testDeleteLazyShare(): void { + $manager = $this->createManagerMock() + ->setMethods(['getShareById', 'deleteChildren']) + ->getMock(); + + $manager->method('deleteChildren')->willReturn([]); + + $share = $this->manager->newShare(); + $share->setId(42) + ->setProviderId('prov') + ->setShareType(IShare::TYPE_USER) + ->setSharedWith('sharedWith') + ->setSharedBy('sharedBy') + ->setShareOwner('shareOwner') + ->setTarget('myTarget') + ->setNodeId(1) + ->setNodeType('file'); + + $this->rootFolder->expects($this->never())->method($this->anything()); + + $manager->expects($this->once())->method('deleteChildren')->with($share); + + $this->defaultProvider + ->expects($this->once()) + ->method('delete') + ->with($share); + + $this->dispatcher->expects($this->exactly(2)) + ->method('dispatchTyped') + ->withConsecutive( + [ + $this->callBack(function (BeforeShareDeletedEvent $e) use ($share) { + return $e->getShare() === $share; + })], + [ + $this->callBack(function (ShareDeletedEvent $e) use ($share) { + return $e->getShare() === $share; + })] + ); + + $manager->deleteShare($share); + } + + public function testDeleteNested(): void { + $manager = $this->createManagerMock() + ->setMethods(['getShareById']) + ->getMock(); + + $path = $this->createMock(File::class); + $path->method('getId')->willReturn(1); + + $share1 = $this->manager->newShare(); + $share1->setId(42) + ->setProviderId('prov') + ->setShareType(IShare::TYPE_USER) + ->setSharedWith('sharedWith1') + ->setSharedBy('sharedBy1') + ->setNode($path) + ->setTarget('myTarget1'); + + $share2 = $this->manager->newShare(); + $share2->setId(43) + ->setProviderId('prov') + ->setShareType(IShare::TYPE_GROUP) + ->setSharedWith('sharedWith2') + ->setSharedBy('sharedBy2') + ->setNode($path) + ->setTarget('myTarget2') + ->setParent(42); + + $share3 = $this->manager->newShare(); + $share3->setId(44) + ->setProviderId('prov') + ->setShareType(IShare::TYPE_LINK) + ->setSharedBy('sharedBy3') + ->setNode($path) + ->setTarget('myTarget3') + ->setParent(43); + + $this->defaultProvider + ->method('getChildren') + ->willReturnMap([ + [$share1, [$share2]], + [$share2, [$share3]], + [$share3, []], + ]); + + $this->defaultProvider + ->method('delete') + ->withConsecutive([$share3], [$share2], [$share1]); + + $this->dispatcher->expects($this->exactly(6)) + ->method('dispatchTyped') + ->withConsecutive( + [ + $this->callBack(function (BeforeShareDeletedEvent $e) use ($share1) { + return $e->getShare()->getId() === $share1->getId(); + }) + ], + [ + $this->callBack(function (BeforeShareDeletedEvent $e) use ($share2) { + return $e->getShare()->getId() === $share2->getId(); + }) + ], + [ + $this->callBack(function (BeforeShareDeletedEvent $e) use ($share3) { + return $e->getShare()->getId() === $share3->getId(); + }) + ], + [ + $this->callBack(function (ShareDeletedEvent $e) use ($share3) { + return $e->getShare()->getId() === $share3->getId(); + }) + ], + [ + $this->callBack(function (ShareDeletedEvent $e) use ($share2) { + return $e->getShare()->getId() === $share2->getId(); + }) + ], + [ + $this->callBack(function (ShareDeletedEvent $e) use ($share1) { + return $e->getShare()->getId() === $share1->getId(); + }) + ], + ); + + $manager->deleteShare($share1); + } + + public function testDeleteFromSelf(): void { + $manager = $this->createManagerMock() + ->setMethods(['getShareById']) + ->getMock(); + + $recipientId = 'unshareFrom'; + $share = $this->manager->newShare(); + $share->setId(42) + ->setProviderId('prov') + ->setShareType(IShare::TYPE_USER) + ->setSharedWith('sharedWith') + ->setSharedBy('sharedBy') + ->setShareOwner('shareOwner') + ->setTarget('myTarget') + ->setNodeId(1) + ->setNodeType('file'); + + $this->defaultProvider + ->expects($this->once()) + ->method('deleteFromSelf') + ->with($share, $recipientId); + + $this->dispatcher->expects($this->once()) + ->method('dispatchTyped') + ->with( + $this->callBack(function (ShareDeletedFromSelfEvent $e) use ($share) { + return $e->getShare() === $share; + }) + ); + + $manager->deleteFromSelf($share, $recipientId); + } + + public function testDeleteChildren(): void { + $manager = $this->createManagerMock() + ->setMethods(['deleteShare']) + ->getMock(); + + $share = $this->createMock(IShare::class); + $share->method('getShareType')->willReturn(IShare::TYPE_USER); + + $child1 = $this->createMock(IShare::class); + $child1->method('getShareType')->willReturn(IShare::TYPE_USER); + $child2 = $this->createMock(IShare::class); + $child2->method('getShareType')->willReturn(IShare::TYPE_USER); + $child3 = $this->createMock(IShare::class); + $child3->method('getShareType')->willReturn(IShare::TYPE_USER); + + $shares = [ + $child1, + $child2, + $child3, + ]; + + $this->defaultProvider + ->expects($this->exactly(4)) + ->method('getChildren') + ->willReturnCallback(function ($_share) use ($share, $shares) { + if ($_share === $share) { + return $shares; + } + return []; + }); + + $this->defaultProvider + ->expects($this->exactly(3)) + ->method('delete') + ->withConsecutive([$child1], [$child2], [$child3]); + + $result = self::invokePrivate($manager, 'deleteChildren', [$share]); + $this->assertSame($shares, $result); + } + + public function testGetShareById(): void { + $share = $this->createMock(IShare::class); + + $this->defaultProvider + ->expects($this->once()) + ->method('getShareById') + ->with(42) + ->willReturn($share); + + $this->assertEquals($share, $this->manager->getShareById('default:42')); + } + + + public function testGetExpiredShareById(): void { + $this->expectException(\OCP\Share\Exceptions\ShareNotFound::class); + + $manager = $this->createManagerMock() + ->setMethods(['deleteShare']) + ->getMock(); + + $date = new \DateTime(); + $date->setTime(0, 0, 0); + + $share = $this->manager->newShare(); + $share->setExpirationDate($date) + ->setShareType(IShare::TYPE_LINK); + + $this->defaultProvider->expects($this->once()) + ->method('getShareById') + ->with('42') + ->willReturn($share); + + $manager->expects($this->once()) + ->method('deleteShare') + ->with($share); + + $manager->getShareById('default:42'); + } + + + public function testVerifyPasswordNullButEnforced(): void { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Passwords are enforced for link and mail shares'); + + $this->config->method('getAppValue')->willReturnMap([ + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], + ['core', 'shareapi_enforce_links_password', 'no', 'yes'], + ]); + + self::invokePrivate($this->manager, 'verifyPassword', [null]); + } + + public function testVerifyPasswordNotEnforcedGroup(): void { + $this->config->method('getAppValue')->willReturnMap([ + ['core', 'shareapi_enforce_links_password_excluded_groups', '', '["admin"]'], + ['core', 'shareapi_enforce_links_password', 'no', 'yes'], + ]); + + // Create admin user + $user = $this->createMock(IUser::class); + $this->userSession->method('getUser')->willReturn($user); + $this->groupManager->method('getUserGroupIds')->with($user)->willReturn(['admin']); + + $result = self::invokePrivate($this->manager, 'verifyPassword', [null]); + $this->assertNull($result); + } + + public function testVerifyPasswordNotEnforcedMultipleGroups(): void { + $this->config->method('getAppValue')->willReturnMap([ + ['core', 'shareapi_enforce_links_password_excluded_groups', '', '["admin", "special"]'], + ['core', 'shareapi_enforce_links_password', 'no', 'yes'], + ]); + + // Create admin user + $user = $this->createMock(IUser::class); + $this->userSession->method('getUser')->willReturn($user); + $this->groupManager->method('getUserGroupIds')->with($user)->willReturn(['special']); + + $result = self::invokePrivate($this->manager, 'verifyPassword', [null]); + $this->assertNull($result); + } + + public function testVerifyPasswordNull(): void { + $this->config->method('getAppValue')->willReturnMap([ + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], + ['core', 'shareapi_enforce_links_password', 'no', 'no'], + ]); + + $result = self::invokePrivate($this->manager, 'verifyPassword', [null]); + $this->assertNull($result); + } + + public function testVerifyPasswordHook(): void { + $this->config->method('getAppValue')->willReturnMap([ + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], + ['core', 'shareapi_enforce_links_password', 'no', 'no'], + ]); + + $this->dispatcher->expects($this->once())->method('dispatchTyped') + ->willReturnCallback(function (Event $event) { + $this->assertInstanceOf(ValidatePasswordPolicyEvent::class, $event); + /** @var ValidatePasswordPolicyEvent $event */ + $this->assertSame('password', $event->getPassword()); + } + ); + + $result = self::invokePrivate($this->manager, 'verifyPassword', ['password']); + $this->assertNull($result); + } + + + public function testVerifyPasswordHookFails(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('password not accepted'); + + $this->config->method('getAppValue')->willReturnMap([ + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], + ['core', 'shareapi_enforce_links_password', 'no', 'no'], + ]); + + $this->dispatcher->expects($this->once())->method('dispatchTyped') + ->willReturnCallback(function (Event $event) { + $this->assertInstanceOf(ValidatePasswordPolicyEvent::class, $event); + /** @var ValidatePasswordPolicyEvent $event */ + $this->assertSame('password', $event->getPassword()); + throw new HintException('message', 'password not accepted'); + } + ); + + self::invokePrivate($this->manager, 'verifyPassword', ['password']); + } + + public function createShare($id, $type, $node, $sharedWith, $sharedBy, $shareOwner, + $permissions, $expireDate = null, $password = null, $attributes = null) { + $share = $this->createMock(IShare::class); + + $share->method('getShareType')->willReturn($type); + $share->method('getSharedWith')->willReturn($sharedWith); + $share->method('getSharedBy')->willReturn($sharedBy); + $share->method('getShareOwner')->willReturn($shareOwner); + $share->method('getNode')->willReturn($node); + if ($node && $node->getId()) { + $share->method('getNodeId')->willReturn($node->getId()); + } + $share->method('getPermissions')->willReturn($permissions); + $share->method('getAttributes')->willReturn($attributes); + $share->method('getExpirationDate')->willReturn($expireDate); + $share->method('getPassword')->willReturn($password); + + return $share; + } + + public function dataGeneralChecks() { + $user0 = 'user0'; + $user2 = 'user1'; + $group0 = 'group0'; + $owner = $this->createMock(IUser::class); + $owner->method('getUID') + ->willReturn($user0); + + $file = $this->createMock(File::class); + $node = $this->createMock(Node::class); + $storage = $this->createMock(Storage\IStorage::class); + $storage->method('instanceOfStorage') + ->with(\OCA\Files_Sharing\External\Storage::class) + ->willReturn(false); + $file->method('getStorage') + ->willReturn($storage); + $file->method('getId')->willReturn(108); + $node->method('getStorage') + ->willReturn($storage); + $node->method('getId')->willReturn(108); + + $data = [ + [$this->createShare(null, IShare::TYPE_USER, $file, null, $user0, $user0, 31, null, null), 'SharedWith is not a valid user', true], + [$this->createShare(null, IShare::TYPE_USER, $file, $group0, $user0, $user0, 31, null, null), 'SharedWith is not a valid user', true], + [$this->createShare(null, IShare::TYPE_USER, $file, 'foo@bar.com', $user0, $user0, 31, null, null), 'SharedWith is not a valid user', true], + [$this->createShare(null, IShare::TYPE_GROUP, $file, null, $user0, $user0, 31, null, null), 'SharedWith is not a valid group', true], + [$this->createShare(null, IShare::TYPE_GROUP, $file, $user2, $user0, $user0, 31, null, null), 'SharedWith is not a valid group', true], + [$this->createShare(null, IShare::TYPE_GROUP, $file, 'foo@bar.com', $user0, $user0, 31, null, null), 'SharedWith is not a valid group', true], + [$this->createShare(null, IShare::TYPE_LINK, $file, $user2, $user0, $user0, 31, null, null), 'SharedWith should be empty', true], + [$this->createShare(null, IShare::TYPE_LINK, $file, $group0, $user0, $user0, 31, null, null), 'SharedWith should be empty', true], + [$this->createShare(null, IShare::TYPE_LINK, $file, 'foo@bar.com', $user0, $user0, 31, null, null), 'SharedWith should be empty', true], + [$this->createShare(null, -1, $file, null, $user0, $user0, 31, null, null), 'Unknown share type', true], + + [$this->createShare(null, IShare::TYPE_USER, $file, $user2, null, $user0, 31, null, null), 'SharedBy should be set', true], + [$this->createShare(null, IShare::TYPE_GROUP, $file, $group0, null, $user0, 31, null, null), 'SharedBy should be set', true], + [$this->createShare(null, IShare::TYPE_LINK, $file, null, null, $user0, 31, null, null), 'SharedBy should be set', true], + + [$this->createShare(null, IShare::TYPE_USER, $file, $user0, $user0, $user0, 31, null, null), 'Cannot share with yourself', true], + + [$this->createShare(null, IShare::TYPE_USER, null, $user2, $user0, $user0, 31, null, null), 'Path should be set', true], + [$this->createShare(null, IShare::TYPE_GROUP, null, $group0, $user0, $user0, 31, null, null), 'Path should be set', true], + [$this->createShare(null, IShare::TYPE_LINK, null, null, $user0, $user0, 31, null, null), 'Path should be set', true], + + [$this->createShare(null, IShare::TYPE_USER, $node, $user2, $user0, $user0, 31, null, null), 'Path should be either a file or a folder', true], + [$this->createShare(null, IShare::TYPE_GROUP, $node, $group0, $user0, $user0, 31, null, null), 'Path should be either a file or a folder', true], + [$this->createShare(null, IShare::TYPE_LINK, $node, null, $user0, $user0, 31, null, null), 'Path should be either a file or a folder', true], + ]; + + $nonShareAble = $this->createMock(Folder::class); + $nonShareAble->method('getId')->willReturn(108); + $nonShareAble->method('isShareable')->willReturn(false); + $nonShareAble->method('getPath')->willReturn('path'); + $nonShareAble->method('getName')->willReturn('name'); + $nonShareAble->method('getOwner') + ->willReturn($owner); + $nonShareAble->method('getStorage') + ->willReturn($storage); + + $data[] = [$this->createShare(null, IShare::TYPE_USER, $nonShareAble, $user2, $user0, $user0, 31, null, null), 'You are not allowed to share name', true]; + $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $nonShareAble, $group0, $user0, $user0, 31, null, null), 'You are not allowed to share name', true]; + $data[] = [$this->createShare(null, IShare::TYPE_LINK, $nonShareAble, null, $user0, $user0, 31, null, null), 'You are not allowed to share name', true]; + + $limitedPermssions = $this->createMock(File::class); + $limitedPermssions->method('isShareable')->willReturn(true); + $limitedPermssions->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_READ); + $limitedPermssions->method('getId')->willReturn(108); + $limitedPermssions->method('getPath')->willReturn('path'); + $limitedPermssions->method('getName')->willReturn('name'); + $limitedPermssions->method('getOwner') + ->willReturn($owner); + $limitedPermssions->method('getStorage') + ->willReturn($storage); + + $data[] = [$this->createShare(null, IShare::TYPE_USER, $limitedPermssions, $user2, $user0, $user0, null, null, null), 'A share requires permissions', true]; + $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $limitedPermssions, $group0, $user0, $user0, null, null, null), 'A share requires permissions', true]; + $data[] = [$this->createShare(null, IShare::TYPE_LINK, $limitedPermssions, null, $user0, $user0, null, null, null), 'A share requires permissions', true]; + + $mount = $this->createMock(MoveableMount::class); + $limitedPermssions->method('getMountPoint')->willReturn($mount); + + + $data[] = [$this->createShare(null, IShare::TYPE_USER, $limitedPermssions, $user2, $user0, $user0, 31, null, null), 'Cannot increase permissions of path', true]; + $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $limitedPermssions, $group0, $user0, $user0, 17, null, null), 'Cannot increase permissions of path', true]; + $data[] = [$this->createShare(null, IShare::TYPE_LINK, $limitedPermssions, null, $user0, $user0, 3, null, null), 'Cannot increase permissions of path', true]; + + $nonMovableStorage = $this->createMock(Storage\IStorage::class); + $nonMovableStorage->method('instanceOfStorage') + ->with(\OCA\Files_Sharing\External\Storage::class) + ->willReturn(false); + $nonMovableStorage->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_ALL); + $nonMoveableMountPermssions = $this->createMock(Folder::class); + $nonMoveableMountPermssions->method('isShareable')->willReturn(true); + $nonMoveableMountPermssions->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_READ); + $nonMoveableMountPermssions->method('getId')->willReturn(108); + $nonMoveableMountPermssions->method('getPath')->willReturn('path'); + $nonMoveableMountPermssions->method('getName')->willReturn('name'); + $nonMoveableMountPermssions->method('getInternalPath')->willReturn(''); + $nonMoveableMountPermssions->method('getOwner') + ->willReturn($owner); + $nonMoveableMountPermssions->method('getStorage') + ->willReturn($nonMovableStorage); + + $data[] = [$this->createShare(null, IShare::TYPE_USER, $nonMoveableMountPermssions, $user2, $user0, $user0, 11, null, null), 'Cannot increase permissions of path', false]; + $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $nonMoveableMountPermssions, $group0, $user0, $user0, 11, null, null), 'Cannot increase permissions of path', false]; + + $rootFolder = $this->createMock(Folder::class); + $rootFolder->method('isShareable')->willReturn(true); + $rootFolder->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_ALL); + $rootFolder->method('getId')->willReturn(42); + + $data[] = [$this->createShare(null, IShare::TYPE_USER, $rootFolder, $user2, $user0, $user0, 30, null, null), 'You cannot share your root folder', true]; + $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $rootFolder, $group0, $user0, $user0, 2, null, null), 'You cannot share your root folder', true]; + $data[] = [$this->createShare(null, IShare::TYPE_LINK, $rootFolder, null, $user0, $user0, 16, null, null), 'You cannot share your root folder', true]; + + $allPermssions = $this->createMock(Folder::class); + $allPermssions->method('isShareable')->willReturn(true); + $allPermssions->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_ALL); + $allPermssions->method('getId')->willReturn(108); + $allPermssions->method('getOwner') + ->willReturn($owner); + $allPermssions->method('getStorage') + ->willReturn($storage); + + $data[] = [$this->createShare(null, IShare::TYPE_USER, $allPermssions, $user2, $user0, $user0, 30, null, null), 'Shares need at least read permissions', true]; + $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $allPermssions, $group0, $user0, $user0, 2, null, null), 'Shares need at least read permissions', true]; + + $data[] = [$this->createShare(null, IShare::TYPE_USER, $allPermssions, $user2, $user0, $user0, 31, null, null), null, false]; + $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $allPermssions, $group0, $user0, $user0, 3, null, null), null, false]; + $data[] = [$this->createShare(null, IShare::TYPE_LINK, $allPermssions, null, $user0, $user0, 17, null, null), null, false]; + + + $remoteStorage = $this->createMock(Storage\IStorage::class); + $remoteStorage->method('instanceOfStorage') + ->with(\OCA\Files_Sharing\External\Storage::class) + ->willReturn(true); + $remoteFile = $this->createMock(Folder::class); + $remoteFile->method('isShareable')->willReturn(true); + $remoteFile->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_READ ^ \OCP\Constants::PERMISSION_UPDATE); + $remoteFile->method('getId')->willReturn(108); + $remoteFile->method('getOwner') + ->willReturn($owner); + $remoteFile->method('getStorage') + ->willReturn($storage); + $data[] = [$this->createShare(null, IShare::TYPE_REMOTE, $remoteFile, $user2, $user0, $user0, 1, null, null), null, false]; + $data[] = [$this->createShare(null, IShare::TYPE_REMOTE, $remoteFile, $user2, $user0, $user0, 3, null, null), null, false]; + $data[] = [$this->createShare(null, IShare::TYPE_REMOTE, $remoteFile, $user2, $user0, $user0, 31, null, null), 'Cannot increase permissions of ', true]; + + return $data; + } + + /** + * @dataProvider dataGeneralChecks + * + * @param $share + * @param $exceptionMessage + * @param $exception + */ + public function testGeneralChecks($share, $exceptionMessage, $exception): void { + $thrown = null; + + $this->userManager->method('userExists')->willReturnMap([ + ['user0', true], + ['user1', true], + ]); + + $this->groupManager->method('groupExists')->willReturnMap([ + ['group0', true], + ]); + + $userFolder = $this->createMock(Folder::class); + $userFolder->expects($this->any()) + ->method('getId') + ->willReturn(42); + // Id 108 is used in the data to refer to the node of the share. + $userFolder->method('getById') + ->with(108) + ->willReturn([$share->getNode()]); + $userFolder->expects($this->any()) + ->method('getRelativePath') + ->willReturnArgument(0); + $this->rootFolder->method('getUserFolder')->willReturn($userFolder); + + + try { + self::invokePrivate($this->manager, 'generalCreateChecks', [$share]); + $thrown = false; + } catch (\OCP\Share\Exceptions\GenericShareException $e) { + $this->assertEquals($exceptionMessage, $e->getHint()); + $thrown = true; + } catch (\InvalidArgumentException $e) { + $this->assertEquals($exceptionMessage, $e->getMessage()); + $thrown = true; + } + + $this->assertSame($exception, $thrown); + } + + + public function testGeneralCheckShareRoot(): void { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('You cannot share your root folder'); + + $thrown = null; + + $this->userManager->method('userExists')->willReturnMap([ + ['user0', true], + ['user1', true], + ]); + + $userFolder = $this->createMock(Folder::class); + $userFolder->method('isSubNode')->with($userFolder)->willReturn(false); + $this->rootFolder->method('getUserFolder')->willReturn($userFolder); + + $share = $this->manager->newShare(); + + $share->setShareType(IShare::TYPE_USER) + ->setSharedWith('user0') + ->setSharedBy('user1') + ->setNode($userFolder); + + self::invokePrivate($this->manager, 'generalCreateChecks', [$share]); + } + + public function validateExpirationDateInternalProvider() { + return [[IShare::TYPE_USER], [IShare::TYPE_REMOTE], [IShare::TYPE_REMOTE_GROUP]]; + } + + /** + * @dataProvider validateExpirationDateInternalProvider + */ + public function testValidateExpirationDateInternalInPast($shareType): void { + $this->expectException(\OCP\Share\Exceptions\GenericShareException::class); + $this->expectExceptionMessage('Expiration date is in the past'); + + // Expire date in the past + $past = new \DateTime(); + $past->sub(new \DateInterval('P1D')); + + $share = $this->manager->newShare(); + $share->setShareType($shareType); + $share->setExpirationDate($past); + + self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); + } + + /** + * @dataProvider validateExpirationDateInternalProvider + */ + public function testValidateExpirationDateInternalEnforceButNotSet($shareType): void { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Expiration date is enforced'); + + $share = $this->manager->newShare(); + $share->setProviderId('foo')->setId('bar'); + $share->setShareType($shareType); + if ($shareType === IShare::TYPE_USER) { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'], + ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'], + ]); + } else { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'], + ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'], + ]); + } + + self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); + } + + /** + * @dataProvider validateExpirationDateInternalProvider + */ + public function testValidateExpirationDateInternalEnforceButNotEnabledAndNotSet($shareType): void { + $share = $this->manager->newShare(); + $share->setProviderId('foo')->setId('bar'); + $share->setShareType($shareType); + + if ($shareType === IShare::TYPE_USER) { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'], + ]); + } else { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'], + ]); + } + + self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); + + $this->assertNull($share->getExpirationDate()); + } + + /** + * @dataProvider validateExpirationDateInternalProvider + */ + public function testValidateExpirationDateInternalEnforceButNotSetNewShare($shareType): void { + $share = $this->manager->newShare(); + $share->setShareType($shareType); + + if ($shareType === IShare::TYPE_USER) { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'], + ['core', 'shareapi_internal_expire_after_n_days', '7', '3'], + ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'], + ['core', 'internal_defaultExpDays', '3', '3'], + ]); + } else { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'], + ['core', 'shareapi_remote_expire_after_n_days', '7', '3'], + ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'], + ['core', 'remote_defaultExpDays', '3', '3'], + ]); + } + + $expected = new \DateTime('now', $this->timezone); + $expected->setTime(0, 0, 0); + $expected->add(new \DateInterval('P3D')); + + self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); + + $this->assertNotNull($share->getExpirationDate()); + $this->assertEquals($expected, $share->getExpirationDate()); + } + + /** + * @dataProvider validateExpirationDateInternalProvider + */ + public function testValidateExpirationDateInternalEnforceRelaxedDefaultButNotSetNewShare($shareType): void { + $share = $this->manager->newShare(); + $share->setShareType($shareType); + + if ($shareType === IShare::TYPE_USER) { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'], + ['core', 'shareapi_internal_expire_after_n_days', '7', '3'], + ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'], + ['core', 'internal_defaultExpDays', '3', '1'], + ]); + } else { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'], + ['core', 'shareapi_remote_expire_after_n_days', '7', '3'], + ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'], + ['core', 'remote_defaultExpDays', '3', '1'], + ]); + } + + $expected = new \DateTime('now', $this->timezone); + $expected->setTime(0, 0, 0); + $expected->add(new \DateInterval('P1D')); + + self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); + + $this->assertNotNull($share->getExpirationDate()); + $this->assertEquals($expected, $share->getExpirationDate()); + } + + /** + * @dataProvider validateExpirationDateInternalProvider + */ + public function testValidateExpirationDateInternalEnforceTooFarIntoFuture($shareType): void { + $this->expectException(\OCP\Share\Exceptions\GenericShareException::class); + $this->expectExceptionMessage('Cannot set expiration date more than 3 days in the future'); + + $future = new \DateTime(); + $future->add(new \DateInterval('P7D')); + + $share = $this->manager->newShare(); + $share->setShareType($shareType); + $share->setExpirationDate($future); + + if ($shareType === IShare::TYPE_USER) { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'], + ['core', 'shareapi_internal_expire_after_n_days', '7', '3'], + ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'], + ]); + } else { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'], + ['core', 'shareapi_remote_expire_after_n_days', '7', '3'], + ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'], + ]); + } + + self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); + } + + /** + * @dataProvider validateExpirationDateInternalProvider + */ + public function testValidateExpirationDateInternalEnforceValid($shareType): void { + $future = new \DateTime('now', $this->dateTimeZone->getTimeZone()); + $future->add(new \DateInterval('P2D')); + $future->setTime(1, 2, 3); + + $expected = clone $future; + $expected->setTime(0, 0, 0); + + $share = $this->manager->newShare(); + $share->setShareType($shareType); + $share->setExpirationDate($future); + + if ($shareType === IShare::TYPE_USER) { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'], + ['core', 'shareapi_internal_expire_after_n_days', '7', '3'], + ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'], + ]); + } else { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'], + ['core', 'shareapi_remote_expire_after_n_days', '7', '3'], + ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'], + ]); + } + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); + \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); + $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($future) { + return $data['expirationDate'] == $future; + })); + + self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); + + $this->assertEquals($expected, $share->getExpirationDate()); + } + + /** + * @dataProvider validateExpirationDateInternalProvider + */ + public function testValidateExpirationDateInternalNoDefault($shareType): void { + $date = new \DateTime('now', $this->dateTimeZone->getTimeZone()); + $date->add(new \DateInterval('P5D')); + $date->setTime(1, 2, 3); + + $expected = clone $date; + $expected->setTime(0, 0, 0); + + $share = $this->manager->newShare(); + $share->setShareType($shareType); + $share->setExpirationDate($date); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); + \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); + $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) { + return $data['expirationDate'] == $expected && $data['passwordSet'] === false; + })); + + self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); + + $this->assertEquals($expected, $share->getExpirationDate()); + } + + /** + * @dataProvider validateExpirationDateInternalProvider + */ + public function testValidateExpirationDateInternalNoDateNoDefault($shareType): void { + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); + \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); + $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) { + return $data['expirationDate'] === null && $data['passwordSet'] === true; + })); + + $share = $this->manager->newShare(); + $share->setShareType($shareType); + $share->setPassword('password'); + + self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); + + $this->assertNull($share->getExpirationDate()); + } + + /** + * @dataProvider validateExpirationDateInternalProvider + */ + public function testValidateExpirationDateInternalNoDateDefault($shareType): void { + $share = $this->manager->newShare(); + $share->setShareType($shareType); + + $expected = new \DateTime('now', $this->timezone); + $expected->setTime(0, 0); + $expected->add(new \DateInterval('P3D')); + $expected->setTimezone(new \DateTimeZone(date_default_timezone_get())); + + if ($shareType === IShare::TYPE_USER) { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'], + ['core', 'shareapi_internal_expire_after_n_days', '7', '3'], + ['core', 'internal_defaultExpDays', '3', '3'], + ]); + } else { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'], + ['core', 'shareapi_remote_expire_after_n_days', '7', '3'], + ['core', 'remote_defaultExpDays', '3', '3'], + ]); + } + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); + \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); + $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) { + return $data['expirationDate'] == $expected; + })); + + self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); + + $this->assertEquals($expected, $share->getExpirationDate()); + } + + /** + * @dataProvider validateExpirationDateInternalProvider + */ + public function testValidateExpirationDateInternalDefault($shareType): void { + $future = new \DateTime('now', $this->timezone); + $future->add(new \DateInterval('P5D')); + $future->setTime(1, 2, 3); + + $expected = clone $future; + $expected->setTime(0, 0); + + $share = $this->manager->newShare(); + $share->setShareType($shareType); + $share->setExpirationDate($future); + + if ($shareType === IShare::TYPE_USER) { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'], + ['core', 'shareapi_internal_expire_after_n_days', '7', '3'], + ['core', 'internal_defaultExpDays', '3', '1'], + ]); + } else { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'], + ['core', 'shareapi_remote_expire_after_n_days', '7', '3'], + ['core', 'remote_defaultExpDays', '3', '1'], + ]); + } + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); + \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); + $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) { + return $data['expirationDate'] == $expected; + })); + + self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); + + $this->assertEquals($expected, $share->getExpirationDate()); + } + + /** + * @dataProvider validateExpirationDateInternalProvider + */ + public function testValidateExpirationDateInternalHookModification($shareType): void { + $nextWeek = new \DateTime('now', $this->timezone); + $nextWeek->add(new \DateInterval('P7D')); + $nextWeek->setTime(0, 0, 0); + + $save = clone $nextWeek; + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); + \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); + $hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) { + $data['expirationDate']->sub(new \DateInterval('P2D')); + }); + + $share = $this->manager->newShare(); + $share->setShareType($shareType); + $share->setExpirationDate($nextWeek); + + self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); + + $save->sub(new \DateInterval('P2D')); + $this->assertEquals($save, $share->getExpirationDate()); + } + + /** + * @dataProvider validateExpirationDateInternalProvider + */ + public function testValidateExpirationDateInternalHookException($shareType): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Invalid date!'); + + $nextWeek = new \DateTime(); + $nextWeek->add(new \DateInterval('P7D')); + $nextWeek->setTime(0, 0, 0); + + $share = $this->manager->newShare(); + $share->setShareType($shareType); + $share->setExpirationDate($nextWeek); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); + \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); + $hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) { + $data['accepted'] = false; + $data['message'] = 'Invalid date!'; + }); + + self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); + } + + /** + * @dataProvider validateExpirationDateInternalProvider + */ + public function testValidateExpirationDateInternalExistingShareNoDefault($shareType): void { + $share = $this->manager->newShare(); + $share->setShareType($shareType); + $share->setId('42')->setProviderId('foo'); + + if ($shareType === IShare::TYPE_USER) { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'], + ['core', 'shareapi_internal_expire_after_n_days', '7', '6'], + ]); + } else { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'], + ['core', 'shareapi_remote_expire_after_n_days', '7', '6'], + ]); + } + + self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]); + + $this->assertEquals(null, $share->getExpirationDate()); + } + + public function testValidateExpirationDateInPast(): void { + $this->expectException(\OCP\Share\Exceptions\GenericShareException::class); + $this->expectExceptionMessage('Expiration date is in the past'); + + // Expire date in the past + $past = new \DateTime(); + $past->sub(new \DateInterval('P1D')); + + $share = $this->manager->newShare(); + $share->setExpirationDate($past); + + self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); + } + + public function testValidateExpirationDateEnforceButNotSet(): void { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Expiration date is enforced'); + + $share = $this->manager->newShare(); + $share->setProviderId('foo')->setId('bar'); + + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_default_expire_date', 'no', 'yes'], + ['core', 'shareapi_enforce_expire_date', 'no', 'yes'], + ]); + + self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); + } + + public function testValidateExpirationDateEnforceButNotEnabledAndNotSet(): void { + $share = $this->manager->newShare(); + $share->setProviderId('foo')->setId('bar'); + + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_enforce_expire_date', 'no', 'yes'], + ]); + + self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); + + $this->assertNull($share->getExpirationDate()); + } + + public function testValidateExpirationDateEnforceButNotSetNewShare(): void { + $share = $this->manager->newShare(); + + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_enforce_expire_date', 'no', 'yes'], + ['core', 'shareapi_expire_after_n_days', '7', '3'], + ['core', 'shareapi_default_expire_date', 'no', 'yes'], + ['core', 'link_defaultExpDays', '3', '3'], + ]); + + $expected = new \DateTime('now', $this->timezone); + $expected->setTime(0, 0, 0); + $expected->add(new \DateInterval('P3D')); + + self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); + + $this->assertNotNull($share->getExpirationDate()); + $this->assertEquals($expected, $share->getExpirationDate()); + } + + public function testValidateExpirationDateEnforceRelaxedDefaultButNotSetNewShare(): void { + $share = $this->manager->newShare(); + + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_enforce_expire_date', 'no', 'yes'], + ['core', 'shareapi_expire_after_n_days', '7', '3'], + ['core', 'shareapi_default_expire_date', 'no', 'yes'], + ['core', 'link_defaultExpDays', '3', '1'], + ]); + + $expected = new \DateTime('now', $this->timezone); + $expected->setTime(0, 0, 0); + $expected->add(new \DateInterval('P1D')); + + self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); + + $this->assertNotNull($share->getExpirationDate()); + $this->assertEquals($expected, $share->getExpirationDate()); + } + + public function testValidateExpirationDateEnforceTooFarIntoFuture(): void { + $this->expectException(\OCP\Share\Exceptions\GenericShareException::class); + $this->expectExceptionMessage('Cannot set expiration date more than 3 days in the future'); + + $future = new \DateTime(); + $future->add(new \DateInterval('P7D')); + + $share = $this->manager->newShare(); + $share->setExpirationDate($future); + + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_enforce_expire_date', 'no', 'yes'], + ['core', 'shareapi_expire_after_n_days', '7', '3'], + ['core', 'shareapi_default_expire_date', 'no', 'yes'], + ]); + + self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); + } + + public function testValidateExpirationDateEnforceValid(): void { + $future = new \DateTime('now', $this->timezone); + $future->add(new \DateInterval('P2D')); + $future->setTime(1, 2, 3); + + $expected = clone $future; + $expected->setTime(0, 0, 0); + + $share = $this->manager->newShare(); + $share->setExpirationDate($future); + + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_enforce_expire_date', 'no', 'yes'], + ['core', 'shareapi_expire_after_n_days', '7', '3'], + ['core', 'shareapi_default_expire_date', 'no', 'yes'], + ]); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); + \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); + $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($future) { + return $data['expirationDate'] == $future; + })); + + self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); + + $this->assertEquals($expected, $share->getExpirationDate()); + } + + public function testValidateExpirationDateNoDefault(): void { + $date = new \DateTime('now', $this->timezone); + $date->add(new \DateInterval('P5D')); + $date->setTime(1, 2, 3); + + $expected = clone $date; + $expected->setTime(0, 0); + $expected->setTimezone(new \DateTimeZone(date_default_timezone_get())); + + $share = $this->manager->newShare(); + $share->setExpirationDate($date); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); + \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); + $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) { + return $data['expirationDate'] == $expected && $data['passwordSet'] === false; + })); + + self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); + + $this->assertEquals($expected, $share->getExpirationDate()); + } + + public function testValidateExpirationDateNoDateNoDefault(): void { + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); + \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); + $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) { + return $data['expirationDate'] === null && $data['passwordSet'] === true; + })); + + $share = $this->manager->newShare(); + $share->setPassword('password'); + + self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); + + $this->assertNull($share->getExpirationDate()); + } + + public function testValidateExpirationDateNoDateDefault(): void { + $share = $this->manager->newShare(); + + $expected = new \DateTime('now', $this->timezone); + $expected->add(new \DateInterval('P3D')); + $expected->setTime(0, 0); + $expected->setTimezone(new \DateTimeZone(date_default_timezone_get())); + + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_default_expire_date', 'no', 'yes'], + ['core', 'shareapi_expire_after_n_days', '7', '3'], + ['core', 'link_defaultExpDays', '3', '3'], + ]); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); + \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); + $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) { + return $data['expirationDate'] == $expected; + })); + + self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); + + $this->assertEquals($expected, $share->getExpirationDate()); + } + + public function testValidateExpirationDateDefault(): void { + $future = new \DateTime('now', $this->timezone); + $future->add(new \DateInterval('P5D')); + $future->setTime(1, 2, 3); + + $expected = clone $future; + $expected->setTime(0, 0); + $expected->setTimezone(new \DateTimeZone(date_default_timezone_get())); + + $share = $this->manager->newShare(); + $share->setExpirationDate($future); + + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_default_expire_date', 'no', 'yes'], + ['core', 'shareapi_expire_after_n_days', '7', '3'], + ['core', 'link_defaultExpDays', '3', '1'], + ]); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); + \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); + $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) { + return $data['expirationDate'] == $expected; + })); + + self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); + + $this->assertEquals($expected, $share->getExpirationDate()); + } + + public function testValidateExpirationNegativeOffsetTimezone(): void { + $this->timezone = new \DateTimeZone('Pacific/Tahiti'); + $future = new \DateTime(); + $future->add(new \DateInterval('P5D')); + + $expected = clone $future; + $expected->setTimezone($this->timezone); + $expected->setTime(0, 0); + $expected->setTimezone(new \DateTimeZone(date_default_timezone_get())); + + $share = $this->manager->newShare(); + $share->setExpirationDate($future); + + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_default_expire_date', 'no', 'yes'], + ['core', 'shareapi_expire_after_n_days', '7', '3'], + ['core', 'link_defaultExpDays', '3', '1'], + ]); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); + \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); + $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) { + return $data['expirationDate'] == $expected; + })); + + self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); + + $this->assertEquals($expected, $share->getExpirationDate()); + } + + public function testValidateExpirationDateHookModification(): void { + $nextWeek = new \DateTime('now', $this->timezone); + $nextWeek->add(new \DateInterval('P7D')); + + $save = clone $nextWeek; + $save->setTime(0, 0); + $save->sub(new \DateInterval('P2D')); + $save->setTimezone(new \DateTimeZone(date_default_timezone_get())); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); + \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); + $hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) { + $data['expirationDate']->sub(new \DateInterval('P2D')); + }); + + $share = $this->manager->newShare(); + $share->setExpirationDate($nextWeek); + + self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); + + $this->assertEquals($save, $share->getExpirationDate()); + } + + public function testValidateExpirationDateHookException(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Invalid date!'); + + $nextWeek = new \DateTime(); + $nextWeek->add(new \DateInterval('P7D')); + $nextWeek->setTime(0, 0, 0); + + $share = $this->manager->newShare(); + $share->setExpirationDate($nextWeek); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['listener'])->getMock(); + \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener'); + $hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) { + $data['accepted'] = false; + $data['message'] = 'Invalid date!'; + }); + + self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); + } + + public function testValidateExpirationDateExistingShareNoDefault(): void { + $share = $this->manager->newShare(); + + $share->setId('42')->setProviderId('foo'); + + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_default_expire_date', 'no', 'yes'], + ['core', 'shareapi_expire_after_n_days', '7', '6'], + ]); + + self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]); + + $this->assertEquals(null, $share->getExpirationDate()); + } + + public function testUserCreateChecksShareWithGroupMembersOnlyDifferentGroups(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Sharing is only allowed with group members'); + + $share = $this->manager->newShare(); + + $sharedBy = $this->createMock(IUser::class); + $sharedWith = $this->createMock(IUser::class); + $share->setSharedBy('sharedBy')->setSharedWith('sharedWith'); + + $this->groupManager + ->method('getUserGroupIds') + ->willReturnMap( + [ + [$sharedBy, ['group1']], + [$sharedWith, ['group2']], + ] + ); + + $this->userManager->method('get')->willReturnMap([ + ['sharedBy', $sharedBy], + ['sharedWith', $sharedWith], + ]); + + $this->config + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'], + ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'], + ]); + + self::invokePrivate($this->manager, 'userCreateChecks', [$share]); + } + + public function testUserCreateChecksShareWithGroupMembersOnlySharedGroup(): void { + $share = $this->manager->newShare(); + + $sharedBy = $this->createMock(IUser::class); + $sharedWith = $this->createMock(IUser::class); + $share->setSharedBy('sharedBy')->setSharedWith('sharedWith'); + + $path = $this->createMock(Node::class); + $share->setNode($path); + + $this->groupManager + ->method('getUserGroupIds') + ->willReturnMap( + [ + [$sharedBy, ['group1', 'group3']], + [$sharedWith, ['group2', 'group3']], + ] + ); + + $this->userManager->method('get')->willReturnMap([ + ['sharedBy', $sharedBy], + ['sharedWith', $sharedWith], + ]); + + $this->config + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'], + ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'], + ]); + + $this->defaultProvider + ->method('getSharesByPath') + ->with($path) + ->willReturn([]); + + self::invokePrivate($this->manager, 'userCreateChecks', [$share]); + $this->addToAssertionCount(1); + } + + + public function testUserCreateChecksIdenticalShareExists(): void { + $this->expectException(AlreadySharedException::class); + $this->expectExceptionMessage('Sharing name.txt failed, because this item is already shared with the account user'); + + $share = $this->manager->newShare(); + $share->setSharedWithDisplayName('user'); + $share2 = $this->manager->newShare(); + + $sharedWith = $this->createMock(IUser::class); + $path = $this->createMock(Node::class); + + $share->setSharedWith('sharedWith')->setNode($path) + ->setProviderId('foo')->setId('bar'); + + $share2->setSharedWith('sharedWith')->setNode($path) + ->setProviderId('foo')->setId('baz'); + + $this->defaultProvider + ->method('getSharesByPath') + ->with($path) + ->willReturn([$share2]); + + $path->method('getName') + ->willReturn('name.txt'); + + self::invokePrivate($this->manager, 'userCreateChecks', [$share]); + } + + + public function testUserCreateChecksIdenticalPathSharedViaGroup(): void { + $this->expectException(AlreadySharedException::class); + $this->expectExceptionMessage('Sharing name2.txt failed, because this item is already shared with the account userName'); + + $share = $this->manager->newShare(); + + $sharedWith = $this->createMock(IUser::class); + $sharedWith->method('getUID')->willReturn('sharedWith'); + + $this->userManager->method('get')->with('sharedWith')->willReturn($sharedWith); + + $path = $this->createMock(Node::class); + + $share->setSharedWith('sharedWith') + ->setNode($path) + ->setShareOwner('shareOwner') + ->setSharedWithDisplayName('userName') + ->setProviderId('foo') + ->setId('bar'); + + $share2 = $this->manager->newShare(); + $share2->setShareType(IShare::TYPE_GROUP) + ->setShareOwner('shareOwner2') + ->setProviderId('foo') + ->setId('baz') + ->setSharedWith('group'); + + $group = $this->createMock(IGroup::class); + $group->method('inGroup') + ->with($sharedWith) + ->willReturn(true); + + $this->groupManager->method('get')->with('group')->willReturn($group); + + $this->defaultProvider + ->method('getSharesByPath') + ->with($path) + ->willReturn([$share2]); + + $path->method('getName') + ->willReturn('name2.txt'); + + self::invokePrivate($this->manager, 'userCreateChecks', [$share]); + } + + public function testUserCreateChecksIdenticalPathSharedViaDeletedGroup(): void { + $share = $this->manager->newShare(); + + $sharedWith = $this->createMock(IUser::class); + $sharedWith->method('getUID')->willReturn('sharedWith'); + + $this->userManager->method('get')->with('sharedWith')->willReturn($sharedWith); + + $path = $this->createMock(Node::class); + + $share->setSharedWith('sharedWith') + ->setNode($path) + ->setShareOwner('shareOwner') + ->setProviderId('foo') + ->setId('bar'); + + $share2 = $this->manager->newShare(); + $share2->setShareType(IShare::TYPE_GROUP) + ->setShareOwner('shareOwner2') + ->setProviderId('foo') + ->setId('baz') + ->setSharedWith('group'); + + $this->groupManager->method('get')->with('group')->willReturn(null); + + $this->defaultProvider + ->method('getSharesByPath') + ->with($path) + ->willReturn([$share2]); + + $this->assertNull($this->invokePrivate($this->manager, 'userCreateChecks', [$share])); + } + + public function testUserCreateChecksIdenticalPathNotSharedWithUser(): void { + $share = $this->manager->newShare(); + $sharedWith = $this->createMock(IUser::class); + $path = $this->createMock(Node::class); + $share->setSharedWith('sharedWith') + ->setNode($path) + ->setShareOwner('shareOwner') + ->setProviderId('foo') + ->setId('bar'); + + $this->userManager->method('get')->with('sharedWith')->willReturn($sharedWith); + + $share2 = $this->manager->newShare(); + $share2->setShareType(IShare::TYPE_GROUP) + ->setShareOwner('shareOwner2') + ->setProviderId('foo') + ->setId('baz'); + + $group = $this->createMock(IGroup::class); + $group->method('inGroup') + ->with($sharedWith) + ->willReturn(false); + + $this->groupManager->method('get')->with('group')->willReturn($group); + + $share2->setSharedWith('group'); + + $this->defaultProvider + ->method('getSharesByPath') + ->with($path) + ->willReturn([$share2]); + + self::invokePrivate($this->manager, 'userCreateChecks', [$share]); + $this->addToAssertionCount(1); + } + + + public function testGroupCreateChecksShareWithGroupMembersGroupSharingNotAllowed(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Group sharing is now allowed'); + + $share = $this->manager->newShare(); + + $this->config + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_allow_group_sharing', 'yes', 'no'], + ]); + + self::invokePrivate($this->manager, 'groupCreateChecks', [$share]); + } + + + public function testGroupCreateChecksShareWithGroupMembersOnlyNotInGroup(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Sharing is only allowed within your own groups'); + + $share = $this->manager->newShare(); + + $user = $this->createMock(IUser::class); + $group = $this->createMock(IGroup::class); + $share->setSharedBy('user')->setSharedWith('group'); + + $group->method('inGroup')->with($user)->willReturn(false); + + $this->groupManager->method('get')->with('group')->willReturn($group); + $this->userManager->method('get')->with('user')->willReturn($user); + + $this->config + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'], + ['core', 'shareapi_allow_group_sharing', 'yes', 'yes'], + ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'], + ]); + + self::invokePrivate($this->manager, 'groupCreateChecks', [$share]); + } + + + public function testGroupCreateChecksShareWithGroupMembersOnlyNullGroup(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Sharing is only allowed within your own groups'); + + $share = $this->manager->newShare(); + + $user = $this->createMock(IUser::class); + $share->setSharedBy('user')->setSharedWith('group'); + + $this->groupManager->method('get')->with('group')->willReturn(null); + $this->userManager->method('get')->with('user')->willReturn($user); + + $this->config + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'], + ['core', 'shareapi_allow_group_sharing', 'yes', 'yes'], + ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'], + ]); + + $this->assertNull($this->invokePrivate($this->manager, 'groupCreateChecks', [$share])); + } + + public function testGroupCreateChecksShareWithGroupMembersOnlyInGroup(): void { + $share = $this->manager->newShare(); + + $user = $this->createMock(IUser::class); + $group = $this->createMock(IGroup::class); + $share->setSharedBy('user')->setSharedWith('group'); + + $this->userManager->method('get')->with('user')->willReturn($user); + $this->groupManager->method('get')->with('group')->willReturn($group); + + $group->method('inGroup')->with($user)->willReturn(true); + + $path = $this->createMock(Node::class); + $share->setNode($path); + + $this->defaultProvider->method('getSharesByPath') + ->with($path) + ->willReturn([]); + + $this->config + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'], + ['core', 'shareapi_allow_group_sharing', 'yes', 'yes'], + ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'], + ]); + + self::invokePrivate($this->manager, 'groupCreateChecks', [$share]); + $this->addToAssertionCount(1); + } + + + public function testGroupCreateChecksPathAlreadySharedWithSameGroup(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Path is already shared with this group'); + + $share = $this->manager->newShare(); + + $path = $this->createMock(Node::class); + $share->setSharedWith('sharedWith') + ->setNode($path) + ->setProviderId('foo') + ->setId('bar'); + + $share2 = $this->manager->newShare(); + $share2->setSharedWith('sharedWith') + ->setProviderId('foo') + ->setId('baz'); + + $this->defaultProvider->method('getSharesByPath') + ->with($path) + ->willReturn([$share2]); + + $this->config + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_allow_group_sharing', 'yes', 'yes'], + ]); + + self::invokePrivate($this->manager, 'groupCreateChecks', [$share]); + } + + public function testGroupCreateChecksPathAlreadySharedWithDifferentGroup(): void { + $share = $this->manager->newShare(); + + $share->setSharedWith('sharedWith'); + + $path = $this->createMock(Node::class); + $share->setNode($path); + + $share2 = $this->manager->newShare(); + $share2->setSharedWith('sharedWith2'); + + $this->defaultProvider->method('getSharesByPath') + ->with($path) + ->willReturn([$share2]); + + $this->config + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_allow_group_sharing', 'yes', 'yes'], + ]); + + self::invokePrivate($this->manager, 'groupCreateChecks', [$share]); + $this->addToAssertionCount(1); + } + + + public function testLinkCreateChecksNoLinkSharesAllowed(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Link sharing is not allowed'); + + $share = $this->manager->newShare(); + + $this->config + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_allow_links', 'yes', 'no'], + ]); + + self::invokePrivate($this->manager, 'linkCreateChecks', [$share]); + } + + + public function testFileLinkCreateChecksNoPublicUpload(): void { + $share = $this->manager->newShare(); + + $share->setPermissions(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE); + $share->setNodeType('file'); + + $this->config + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_allow_public_upload', 'yes', 'no'] + ]); + + self::invokePrivate($this->manager, 'linkCreateChecks', [$share]); + $this->addToAssertionCount(1); + } + + public function testFolderLinkCreateChecksNoPublicUpload(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Public upload is not allowed'); + + $share = $this->manager->newShare(); + + $share->setPermissions(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE); + $share->setNodeType('folder'); + + $this->config + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_allow_public_upload', 'yes', 'no'] + ]); + + self::invokePrivate($this->manager, 'linkCreateChecks', [$share]); + } + + public function testLinkCreateChecksPublicUpload(): void { + $share = $this->manager->newShare(); + + $share->setPermissions(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE); + $share->setSharedWith('sharedWith'); + $folder = $this->createMock(\OC\Files\Node\Folder::class); + $share->setNode($folder); + + $this->config + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_allow_public_upload', 'yes', 'yes'] + ]); + + self::invokePrivate($this->manager, 'linkCreateChecks', [$share]); + $this->addToAssertionCount(1); + } + + public function testLinkCreateChecksReadOnly(): void { + $share = $this->manager->newShare(); + + $share->setPermissions(\OCP\Constants::PERMISSION_READ); + $share->setSharedWith('sharedWith'); + $folder = $this->createMock(\OC\Files\Node\Folder::class); + $share->setNode($folder); + + $this->config + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_allow_public_upload', 'yes', 'no'] + ]); + + self::invokePrivate($this->manager, 'linkCreateChecks', [$share]); + $this->addToAssertionCount(1); + } + + + public function testPathCreateChecksContainsSharedMount(): void { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Path contains files shared with you'); + + $path = $this->createMock(Folder::class); + $path->method('getPath')->willReturn('path'); + + $mount = $this->createMock(IMountPoint::class); + $storage = $this->createMock(Storage::class); + $mount->method('getStorage')->willReturn($storage); + $storage->method('instanceOfStorage')->with(\OCA\Files_Sharing\ISharedStorage::class)->willReturn(true); + + $this->mountManager->method('findIn')->with('path')->willReturn([$mount]); + + self::invokePrivate($this->manager, 'pathCreateChecks', [$path]); + } + + public function testPathCreateChecksContainsNoSharedMount(): void { + $path = $this->createMock(Folder::class); + $path->method('getPath')->willReturn('path'); + + $mount = $this->createMock(IMountPoint::class); + $storage = $this->createMock(Storage::class); + $mount->method('getStorage')->willReturn($storage); + $storage->method('instanceOfStorage')->with(\OCA\Files_Sharing\ISharedStorage::class)->willReturn(false); + + $this->mountManager->method('findIn')->with('path')->willReturn([$mount]); + + self::invokePrivate($this->manager, 'pathCreateChecks', [$path]); + $this->addToAssertionCount(1); + } + + public function testPathCreateChecksContainsNoFolder(): void { + $path = $this->createMock(File::class); + + self::invokePrivate($this->manager, 'pathCreateChecks', [$path]); + $this->addToAssertionCount(1); + } + + public function dataIsSharingDisabledForUser() { + $data = []; + + // No exclude groups + $data[] = ['no', null, null, [], false]; + + // empty exclude / allow list, user no groups + $data[] = ['yes', '', json_encode(['']), [], false]; + $data[] = ['allow', '', json_encode(['']), [], true]; + + // empty exclude / allow list, user groups + $data[] = ['yes', '', json_encode(['']), ['group1', 'group2'], false]; + $data[] = ['allow', '', json_encode(['']), ['group1', 'group2'], true]; + + // Convert old list to json + $data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), [], false]; + $data[] = ['allow', 'group1,group2', json_encode(['group1', 'group2']), [], true]; + + // Old list partly groups in common + $data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), ['group1', 'group3'], false]; + $data[] = ['allow', 'group1,group2', json_encode(['group1', 'group2']), ['group1', 'group3'], false]; + + // Old list only groups in common + $data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), ['group1'], true]; + $data[] = ['allow', 'group1,group2', json_encode(['group1', 'group2']), ['group1'], false]; + + // New list partly in common + $data[] = ['yes', json_encode(['group1', 'group2']), null, ['group1', 'group3'], false]; + $data[] = ['allow', json_encode(['group1', 'group2']), null, ['group1', 'group3'], false]; + + // New list only groups in common + $data[] = ['yes', json_encode(['group1', 'group2']), null, ['group2'], true]; + $data[] = ['allow', json_encode(['group1', 'group2']), null, ['group2'], false]; + + return $data; + } + + /** + * @dataProvider dataIsSharingDisabledForUser + * + * @param string $excludeGroups + * @param string $groupList + * @param string $setList + * @param string[] $groupIds + * @param bool $expected + */ + public function testIsSharingDisabledForUser($excludeGroups, $groupList, $setList, $groupIds, $expected): void { + $user = $this->createMock(IUser::class); + + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_exclude_groups', 'no', $excludeGroups], + ['core', 'shareapi_exclude_groups_list', '', $groupList], + ]); + + if ($setList !== null) { + $this->config->expects($this->once()) + ->method('setAppValue') + ->with('core', 'shareapi_exclude_groups_list', $setList); + } else { + $this->config->expects($this->never()) + ->method('setAppValue'); + } + + $this->groupManager->method('getUserGroupIds') + ->with($user) + ->willReturn($groupIds); + + $this->userManager->method('get')->with('user')->willReturn($user); + + $res = $this->manager->sharingDisabledForUser('user'); + $this->assertEquals($expected, $res); + } + + public function dataCanShare() { + $data = []; + + /* + * [expected, sharing enabled, disabled for user] + */ + + $data[] = [false, 'no', false]; + $data[] = [false, 'no', true]; + $data[] = [true, 'yes', false]; + $data[] = [false, 'yes', true]; + + return $data; + } + + /** + * @dataProvider dataCanShare + * + * @param bool $expected + * @param string $sharingEnabled + * @param bool $disabledForUser + */ + public function testCanShare($expected, $sharingEnabled, $disabledForUser): void { + $this->config->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_enabled', 'yes', $sharingEnabled], + ]); + + $manager = $this->createManagerMock() + ->setMethods(['sharingDisabledForUser']) + ->getMock(); + + $manager->method('sharingDisabledForUser') + ->with('user') + ->willReturn($disabledForUser); + + $share = $this->manager->newShare(); + $share->setSharedBy('user'); + + $exception = false; + try { + $res = self::invokePrivate($manager, 'canShare', [$share]); + } catch (\Exception $e) { + $exception = true; + } + + $this->assertEquals($expected, !$exception); + } + + public function testCreateShareUser(): void { + $manager = $this->createManagerMock() + ->setMethods(['canShare', 'generalCreateChecks', 'userCreateChecks', 'pathCreateChecks']) + ->getMock(); + + $shareOwner = $this->createMock(IUser::class); + $shareOwner->method('getUID')->willReturn('shareOwner'); + + $storage = $this->createMock(Storage::class); + $path = $this->createMock(File::class); + $path->method('getOwner')->willReturn($shareOwner); + $path->method('getName')->willReturn('target'); + $path->method('getStorage')->willReturn($storage); + + $share = $this->createShare( + null, + IShare::TYPE_USER, + $path, + 'sharedWith', + 'sharedBy', + null, + \OCP\Constants::PERMISSION_ALL); + + $manager->expects($this->once()) + ->method('canShare') + ->with($share) + ->willReturn(true); + $manager->expects($this->once()) + ->method('generalCreateChecks') + ->with($share); + ; + $manager->expects($this->once()) + ->method('userCreateChecks') + ->with($share); + ; + $manager->expects($this->once()) + ->method('pathCreateChecks') + ->with($path); + + $this->defaultProvider + ->expects($this->once()) + ->method('create') + ->with($share) + ->willReturnArgument(0); + + $share->expects($this->once()) + ->method('setShareOwner') + ->with('shareOwner'); + $share->expects($this->once()) + ->method('setTarget') + ->with('/target'); + + $manager->createShare($share); + } + + public function testCreateShareGroup(): void { + $manager = $this->createManagerMock() + ->setMethods(['canShare', 'generalCreateChecks', 'groupCreateChecks', 'pathCreateChecks']) + ->getMock(); + + $shareOwner = $this->createMock(IUser::class); + $shareOwner->method('getUID')->willReturn('shareOwner'); + + $storage = $this->createMock(Storage::class); + $path = $this->createMock(File::class); + $path->method('getOwner')->willReturn($shareOwner); + $path->method('getName')->willReturn('target'); + $path->method('getStorage')->willReturn($storage); + + $share = $this->createShare( + null, + IShare::TYPE_GROUP, + $path, + 'sharedWith', + 'sharedBy', + null, + \OCP\Constants::PERMISSION_ALL); + + $manager->expects($this->once()) + ->method('canShare') + ->with($share) + ->willReturn(true); + $manager->expects($this->once()) + ->method('generalCreateChecks') + ->with($share); + ; + $manager->expects($this->once()) + ->method('groupCreateChecks') + ->with($share); + ; + $manager->expects($this->once()) + ->method('pathCreateChecks') + ->with($path); + + $this->defaultProvider + ->expects($this->once()) + ->method('create') + ->with($share) + ->willReturnArgument(0); + + $share->expects($this->once()) + ->method('setShareOwner') + ->with('shareOwner'); + $share->expects($this->once()) + ->method('setTarget') + ->with('/target'); + + $manager->createShare($share); + } + + public function testCreateShareLink(): void { + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'generalCreateChecks', + 'linkCreateChecks', + 'pathCreateChecks', + 'validateExpirationDateLink', + 'verifyPassword', + 'setLinkParent', + ]) + ->getMock(); + + $shareOwner = $this->createMock(IUser::class); + $shareOwner->method('getUID')->willReturn('shareOwner'); + + $storage = $this->createMock(Storage::class); + $path = $this->createMock(File::class); + $path->method('getOwner')->willReturn($shareOwner); + $path->method('getName')->willReturn('target'); + $path->method('getId')->willReturn(1); + $path->method('getStorage')->willReturn($storage); + + $date = new \DateTime(); + + $share = $this->manager->newShare(); + $share->setShareType(IShare::TYPE_LINK) + ->setNode($path) + ->setSharedBy('sharedBy') + ->setPermissions(\OCP\Constants::PERMISSION_ALL) + ->setExpirationDate($date) + ->setPassword('password'); + + $manager->expects($this->once()) + ->method('canShare') + ->with($share) + ->willReturn(true); + $manager->expects($this->once()) + ->method('generalCreateChecks') + ->with($share); + ; + $manager->expects($this->once()) + ->method('linkCreateChecks') + ->with($share); + ; + $manager->expects($this->once()) + ->method('pathCreateChecks') + ->with($path); + $manager->expects($this->once()) + ->method('validateExpirationDateLink') + ->with($share) + ->willReturn($share); + $manager->expects($this->once()) + ->method('verifyPassword') + ->with('password'); + $manager->expects($this->once()) + ->method('setLinkParent') + ->with($share); + + $this->hasher->expects($this->once()) + ->method('hash') + ->with('password') + ->willReturn('hashed'); + + $this->secureRandom->method('generate') + ->willReturn('token'); + + $this->defaultProvider + ->expects($this->once()) + ->method('create') + ->with($share) + ->willReturnCallback(function (Share $share) { + return $share->setId(42); + }); + + $this->dispatcher->expects($this->exactly(2)) + ->method('dispatchTyped') + ->withConsecutive( + // Pre share + [ + $this->callback(function (BeforeShareCreatedEvent $e) use ($path, $date) { + $share = $e->getShare(); + + return $share->getShareType() === IShare::TYPE_LINK && + $share->getNode() === $path && + $share->getSharedBy() === 'sharedBy' && + $share->getPermissions() === \OCP\Constants::PERMISSION_ALL && + $share->getExpirationDate() === $date && + $share->getPassword() === 'hashed' && + $share->getToken() === 'token'; + }) + ], + // Post share + [ + $this->callback(function (ShareCreatedEvent $e) use ($path, $date) { + $share = $e->getShare(); + + return $share->getShareType() === IShare::TYPE_LINK && + $share->getNode() === $path && + $share->getSharedBy() === 'sharedBy' && + $share->getPermissions() === \OCP\Constants::PERMISSION_ALL && + $share->getExpirationDate() === $date && + $share->getPassword() === 'hashed' && + $share->getToken() === 'token' && + $share->getId() === '42' && + $share->getTarget() === '/target'; + }) + ] + ); + + /** @var IShare $share */ + $share = $manager->createShare($share); + + $this->assertSame('shareOwner', $share->getShareOwner()); + $this->assertEquals('/target', $share->getTarget()); + $this->assertSame($date, $share->getExpirationDate()); + $this->assertEquals('token', $share->getToken()); + $this->assertEquals('hashed', $share->getPassword()); + } + + public function testCreateShareMail(): void { + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'generalCreateChecks', + 'linkCreateChecks', + 'pathCreateChecks', + 'validateExpirationDateLink', + 'verifyPassword', + 'setLinkParent', + ]) + ->getMock(); + + $shareOwner = $this->createMock(IUser::class); + $shareOwner->method('getUID')->willReturn('shareOwner'); + + $storage = $this->createMock(Storage::class); + $path = $this->createMock(File::class); + $path->method('getOwner')->willReturn($shareOwner); + $path->method('getName')->willReturn('target'); + $path->method('getId')->willReturn(1); + $path->method('getStorage')->willReturn($storage); + + $share = $this->manager->newShare(); + $share->setShareType(IShare::TYPE_EMAIL) + ->setNode($path) + ->setSharedBy('sharedBy') + ->setPermissions(\OCP\Constants::PERMISSION_ALL); + + $manager->expects($this->once()) + ->method('canShare') + ->with($share) + ->willReturn(true); + $manager->expects($this->once()) + ->method('generalCreateChecks') + ->with($share); + + $manager->expects($this->once()) + ->method('linkCreateChecks'); + $manager->expects($this->once()) + ->method('pathCreateChecks') + ->with($path); + $manager->expects($this->once()) + ->method('validateExpirationDateLink') + ->with($share) + ->willReturn($share); + $manager->expects($this->once()) + ->method('verifyPassword'); + $manager->expects($this->once()) + ->method('setLinkParent'); + + $this->secureRandom->method('generate') + ->willReturn('token'); + + $this->defaultProvider + ->expects($this->once()) + ->method('create') + ->with($share) + ->willReturnCallback(function (Share $share) { + return $share->setId(42); + }); + + $this->dispatcher->expects($this->exactly(2)) + ->method('dispatchTyped') + ->withConsecutive( + [ + $this->callback(function (BeforeShareCreatedEvent $e) use ($path) { + $share = $e->getShare(); + + return $share->getShareType() === IShare::TYPE_EMAIL && + $share->getNode() === $path && + $share->getSharedBy() === 'sharedBy' && + $share->getPermissions() === \OCP\Constants::PERMISSION_ALL && + $share->getExpirationDate() === null && + $share->getPassword() === null && + $share->getToken() === 'token'; + }) + ], + [ + $this->callback(function (ShareCreatedEvent $e) use ($path) { + $share = $e->getShare(); + + return $share->getShareType() === IShare::TYPE_EMAIL && + $share->getNode() === $path && + $share->getSharedBy() === 'sharedBy' && + $share->getPermissions() === \OCP\Constants::PERMISSION_ALL && + $share->getExpirationDate() === null && + $share->getPassword() === null && + $share->getToken() === 'token' && + $share->getId() === '42' && + $share->getTarget() === '/target'; + }) + ], + ); + + /** @var IShare $share */ + $share = $manager->createShare($share); + + $this->assertSame('shareOwner', $share->getShareOwner()); + $this->assertEquals('/target', $share->getTarget()); + $this->assertEquals('token', $share->getToken()); + } + + + public function testCreateShareHookError(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('I won\'t let you share'); + + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'generalCreateChecks', + 'userCreateChecks', + 'pathCreateChecks', + ]) + ->getMock(); + + $shareOwner = $this->createMock(IUser::class); + $shareOwner->method('getUID')->willReturn('shareOwner'); + + $storage = $this->createMock(Storage::class); + $path = $this->createMock(File::class); + $path->method('getOwner')->willReturn($shareOwner); + $path->method('getName')->willReturn('target'); + $path->method('getStorage')->willReturn($storage); + + $share = $this->createShare( + null, + IShare::TYPE_USER, + $path, + 'sharedWith', + 'sharedBy', + null, + \OCP\Constants::PERMISSION_ALL); + + $manager->expects($this->once()) + ->method('canShare') + ->with($share) + ->willReturn(true); + $manager->expects($this->once()) + ->method('generalCreateChecks') + ->with($share); + ; + $manager->expects($this->once()) + ->method('userCreateChecks') + ->with($share); + ; + $manager->expects($this->once()) + ->method('pathCreateChecks') + ->with($path); + + $share->expects($this->once()) + ->method('setShareOwner') + ->with('shareOwner'); + $share->expects($this->once()) + ->method('setTarget') + ->with('/target'); + + // Pre share + $this->dispatcher->expects($this->once()) + ->method('dispatchTyped') + ->with( + $this->isInstanceOf(BeforeShareCreatedEvent::class) + )->willReturnCallback(function (BeforeShareCreatedEvent $e) { + $e->setError('I won\'t let you share!'); + $e->stopPropagation(); + } + ); + + $manager->createShare($share); + } + + public function testCreateShareOfIncomingFederatedShare(): void { + $manager = $this->createManagerMock() + ->setMethods(['canShare', 'generalCreateChecks', 'userCreateChecks', 'pathCreateChecks']) + ->getMock(); + + $shareOwner = $this->createMock(IUser::class); + $shareOwner->method('getUID')->willReturn('shareOwner'); + + $storage = $this->createMock(Storage::class); + $storage->method('instanceOfStorage') + ->with(\OCA\Files_Sharing\External\Storage::class) + ->willReturn(true); + + $storage2 = $this->createMock(Storage::class); + $storage2->method('instanceOfStorage') + ->with(\OCA\Files_Sharing\External\Storage::class) + ->willReturn(false); + + $path = $this->createMock(File::class); + $path->expects($this->never())->method('getOwner'); + $path->method('getName')->willReturn('target'); + $path->method('getStorage')->willReturn($storage); + + $parent = $this->createMock(Folder::class); + $parent->method('getStorage')->willReturn($storage); + + $parentParent = $this->createMock(Folder::class); + $parentParent->method('getStorage')->willReturn($storage2); + $parentParent->method('getOwner')->willReturn($shareOwner); + + $path->method('getParent')->willReturn($parent); + $parent->method('getParent')->willReturn($parentParent); + + $share = $this->createShare( + null, + IShare::TYPE_USER, + $path, + 'sharedWith', + 'sharedBy', + null, + \OCP\Constants::PERMISSION_ALL); + + $manager->expects($this->once()) + ->method('canShare') + ->with($share) + ->willReturn(true); + $manager->expects($this->once()) + ->method('generalCreateChecks') + ->with($share); + ; + $manager->expects($this->once()) + ->method('userCreateChecks') + ->with($share); + ; + $manager->expects($this->once()) + ->method('pathCreateChecks') + ->with($path); + + $this->defaultProvider + ->expects($this->once()) + ->method('create') + ->with($share) + ->willReturnArgument(0); + + $share->expects($this->once()) + ->method('setShareOwner') + ->with('shareOwner'); + $share->expects($this->once()) + ->method('setTarget') + ->with('/target'); + + $manager->createShare($share); + } + + public function testGetSharesBy(): void { + $share = $this->manager->newShare(); + + $node = $this->createMock(Folder::class); + + $this->defaultProvider->expects($this->once()) + ->method('getSharesBy') + ->with( + $this->equalTo('user'), + $this->equalTo(IShare::TYPE_USER), + $this->equalTo($node), + $this->equalTo(true), + $this->equalTo(1), + $this->equalTo(1) + )->willReturn([$share]); + + $shares = $this->manager->getSharesBy('user', IShare::TYPE_USER, $node, true, 1, 1); + + $this->assertCount(1, $shares); + $this->assertSame($share, $shares[0]); + } + + /** + * Test to ensure we correctly remove expired link shares + * + * We have 8 Shares and we want the 3 first valid shares. + * share 3-6 and 8 are expired. Thus at the end of this test we should + * have received share 1,2 and 7. And from the manager. Share 3-6 should be + * deleted (as they are evaluated). but share 8 should still be there. + */ + public function testGetSharesByExpiredLinkShares(): void { + $manager = $this->createManagerMock() + ->setMethods(['deleteShare']) + ->getMock(); + + /** @var \OCP\Share\IShare[] $shares */ + $shares = []; + + /* + * This results in an array of 8 IShare elements + */ + for ($i = 0; $i < 8; $i++) { + $share = $this->manager->newShare(); + $share->setId($i); + $shares[] = $share; + } + + $today = new \DateTime(); + $today->setTime(0, 0, 0); + + /* + * Set the expiration date to today for some shares + */ + $shares[2]->setExpirationDate($today); + $shares[3]->setExpirationDate($today); + $shares[4]->setExpirationDate($today); + $shares[5]->setExpirationDate($today); + + /** @var \OCP\Share\IShare[] $i */ + $shares2 = []; + for ($i = 0; $i < 8; $i++) { + $shares2[] = clone $shares[$i]; + } + + $node = $this->createMock(File::class); + + /* + * Simulate the getSharesBy call. + */ + $this->defaultProvider + ->method('getSharesBy') + ->willReturnCallback(function ($uid, $type, $node, $reshares, $limit, $offset) use (&$shares2) { + return array_slice($shares2, $offset, $limit); + }); + + /* + * Simulate the deleteShare call. + */ + $manager->method('deleteShare') + ->willReturnCallback(function ($share) use (&$shares2) { + for ($i = 0; $i < count($shares2); $i++) { + if ($shares2[$i]->getId() === $share->getId()) { + array_splice($shares2, $i, 1); + break; + } + } + }); + + $res = $manager->getSharesBy('user', IShare::TYPE_LINK, $node, true, 3, 0); + + $this->assertCount(3, $res); + $this->assertEquals($shares[0]->getId(), $res[0]->getId()); + $this->assertEquals($shares[1]->getId(), $res[1]->getId()); + $this->assertEquals($shares[6]->getId(), $res[2]->getId()); + + $this->assertCount(4, $shares2); + $this->assertEquals(0, $shares2[0]->getId()); + $this->assertEquals(1, $shares2[1]->getId()); + $this->assertEquals(6, $shares2[2]->getId()); + $this->assertEquals(7, $shares2[3]->getId()); + $this->assertSame($today, $shares[3]->getExpirationDate()); + } + + public function testGetShareByToken(): void { + $this->config + ->expects($this->exactly(2)) + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['files_sharing', 'hide_disabled_user_shares', 'no', 'no'], + ]); + + $factory = $this->createMock(IProviderFactory::class); + + $manager = $this->createManager($factory); + + $share = $this->createMock(IShare::class); + + $factory->expects($this->once()) + ->method('getProviderForType') + ->with(IShare::TYPE_LINK) + ->willReturn($this->defaultProvider); + + $this->defaultProvider->expects($this->once()) + ->method('getShareByToken') + ->with('token') + ->willReturn($share); + + $ret = $manager->getShareByToken('token'); + $this->assertSame($share, $ret); + } + + public function testGetShareByTokenRoom(): void { + $this->config + ->expects($this->exactly(2)) + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_allow_links', 'yes', 'no'], + ['files_sharing', 'hide_disabled_user_shares', 'no', 'no'], + ]); + + $factory = $this->createMock(IProviderFactory::class); + + $manager = $this->createManager($factory); + + $share = $this->createMock(IShare::class); + + $roomShareProvider = $this->createMock(IShareProvider::class); + + $factory->expects($this->any()) + ->method('getProviderForType') + ->willReturnCallback(function ($shareType) use ($roomShareProvider) { + if ($shareType !== IShare::TYPE_ROOM) { + throw new Exception\ProviderException(); + } + + return $roomShareProvider; + }); + + $roomShareProvider->expects($this->once()) + ->method('getShareByToken') + ->with('token') + ->willReturn($share); + + $ret = $manager->getShareByToken('token'); + $this->assertSame($share, $ret); + } + + public function testGetShareByTokenWithException(): void { + $this->config + ->expects($this->exactly(2)) + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['files_sharing', 'hide_disabled_user_shares', 'no', 'no'], + ]); + + $factory = $this->createMock(IProviderFactory::class); + + $manager = $this->createManager($factory); + + $share = $this->createMock(IShare::class); + + $factory->expects($this->exactly(2)) + ->method('getProviderForType') + ->withConsecutive( + [IShare::TYPE_LINK], + [IShare::TYPE_REMOTE] + ) + ->willReturn($this->defaultProvider); + + $this->defaultProvider->expects($this->exactly(2)) + ->method('getShareByToken') + ->with('token') + ->willReturnOnConsecutiveCalls( + $this->throwException(new ShareNotFound()), + $share + ); + + $ret = $manager->getShareByToken('token'); + $this->assertSame($share, $ret); + } + + + public function testGetShareByTokenHideDisabledUser(): void { + $this->expectException(\OCP\Share\Exceptions\ShareNotFound::class); + $this->expectExceptionMessage('The requested share comes from a disabled user'); + + $this->config + ->expects($this->exactly(2)) + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['files_sharing', 'hide_disabled_user_shares', 'no', 'yes'], + ]); + + $this->l->expects($this->once()) + ->method('t') + ->willReturnArgument(0); + + $manager = $this->createManagerMock() + ->setMethods(['deleteShare']) + ->getMock(); + + $date = new \DateTime(); + $date->setTime(0, 0, 0); + $date->add(new \DateInterval('P2D')); + $share = $this->manager->newShare(); + $share->setExpirationDate($date); + $share->setShareOwner('owner'); + $share->setSharedBy('sharedBy'); + + $sharedBy = $this->createMock(IUser::class); + $owner = $this->createMock(IUser::class); + + $this->userManager->method('get')->willReturnMap([ + ['sharedBy', $sharedBy], + ['owner', $owner], + ]); + + $owner->expects($this->once()) + ->method('isEnabled') + ->willReturn(true); + $sharedBy->expects($this->once()) + ->method('isEnabled') + ->willReturn(false); + + $this->defaultProvider->expects($this->once()) + ->method('getShareByToken') + ->with('expiredToken') + ->willReturn($share); + + $manager->expects($this->never()) + ->method('deleteShare'); + + $manager->getShareByToken('expiredToken'); + } + + + public function testGetShareByTokenExpired(): void { + $this->expectException(\OCP\Share\Exceptions\ShareNotFound::class); + $this->expectExceptionMessage('The requested share does not exist anymore'); + + $this->config + ->expects($this->once()) + ->method('getAppValue') + ->with('core', 'shareapi_allow_links', 'yes') + ->willReturn('yes'); + + $this->l->expects($this->once()) + ->method('t') + ->willReturnArgument(0); + + $manager = $this->createManagerMock() + ->setMethods(['deleteShare']) + ->getMock(); + + $date = new \DateTime(); + $date->setTime(0, 0, 0); + $share = $this->manager->newShare(); + $share->setExpirationDate($date); + + $this->defaultProvider->expects($this->once()) + ->method('getShareByToken') + ->with('expiredToken') + ->willReturn($share); + + $manager->expects($this->once()) + ->method('deleteShare') + ->with($this->equalTo($share)); + + $manager->getShareByToken('expiredToken'); + } + + public function testGetShareByTokenNotExpired(): void { + $this->config + ->expects($this->exactly(2)) + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['files_sharing', 'hide_disabled_user_shares', 'no', 'no'], + ]); + + $date = new \DateTime(); + $date->setTime(0, 0, 0); + $date->add(new \DateInterval('P2D')); + $share = $this->manager->newShare(); + $share->setExpirationDate($date); + + $this->defaultProvider->expects($this->once()) + ->method('getShareByToken') + ->with('expiredToken') + ->willReturn($share); + + $res = $this->manager->getShareByToken('expiredToken'); + + $this->assertSame($share, $res); + } + + + public function testGetShareByTokenWithPublicLinksDisabled(): void { + $this->expectException(\OCP\Share\Exceptions\ShareNotFound::class); + + $this->config + ->expects($this->once()) + ->method('getAppValue') + ->with('core', 'shareapi_allow_links', 'yes') + ->willReturn('no'); + $this->manager->getShareByToken('validToken'); + } + + public function testGetShareByTokenPublicUploadDisabled(): void { + $this->config + ->expects($this->exactly(3)) + ->method('getAppValue') + ->willReturnMap([ + ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_allow_public_upload', 'yes', 'no'], + ['files_sharing', 'hide_disabled_user_shares', 'no', 'no'], + ]); + + $share = $this->manager->newShare(); + $share->setShareType(IShare::TYPE_LINK) + ->setPermissions(\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE); + $share->setSharedWith('sharedWith'); + $folder = $this->createMock(\OC\Files\Node\Folder::class); + $share->setNode($folder); + + $this->defaultProvider->expects($this->once()) + ->method('getShareByToken') + ->willReturn('validToken') + ->willReturn($share); + + $res = $this->manager->getShareByToken('validToken'); + + $this->assertSame(\OCP\Constants::PERMISSION_READ, $res->getPermissions()); + } + + public function testCheckPasswordNoLinkShare(): void { + $share = $this->createMock(IShare::class); + $share->method('getShareType')->willReturn(IShare::TYPE_USER); + $this->assertFalse($this->manager->checkPassword($share, 'password')); + } + + public function testCheckPasswordNoPassword(): void { + $share = $this->createMock(IShare::class); + $share->method('getShareType')->willReturn(IShare::TYPE_LINK); + $this->assertFalse($this->manager->checkPassword($share, 'password')); + + $share->method('getPassword')->willReturn('password'); + $this->assertFalse($this->manager->checkPassword($share, null)); + } + + public function testCheckPasswordInvalidPassword(): void { + $share = $this->createMock(IShare::class); + $share->method('getShareType')->willReturn(IShare::TYPE_LINK); + $share->method('getPassword')->willReturn('password'); + + $this->hasher->method('verify')->with('invalidpassword', 'password', '')->willReturn(false); + + $this->assertFalse($this->manager->checkPassword($share, 'invalidpassword')); + } + + public function testCheckPasswordValidPassword(): void { + $share = $this->createMock(IShare::class); + $share->method('getShareType')->willReturn(IShare::TYPE_LINK); + $share->method('getPassword')->willReturn('passwordHash'); + + $this->hasher->method('verify')->with('password', 'passwordHash', '')->willReturn(true); + + $this->assertTrue($this->manager->checkPassword($share, 'password')); + } + + public function testCheckPasswordUpdateShare(): void { + $share = $this->manager->newShare(); + $share->setShareType(IShare::TYPE_LINK) + ->setPassword('passwordHash'); + + $this->hasher->method('verify')->with('password', 'passwordHash', '') + ->willReturnCallback(function ($pass, $hash, &$newHash) { + $newHash = 'newHash'; + + return true; + }); + + $this->defaultProvider->expects($this->once()) + ->method('update') + ->with($this->callback(function (\OCP\Share\IShare $share) { + return $share->getPassword() === 'newHash'; + })); + + $this->assertTrue($this->manager->checkPassword($share, 'password')); + } + + + public function testUpdateShareCantChangeShareType(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Cannot change share type'); + + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'getShareById' + ]) + ->getMock(); + + $originalShare = $this->manager->newShare(); + $originalShare->setShareType(IShare::TYPE_GROUP); + + $manager->expects($this->once())->method('canShare')->willReturn(true); + $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); + + $share = $this->manager->newShare(); + $attrs = $this->manager->newShare()->newAttributes(); + $attrs->setAttribute('app1', 'perm1', true); + $share->setProviderId('foo') + ->setId('42') + ->setShareType(IShare::TYPE_USER); + + $manager->updateShare($share); + } + + + public function testUpdateShareCantChangeRecipientForGroupShare(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Can only update recipient on user shares'); + + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'getShareById' + ]) + ->getMock(); + + $originalShare = $this->manager->newShare(); + $originalShare->setShareType(IShare::TYPE_GROUP) + ->setSharedWith('origGroup'); + + $manager->expects($this->once())->method('canShare')->willReturn(true); + $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); + + $share = $this->manager->newShare(); + $share->setProviderId('foo') + ->setId('42') + ->setShareType(IShare::TYPE_GROUP) + ->setSharedWith('newGroup'); + + $manager->updateShare($share); + } + + + public function testUpdateShareCantShareWithOwner(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Cannot share with the share owner'); + + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'getShareById' + ]) + ->getMock(); + + $originalShare = $this->manager->newShare(); + $originalShare->setShareType(IShare::TYPE_USER) + ->setSharedWith('sharedWith'); + + $manager->expects($this->once())->method('canShare')->willReturn(true); + $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); + + $share = $this->manager->newShare(); + $share->setProviderId('foo') + ->setId('42') + ->setShareType(IShare::TYPE_USER) + ->setSharedWith('newUser') + ->setShareOwner('newUser'); + + $manager->updateShare($share); + } + + public function testUpdateShareUser(): void { + $this->userManager->expects($this->any())->method('userExists')->willReturn(true); + + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'getShareById', + 'generalCreateChecks', + 'userCreateChecks', + 'pathCreateChecks', + ]) + ->getMock(); + + $originalShare = $this->manager->newShare(); + $originalShare->setShareType(IShare::TYPE_USER) + ->setSharedWith('origUser') + ->setPermissions(1); + + $node = $this->createMock(File::class); + $node->method('getId')->willReturn(100); + $node->method('getPath')->willReturn('/newUser/files/myPath'); + + $manager->expects($this->once())->method('canShare')->willReturn(true); + $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); + + $share = $this->manager->newShare(); + $attrs = $this->manager->newShare()->newAttributes(); + $attrs->setAttribute('app1', 'perm1', true); + $share->setProviderId('foo') + ->setId('42') + ->setShareType(IShare::TYPE_USER) + ->setSharedWith('origUser') + ->setShareOwner('newUser') + ->setSharedBy('sharer') + ->setPermissions(31) + ->setAttributes($attrs) + ->setNode($node); + + $this->defaultProvider->expects($this->once()) + ->method('update') + ->with($share) + ->willReturn($share); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_set_expiration_date', $hookListener, 'post'); + $hookListener->expects($this->never())->method('post'); + + $this->rootFolder->method('getUserFolder')->with('newUser')->willReturnSelf(); + $this->rootFolder->method('getRelativePath')->with('/newUser/files/myPath')->willReturn('/myPath'); + + $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_permissions', $hookListener2, 'post'); + $hookListener2->expects($this->once())->method('post')->with([ + 'itemType' => 'file', + 'itemSource' => 100, + 'shareType' => IShare::TYPE_USER, + 'shareWith' => 'origUser', + 'uidOwner' => 'sharer', + 'permissions' => 31, + 'path' => '/myPath', + 'attributes' => $attrs->toArray(), + ]); + + $manager->updateShare($share); + } + + public function testUpdateShareGroup(): void { + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'getShareById', + 'generalCreateChecks', + 'groupCreateChecks', + 'pathCreateChecks', + ]) + ->getMock(); + + $originalShare = $this->manager->newShare(); + $originalShare->setShareType(IShare::TYPE_GROUP) + ->setSharedWith('origUser') + ->setPermissions(31); + + $manager->expects($this->once())->method('canShare')->willReturn(true); + $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); + + $node = $this->createMock(File::class); + + $share = $this->manager->newShare(); + $share->setProviderId('foo') + ->setId('42') + ->setShareType(IShare::TYPE_GROUP) + ->setSharedWith('origUser') + ->setShareOwner('owner') + ->setNode($node) + ->setPermissions(31); + + $this->defaultProvider->expects($this->once()) + ->method('update') + ->with($share) + ->willReturn($share); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_set_expiration_date', $hookListener, 'post'); + $hookListener->expects($this->never())->method('post'); + + $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_permissions', $hookListener2, 'post'); + $hookListener2->expects($this->never())->method('post'); + + $manager->updateShare($share); + } + + public function testUpdateShareLink(): void { + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'getShareById', + 'generalCreateChecks', + 'linkCreateChecks', + 'pathCreateChecks', + 'verifyPassword', + 'validateExpirationDateLink', + ]) + ->getMock(); + + $originalShare = $this->manager->newShare(); + $originalShare->setShareType(IShare::TYPE_LINK) + ->setPermissions(15); + + $tomorrow = new \DateTime(); + $tomorrow->setTime(0, 0, 0); + $tomorrow->add(new \DateInterval('P1D')); + + $file = $this->createMock(File::class); + $file->method('getId')->willReturn(100); + + $share = $this->manager->newShare(); + $share->setProviderId('foo') + ->setId('42') + ->setShareType(IShare::TYPE_LINK) + ->setToken('token') + ->setSharedBy('owner') + ->setShareOwner('owner') + ->setPassword('password') + ->setExpirationDate($tomorrow) + ->setNode($file) + ->setPermissions(15); + + $manager->expects($this->once())->method('canShare')->willReturn(true); + $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); + $manager->expects($this->once())->method('validateExpirationDateLink')->with($share); + $manager->expects($this->once())->method('verifyPassword')->with('password'); + + $this->hasher->expects($this->once()) + ->method('hash') + ->with('password') + ->willReturn('hashed'); + + $this->defaultProvider->expects($this->once()) + ->method('update') + ->with($share) + ->willReturn($share); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_set_expiration_date', $hookListener, 'post'); + $hookListener->expects($this->once())->method('post')->with([ + 'itemType' => 'file', + 'itemSource' => 100, + 'date' => $tomorrow, + 'uidOwner' => 'owner', + ]); + + $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_password', $hookListener2, 'post'); + $hookListener2->expects($this->once())->method('post')->with([ + 'itemType' => 'file', + 'itemSource' => 100, + 'uidOwner' => 'owner', + 'token' => 'token', + 'disabled' => false, + ]); + + $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_permissions', $hookListener3, 'post'); + $hookListener3->expects($this->never())->method('post'); + + + $manager->updateShare($share); + } + + public function testUpdateShareLinkEnableSendPasswordByTalkWithNoPassword(): void { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Cannot enable sending the password by Talk with an empty password'); + + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'getShareById', + 'generalCreateChecks', + 'linkCreateChecks', + 'pathCreateChecks', + 'verifyPassword', + 'validateExpirationDateLink', + ]) + ->getMock(); + + $originalShare = $this->manager->newShare(); + $originalShare->setShareType(IShare::TYPE_LINK) + ->setPermissions(15); + + $tomorrow = new \DateTime(); + $tomorrow->setTime(0, 0, 0); + $tomorrow->add(new \DateInterval('P1D')); + + $file = $this->createMock(File::class); + $file->method('getId')->willReturn(100); + + $share = $this->manager->newShare(); + $share->setProviderId('foo') + ->setId('42') + ->setShareType(IShare::TYPE_LINK) + ->setToken('token') + ->setSharedBy('owner') + ->setShareOwner('owner') + ->setPassword(null) + ->setSendPasswordByTalk(true) + ->setExpirationDate($tomorrow) + ->setNode($file) + ->setPermissions(15); + + $manager->expects($this->once())->method('canShare')->willReturn(true); + $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); + $manager->expects($this->once())->method('generalCreateChecks')->with($share); + $manager->expects($this->once())->method('linkCreateChecks')->with($share); + $manager->expects($this->never())->method('verifyPassword'); + $manager->expects($this->never())->method('pathCreateChecks'); + $manager->expects($this->never())->method('validateExpirationDateLink'); + + $this->hasher->expects($this->never()) + ->method('hash'); + + $this->defaultProvider->expects($this->never()) + ->method('update'); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_set_expiration_date', $hookListener, 'post'); + $hookListener->expects($this->never())->method('post'); + + $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_password', $hookListener2, 'post'); + $hookListener2->expects($this->never())->method('post'); + + $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_permissions', $hookListener3, 'post'); + $hookListener3->expects($this->never())->method('post'); + + $manager->updateShare($share); + } + + public function testUpdateShareMail(): void { + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'getShareById', + 'generalCreateChecks', + 'verifyPassword', + 'pathCreateChecks', + 'linkCreateChecks', + 'validateExpirationDateLink', + ]) + ->getMock(); + + $originalShare = $this->manager->newShare(); + $originalShare->setShareType(IShare::TYPE_EMAIL) + ->setPermissions(\OCP\Constants::PERMISSION_ALL); + + $tomorrow = new \DateTime(); + $tomorrow->setTime(0, 0, 0); + $tomorrow->add(new \DateInterval('P1D')); + + $file = $this->createMock(File::class); + $file->method('getId')->willReturn(100); + + $share = $this->manager->newShare(); + $share->setProviderId('foo') + ->setId('42') + ->setShareType(IShare::TYPE_EMAIL) + ->setToken('token') + ->setSharedBy('owner') + ->setShareOwner('owner') + ->setPassword('password') + ->setExpirationDate($tomorrow) + ->setNode($file) + ->setPermissions(\OCP\Constants::PERMISSION_ALL); + + $manager->expects($this->once())->method('canShare')->willReturn(true); + $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); + $manager->expects($this->once())->method('generalCreateChecks')->with($share); + $manager->expects($this->once())->method('verifyPassword')->with('password'); + $manager->expects($this->once())->method('pathCreateChecks')->with($file); + $manager->expects($this->once())->method('linkCreateChecks'); + $manager->expects($this->once())->method('validateExpirationDateLink'); + + $this->hasher->expects($this->once()) + ->method('hash') + ->with('password') + ->willReturn('hashed'); + + $this->defaultProvider->expects($this->once()) + ->method('update') + ->with($share, 'password') + ->willReturn($share); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_set_expiration_date', $hookListener, 'post'); + $hookListener->expects($this->once())->method('post')->with([ + 'itemType' => 'file', + 'itemSource' => 100, + 'date' => $tomorrow, + 'uidOwner' => 'owner', + ]); + + $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_password', $hookListener2, 'post'); + $hookListener2->expects($this->once())->method('post')->with([ + 'itemType' => 'file', + 'itemSource' => 100, + 'uidOwner' => 'owner', + 'token' => 'token', + 'disabled' => false, + ]); + + $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_permissions', $hookListener3, 'post'); + $hookListener3->expects($this->never())->method('post'); + + $manager->updateShare($share); + } + + public function testUpdateShareMailEnableSendPasswordByTalk(): void { + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'getShareById', + 'generalCreateChecks', + 'verifyPassword', + 'pathCreateChecks', + 'linkCreateChecks', + 'validateExpirationDateLink', + ]) + ->getMock(); + + $originalShare = $this->manager->newShare(); + $originalShare->setShareType(IShare::TYPE_EMAIL) + ->setPermissions(\OCP\Constants::PERMISSION_ALL) + ->setPassword(null) + ->setSendPasswordByTalk(false); + + $tomorrow = new \DateTime(); + $tomorrow->setTime(0, 0, 0); + $tomorrow->add(new \DateInterval('P1D')); + + $file = $this->createMock(File::class); + $file->method('getId')->willReturn(100); + + $share = $this->manager->newShare(); + $share->setProviderId('foo') + ->setId('42') + ->setShareType(IShare::TYPE_EMAIL) + ->setToken('token') + ->setSharedBy('owner') + ->setShareOwner('owner') + ->setPassword('password') + ->setSendPasswordByTalk(true) + ->setExpirationDate($tomorrow) + ->setNode($file) + ->setPermissions(\OCP\Constants::PERMISSION_ALL); + + $manager->expects($this->once())->method('canShare')->willReturn(true); + $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); + $manager->expects($this->once())->method('generalCreateChecks')->with($share); + $manager->expects($this->once())->method('verifyPassword')->with('password'); + $manager->expects($this->once())->method('pathCreateChecks')->with($file); + $manager->expects($this->once())->method('linkCreateChecks'); + $manager->expects($this->once())->method('validateExpirationDateLink'); + + $this->hasher->expects($this->once()) + ->method('hash') + ->with('password') + ->willReturn('hashed'); + + $this->defaultProvider->expects($this->once()) + ->method('update') + ->with($share, 'password') + ->willReturn($share); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_set_expiration_date', $hookListener, 'post'); + $hookListener->expects($this->once())->method('post')->with([ + 'itemType' => 'file', + 'itemSource' => 100, + 'date' => $tomorrow, + 'uidOwner' => 'owner', + ]); + + $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_password', $hookListener2, 'post'); + $hookListener2->expects($this->once())->method('post')->with([ + 'itemType' => 'file', + 'itemSource' => 100, + 'uidOwner' => 'owner', + 'token' => 'token', + 'disabled' => false, + ]); + + $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_permissions', $hookListener3, 'post'); + $hookListener3->expects($this->never())->method('post'); + + $manager->updateShare($share); + } + + public function testUpdateShareMailEnableSendPasswordByTalkWithDifferentPassword(): void { + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'getShareById', + 'generalCreateChecks', + 'verifyPassword', + 'pathCreateChecks', + 'linkCreateChecks', + 'validateExpirationDateLink', + ]) + ->getMock(); + + $originalShare = $this->manager->newShare(); + $originalShare->setShareType(IShare::TYPE_EMAIL) + ->setPermissions(\OCP\Constants::PERMISSION_ALL) + ->setPassword('anotherPasswordHash') + ->setSendPasswordByTalk(false); + + $tomorrow = new \DateTime(); + $tomorrow->setTime(0, 0, 0); + $tomorrow->add(new \DateInterval('P1D')); + + $file = $this->createMock(File::class); + $file->method('getId')->willReturn(100); + + $share = $this->manager->newShare(); + $share->setProviderId('foo') + ->setId('42') + ->setShareType(IShare::TYPE_EMAIL) + ->setToken('token') + ->setSharedBy('owner') + ->setShareOwner('owner') + ->setPassword('password') + ->setSendPasswordByTalk(true) + ->setExpirationDate($tomorrow) + ->setNode($file) + ->setPermissions(\OCP\Constants::PERMISSION_ALL); + + $manager->expects($this->once())->method('canShare')->willReturn(true); + $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); + $manager->expects($this->once())->method('generalCreateChecks')->with($share); + $manager->expects($this->once())->method('verifyPassword')->with('password'); + $manager->expects($this->once())->method('pathCreateChecks')->with($file); + $manager->expects($this->once())->method('linkCreateChecks'); + $manager->expects($this->once())->method('validateExpirationDateLink'); + + $this->hasher->expects($this->once()) + ->method('verify') + ->with('password', 'anotherPasswordHash') + ->willReturn(false); + + $this->hasher->expects($this->once()) + ->method('hash') + ->with('password') + ->willReturn('hashed'); + + $this->defaultProvider->expects($this->once()) + ->method('update') + ->with($share, 'password') + ->willReturn($share); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_set_expiration_date', $hookListener, 'post'); + $hookListener->expects($this->once())->method('post')->with([ + 'itemType' => 'file', + 'itemSource' => 100, + 'date' => $tomorrow, + 'uidOwner' => 'owner', + ]); + + $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_password', $hookListener2, 'post'); + $hookListener2->expects($this->once())->method('post')->with([ + 'itemType' => 'file', + 'itemSource' => 100, + 'uidOwner' => 'owner', + 'token' => 'token', + 'disabled' => false, + ]); + + $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_permissions', $hookListener3, 'post'); + $hookListener3->expects($this->never())->method('post'); + + $manager->updateShare($share); + } + + public function testUpdateShareMailEnableSendPasswordByTalkWithNoPassword(): void { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Cannot enable sending the password by Talk with an empty password'); + + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'getShareById', + 'generalCreateChecks', + 'verifyPassword', + 'pathCreateChecks', + 'linkCreateChecks', + 'validateExpirationDateLink', + ]) + ->getMock(); + + $originalShare = $this->manager->newShare(); + $originalShare->setShareType(IShare::TYPE_EMAIL) + ->setPermissions(\OCP\Constants::PERMISSION_ALL) + ->setPassword(null) + ->setSendPasswordByTalk(false); + + $tomorrow = new \DateTime(); + $tomorrow->setTime(0, 0, 0); + $tomorrow->add(new \DateInterval('P1D')); + + $file = $this->createMock(File::class); + $file->method('getId')->willReturn(100); + + $share = $this->manager->newShare(); + $share->setProviderId('foo') + ->setId('42') + ->setShareType(IShare::TYPE_EMAIL) + ->setToken('token') + ->setSharedBy('owner') + ->setShareOwner('owner') + ->setPassword(null) + ->setSendPasswordByTalk(true) + ->setExpirationDate($tomorrow) + ->setNode($file) + ->setPermissions(\OCP\Constants::PERMISSION_ALL); + + $manager->expects($this->once())->method('canShare')->willReturn(true); + $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); + $manager->expects($this->once())->method('generalCreateChecks')->with($share); + $manager->expects($this->never())->method('verifyPassword'); + $manager->expects($this->never())->method('pathCreateChecks'); + $manager->expects($this->once())->method('linkCreateChecks'); + $manager->expects($this->never())->method('validateExpirationDateLink'); + + // If the password is empty, we have nothing to hash + $this->hasher->expects($this->never()) + ->method('hash'); + + $this->defaultProvider->expects($this->never()) + ->method('update'); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_set_expiration_date', $hookListener, 'post'); + $hookListener->expects($this->never())->method('post'); + + $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_password', $hookListener2, 'post'); + $hookListener2->expects($this->never())->method('post'); + + $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_permissions', $hookListener3, 'post'); + $hookListener3->expects($this->never())->method('post'); + + $manager->updateShare($share); + } + + + public function testUpdateShareMailEnableSendPasswordByTalkRemovingPassword(): void { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Cannot enable sending the password by Talk with an empty password'); + + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'getShareById', + 'generalCreateChecks', + 'verifyPassword', + 'pathCreateChecks', + 'linkCreateChecks', + 'validateExpirationDateLink', + ]) + ->getMock(); + + $originalShare = $this->manager->newShare(); + $originalShare->setShareType(IShare::TYPE_EMAIL) + ->setPermissions(\OCP\Constants::PERMISSION_ALL) + ->setPassword('passwordHash') + ->setSendPasswordByTalk(false); + + $tomorrow = new \DateTime(); + $tomorrow->setTime(0, 0, 0); + $tomorrow->add(new \DateInterval('P1D')); + + $file = $this->createMock(File::class); + $file->method('getId')->willReturn(100); + + $share = $this->manager->newShare(); + $share->setProviderId('foo') + ->setId('42') + ->setShareType(IShare::TYPE_EMAIL) + ->setToken('token') + ->setSharedBy('owner') + ->setShareOwner('owner') + ->setPassword(null) + ->setSendPasswordByTalk(true) + ->setExpirationDate($tomorrow) + ->setNode($file) + ->setPermissions(\OCP\Constants::PERMISSION_ALL); + + $manager->expects($this->once())->method('canShare')->willReturn(true); + $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); + $manager->expects($this->once())->method('generalCreateChecks')->with($share); + $manager->expects($this->once())->method('verifyPassword'); + $manager->expects($this->never())->method('pathCreateChecks'); + $manager->expects($this->once())->method('linkCreateChecks'); + $manager->expects($this->never())->method('validateExpirationDateLink'); + + // If the password is empty, we have nothing to hash + $this->hasher->expects($this->never()) + ->method('hash'); + + $this->defaultProvider->expects($this->never()) + ->method('update'); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_set_expiration_date', $hookListener, 'post'); + $hookListener->expects($this->never())->method('post'); + + $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_password', $hookListener2, 'post'); + $hookListener2->expects($this->never())->method('post'); + + $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_permissions', $hookListener3, 'post'); + $hookListener3->expects($this->never())->method('post'); + + $manager->updateShare($share); + } + + + public function testUpdateShareMailEnableSendPasswordByTalkRemovingPasswordWithEmptyString(): void { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Cannot enable sending the password by Talk with an empty password'); + + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'getShareById', + 'generalCreateChecks', + 'verifyPassword', + 'pathCreateChecks', + 'linkCreateChecks', + 'validateExpirationDateLink', + ]) + ->getMock(); + + $originalShare = $this->manager->newShare(); + $originalShare->setShareType(IShare::TYPE_EMAIL) + ->setPermissions(\OCP\Constants::PERMISSION_ALL) + ->setPassword('passwordHash') + ->setSendPasswordByTalk(false); + + $tomorrow = new \DateTime(); + $tomorrow->setTime(0, 0, 0); + $tomorrow->add(new \DateInterval('P1D')); + + $file = $this->createMock(File::class); + $file->method('getId')->willReturn(100); + + $share = $this->manager->newShare(); + $share->setProviderId('foo') + ->setId('42') + ->setShareType(IShare::TYPE_EMAIL) + ->setToken('token') + ->setSharedBy('owner') + ->setShareOwner('owner') + ->setPassword('') + ->setSendPasswordByTalk(true) + ->setExpirationDate($tomorrow) + ->setNode($file) + ->setPermissions(\OCP\Constants::PERMISSION_ALL); + + $manager->expects($this->once())->method('canShare')->willReturn(true); + $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); + $manager->expects($this->once())->method('generalCreateChecks')->with($share); + $manager->expects($this->once())->method('verifyPassword'); + $manager->expects($this->never())->method('pathCreateChecks'); + $manager->expects($this->once())->method('linkCreateChecks'); + $manager->expects($this->never())->method('validateExpirationDateLink'); + + // If the password is empty, we have nothing to hash + $this->hasher->expects($this->never()) + ->method('hash'); + + $this->defaultProvider->expects($this->never()) + ->method('update'); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_set_expiration_date', $hookListener, 'post'); + $hookListener->expects($this->never())->method('post'); + + $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_password', $hookListener2, 'post'); + $hookListener2->expects($this->never())->method('post'); + + $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_permissions', $hookListener3, 'post'); + $hookListener3->expects($this->never())->method('post'); + + $manager->updateShare($share); + } + + + public function testUpdateShareMailEnableSendPasswordByTalkWithPreviousPassword(): void { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Cannot enable sending the password by Talk without setting a new password'); + + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'getShareById', + 'generalCreateChecks', + 'verifyPassword', + 'pathCreateChecks', + 'linkCreateChecks', + 'validateExpirationDateLink', + ]) + ->getMock(); + + $originalShare = $this->manager->newShare(); + $originalShare->setShareType(IShare::TYPE_EMAIL) + ->setPermissions(\OCP\Constants::PERMISSION_ALL) + ->setPassword('password') + ->setSendPasswordByTalk(false); + + $tomorrow = new \DateTime(); + $tomorrow->setTime(0, 0, 0); + $tomorrow->add(new \DateInterval('P1D')); + + $file = $this->createMock(File::class); + $file->method('getId')->willReturn(100); + + $share = $this->manager->newShare(); + $share->setProviderId('foo') + ->setId('42') + ->setShareType(IShare::TYPE_EMAIL) + ->setToken('token') + ->setSharedBy('owner') + ->setShareOwner('owner') + ->setPassword('password') + ->setSendPasswordByTalk(true) + ->setExpirationDate($tomorrow) + ->setNode($file) + ->setPermissions(\OCP\Constants::PERMISSION_ALL); + + $manager->expects($this->once())->method('canShare')->willReturn(true); + $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); + $manager->expects($this->once())->method('generalCreateChecks')->with($share); + $manager->expects($this->never())->method('verifyPassword'); + $manager->expects($this->never())->method('pathCreateChecks'); + $manager->expects($this->once())->method('linkCreateChecks'); + $manager->expects($this->never())->method('validateExpirationDateLink'); + + // If the old & new passwords are the same, we don't do anything + $this->hasher->expects($this->never()) + ->method('verify'); + $this->hasher->expects($this->never()) + ->method('hash'); + + $this->defaultProvider->expects($this->never()) + ->method('update'); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_set_expiration_date', $hookListener, 'post'); + $hookListener->expects($this->never())->method('post'); + + $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_password', $hookListener2, 'post'); + $hookListener2->expects($this->never())->method('post'); + + $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_permissions', $hookListener3, 'post'); + $hookListener3->expects($this->never())->method('post'); + + $manager->updateShare($share); + } + + public function testUpdateShareMailDisableSendPasswordByTalkWithPreviousPassword(): void { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Cannot disable sending the password by Talk without setting a new password'); + + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'getShareById', + 'generalCreateChecks', + 'verifyPassword', + 'pathCreateChecks', + 'linkCreateChecks', + 'validateExpirationDateLink', + ]) + ->getMock(); + + $originalShare = $this->manager->newShare(); + $originalShare->setShareType(IShare::TYPE_EMAIL) + ->setPermissions(\OCP\Constants::PERMISSION_ALL) + ->setPassword('passwordHash') + ->setSendPasswordByTalk(true); + + $tomorrow = new \DateTime(); + $tomorrow->setTime(0, 0, 0); + $tomorrow->add(new \DateInterval('P1D')); + + $file = $this->createMock(File::class); + $file->method('getId')->willReturn(100); + + $share = $this->manager->newShare(); + $share->setProviderId('foo') + ->setId('42') + ->setShareType(IShare::TYPE_EMAIL) + ->setToken('token') + ->setSharedBy('owner') + ->setShareOwner('owner') + ->setPassword('passwordHash') + ->setSendPasswordByTalk(false) + ->setExpirationDate($tomorrow) + ->setNode($file) + ->setPermissions(\OCP\Constants::PERMISSION_ALL); + + $manager->expects($this->once())->method('canShare')->willReturn(true); + $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); + $manager->expects($this->once())->method('generalCreateChecks')->with($share); + $manager->expects($this->never())->method('verifyPassword'); + $manager->expects($this->never())->method('pathCreateChecks'); + $manager->expects($this->once())->method('linkCreateChecks'); + $manager->expects($this->never())->method('validateExpirationDateLink'); + + // If the old & new passwords are the same, we don't do anything + $this->hasher->expects($this->never()) + ->method('verify'); + $this->hasher->expects($this->never()) + ->method('hash'); + + $this->defaultProvider->expects($this->never()) + ->method('update'); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_set_expiration_date', $hookListener, 'post'); + $hookListener->expects($this->never())->method('post'); + + $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_password', $hookListener2, 'post'); + $hookListener2->expects($this->never())->method('post'); + + $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_permissions', $hookListener3, 'post'); + $hookListener3->expects($this->never())->method('post'); + + $manager->updateShare($share); + } + + public function testUpdateShareMailDisableSendPasswordByTalkWithoutChangingPassword(): void { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Cannot disable sending the password by Talk without setting a new password'); + + $manager = $this->createManagerMock() + ->setMethods([ + 'canShare', + 'getShareById', + 'generalCreateChecks', + 'verifyPassword', + 'pathCreateChecks', + 'linkCreateChecks', + 'validateExpirationDateLink', + ]) + ->getMock(); + + $originalShare = $this->manager->newShare(); + $originalShare->setShareType(IShare::TYPE_EMAIL) + ->setPermissions(\OCP\Constants::PERMISSION_ALL) + ->setPassword('passwordHash') + ->setSendPasswordByTalk(true); + + $tomorrow = new \DateTime(); + $tomorrow->setTime(0, 0, 0); + $tomorrow->add(new \DateInterval('P1D')); + + $file = $this->createMock(File::class); + $file->method('getId')->willReturn(100); + + $share = $this->manager->newShare(); + $share->setProviderId('foo') + ->setId('42') + ->setShareType(IShare::TYPE_EMAIL) + ->setToken('token') + ->setSharedBy('owner') + ->setShareOwner('owner') + ->setPassword('passwordHash') + ->setSendPasswordByTalk(false) + ->setExpirationDate($tomorrow) + ->setNode($file) + ->setPermissions(\OCP\Constants::PERMISSION_ALL); + + $manager->expects($this->once())->method('canShare')->willReturn(true); + $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare); + $manager->expects($this->once())->method('generalCreateChecks')->with($share); + $manager->expects($this->never())->method('verifyPassword'); + $manager->expects($this->never())->method('pathCreateChecks'); + $manager->expects($this->once())->method('linkCreateChecks'); + $manager->expects($this->never())->method('validateExpirationDateLink'); + + // If the old & new passwords are the same, we don't do anything + $this->hasher->expects($this->never()) + ->method('verify'); + $this->hasher->expects($this->never()) + ->method('hash'); + + $this->defaultProvider->expects($this->never()) + ->method('update'); + + $hookListener = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_set_expiration_date', $hookListener, 'post'); + $hookListener->expects($this->never())->method('post'); + + $hookListener2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_password', $hookListener2, 'post'); + $hookListener2->expects($this->never())->method('post'); + + $hookListener3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock(); + \OCP\Util::connectHook(\OCP\Share::class, 'post_update_permissions', $hookListener3, 'post'); + $hookListener3->expects($this->never())->method('post'); + + $manager->updateShare($share); + } + + public function testMoveShareLink(): void { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Cannot change target of link share'); + + $share = $this->manager->newShare(); + $share->setShareType(IShare::TYPE_LINK); + + $recipient = $this->createMock(IUser::class); + + $this->manager->moveShare($share, $recipient); + } + + + public function testMoveShareUserNotRecipient(): void { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid recipient'); + + $share = $this->manager->newShare(); + $share->setShareType(IShare::TYPE_USER); + + $share->setSharedWith('sharedWith'); + + $this->manager->moveShare($share, 'recipient'); + } + + public function testMoveShareUser(): void { + $share = $this->manager->newShare(); + $share->setShareType(IShare::TYPE_USER) + ->setId('42') + ->setProviderId('foo'); + + $share->setSharedWith('recipient'); + + $this->defaultProvider->method('move')->with($share, 'recipient')->willReturnArgument(0); + + $this->manager->moveShare($share, 'recipient'); + $this->addToAssertionCount(1); + } + + + public function testMoveShareGroupNotRecipient(): void { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid recipient'); + + $share = $this->manager->newShare(); + $share->setShareType(IShare::TYPE_GROUP); + + $sharedWith = $this->createMock(IGroup::class); + $share->setSharedWith('shareWith'); + + $recipient = $this->createMock(IUser::class); + $sharedWith->method('inGroup')->with($recipient)->willReturn(false); + + $this->groupManager->method('get')->with('shareWith')->willReturn($sharedWith); + $this->userManager->method('get')->with('recipient')->willReturn($recipient); + + $this->manager->moveShare($share, 'recipient'); + } + + + public function testMoveShareGroupNull(): void { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Group "shareWith" does not exist'); + + $share = $this->manager->newShare(); + $share->setShareType(IShare::TYPE_GROUP); + $share->setSharedWith('shareWith'); + + $recipient = $this->createMock(IUser::class); + + $this->groupManager->method('get')->with('shareWith')->willReturn(null); + $this->userManager->method('get')->with('recipient')->willReturn($recipient); + + $this->manager->moveShare($share, 'recipient'); + } + + public function testMoveShareGroup(): void { + $share = $this->manager->newShare(); + $share->setShareType(IShare::TYPE_GROUP) + ->setId('42') + ->setProviderId('foo'); + + $group = $this->createMock(IGroup::class); + $share->setSharedWith('group'); + + $recipient = $this->createMock(IUser::class); + $group->method('inGroup')->with($recipient)->willReturn(true); + + $this->groupManager->method('get')->with('group')->willReturn($group); + $this->userManager->method('get')->with('recipient')->willReturn($recipient); + + $this->defaultProvider->method('move')->with($share, 'recipient')->willReturnArgument(0); + + $this->manager->moveShare($share, 'recipient'); + $this->addToAssertionCount(1); + } + + /** + * @dataProvider dataTestShareProviderExists + */ + public function testShareProviderExists($shareType, $expected): void { + $factory = $this->getMockBuilder(\OCP\Share\IProviderFactory::class)->getMock(); + $factory->expects($this->any())->method('getProviderForType') + ->willReturnCallback(function ($id) { + if ($id === IShare::TYPE_USER) { + return true; + } + throw new Exception\ProviderException(); + }); + + $manager = $this->createManager($factory); + $this->assertSame($expected, + $manager->shareProviderExists($shareType) + ); + } + + public function dataTestShareProviderExists() { + return [ + [IShare::TYPE_USER, true], + [42, false], + ]; + } + + public function testGetSharesInFolder(): void { + $factory = new DummyFactory2($this->createMock(IServerContainer::class)); + + $manager = $this->createManager($factory); + + $factory->setProvider($this->defaultProvider); + $extraProvider = $this->createMock(IShareProvider::class); + $factory->setSecondProvider($extraProvider); + + $share1 = $this->createMock(IShare::class); + $share2 = $this->createMock(IShare::class); + $share3 = $this->createMock(IShare::class); + $share4 = $this->createMock(IShare::class); + + $folder = $this->createMock(Folder::class); + + $this->defaultProvider->method('getSharesInFolder') + ->with( + $this->equalTo('user'), + $this->equalTo($folder), + $this->equalTo(false) + )->willReturn([ + 1 => [$share1], + 2 => [$share2], + ]); + + $extraProvider->method('getSharesInFolder') + ->with( + $this->equalTo('user'), + $this->equalTo($folder), + $this->equalTo(false) + )->willReturn([ + 2 => [$share3], + 3 => [$share4], + ]); + + $result = $manager->getSharesInFolder('user', $folder, false); + + $expects = [ + 1 => [$share1], + 2 => [$share2, $share3], + 3 => [$share4], + ]; + + $this->assertSame($expects, $result); + } + + public function testGetAccessList(): void { + $factory = new DummyFactory2($this->createMock(IServerContainer::class)); + + $manager = $this->createManager($factory); + + $factory->setProvider($this->defaultProvider); + $extraProvider = $this->createMock(IShareProvider::class); + $factory->setSecondProvider($extraProvider); + + $nodeOwner = $this->createMock(IUser::class); + $nodeOwner->expects($this->once()) + ->method('getUID') + ->willReturn('user1'); + + $node = $this->createMock(Node::class); + $node->expects($this->once()) + ->method('getOwner') + ->willReturn($nodeOwner); + $node->method('getId') + ->willReturn(42); + + $userFolder = $this->createMock(Folder::class); + $file = $this->createMock(File::class); + $folder = $this->createMock(Folder::class); + + $owner = $this->createMock(IUser::class); + $owner->expects($this->once()) + ->method('getUID') + ->willReturn('owner'); + + $file->method('getParent') + ->willReturn($folder); + $file->method('getPath') + ->willReturn('/owner/files/folder/file'); + $file->method('getOwner') + ->willReturn($owner); + $file->method('getId') + ->willReturn(23); + $folder->method('getParent') + ->willReturn($userFolder); + $folder->method('getPath') + ->willReturn('/owner/files/folder'); + $userFolder->method('getFirstNodeById') + ->with($this->equalTo(42)) + ->willReturn($file); + $userFolder->method('getPath') + ->willReturn('/user1/files'); + + $this->userManager->method('userExists') + ->with($this->equalTo('user1')) + ->willReturn(true); + + $this->defaultProvider->method('getAccessList') + ->with( + $this->equalTo([$file, $folder]), + false + ) + ->willReturn([ + 'users' => [ + 'user1', + 'user2', + 'user3', + '123456', + ], + 'public' => true, + ]); + + $extraProvider->method('getAccessList') + ->with( + $this->equalTo([$file, $folder]), + false + ) + ->willReturn([ + 'users' => [ + 'user3', + 'user4', + 'user5', + '234567', + ], + 'remote' => true, + ]); + + $this->rootFolder->method('getUserFolder') + ->with($this->equalTo('user1')) + ->willReturn($userFolder); + + $expected = [ + 'users' => ['owner', 'user1', 'user2', 'user3', '123456','user4', 'user5', '234567'], + 'remote' => true, + 'public' => true, + ]; + + $result = $manager->getAccessList($node, true, false); + + $this->assertSame($expected['public'], $result['public']); + $this->assertSame($expected['remote'], $result['remote']); + $this->assertSame($expected['users'], $result['users']); + } + + public function testGetAccessListWithCurrentAccess(): void { + $factory = new DummyFactory2($this->createMock(IServerContainer::class)); + + $manager = $this->createManager($factory); + + $factory->setProvider($this->defaultProvider); + $extraProvider = $this->createMock(IShareProvider::class); + $factory->setSecondProvider($extraProvider); + + $nodeOwner = $this->createMock(IUser::class); + $nodeOwner->expects($this->once()) + ->method('getUID') + ->willReturn('user1'); + + $node = $this->createMock(Node::class); + $node->expects($this->once()) + ->method('getOwner') + ->willReturn($nodeOwner); + $node->method('getId') + ->willReturn(42); + + $userFolder = $this->createMock(Folder::class); + $file = $this->createMock(File::class); + + $owner = $this->createMock(IUser::class); + $owner->expects($this->once()) + ->method('getUID') + ->willReturn('owner'); + $folder = $this->createMock(Folder::class); + + $file->method('getParent') + ->willReturn($folder); + $file->method('getPath') + ->willReturn('/owner/files/folder/file'); + $file->method('getOwner') + ->willReturn($owner); + $file->method('getId') + ->willReturn(23); + $folder->method('getParent') + ->willReturn($userFolder); + $folder->method('getPath') + ->willReturn('/owner/files/folder'); + $userFolder->method('getFirstNodeById') + ->with($this->equalTo(42)) + ->willReturn($file); + $userFolder->method('getPath') + ->willReturn('/user1/files'); + + $this->userManager->method('userExists') + ->with($this->equalTo('user1')) + ->willReturn(true); + + $this->defaultProvider->method('getAccessList') + ->with( + $this->equalTo([$file, $folder]), + true + ) + ->willReturn([ + 'users' => [ + 'user1' => [], + 'user2' => [], + 'user3' => [], + '123456' => [], + ], + 'public' => true, + ]); + + $extraProvider->method('getAccessList') + ->with( + $this->equalTo([$file, $folder]), + true + ) + ->willReturn([ + 'users' => [ + 'user3' => [], + 'user4' => [], + 'user5' => [], + '234567' => [], + ], + 'remote' => [ + 'remote1', + ], + ]); + + $this->rootFolder->method('getUserFolder') + ->with($this->equalTo('user1')) + ->willReturn($userFolder); + + $expected = [ + 'users' => [ + 'owner' => [ + 'node_id' => 23, + 'node_path' => '/folder/file' + ] + , 'user1' => [], 'user2' => [], 'user3' => [], '123456' => [], 'user4' => [], 'user5' => [], '234567' => []], + 'remote' => [ + 'remote1', + ], + 'public' => true, + ]; + + $result = $manager->getAccessList($node, true, true); + + $this->assertSame($expected['public'], $result['public']); + $this->assertSame($expected['remote'], $result['remote']); + $this->assertSame($expected['users'], $result['users']); + } + + public function testGetAllShares(): void { + $factory = new DummyFactory2($this->createMock(IServerContainer::class)); + + $manager = $this->createManager($factory); + + $factory->setProvider($this->defaultProvider); + $extraProvider = $this->createMock(IShareProvider::class); + $factory->setSecondProvider($extraProvider); + + $share1 = $this->createMock(IShare::class); + $share2 = $this->createMock(IShare::class); + $share3 = $this->createMock(IShare::class); + $share4 = $this->createMock(IShare::class); + + $this->defaultProvider->method('getAllShares') + ->willReturnCallback(function () use ($share1, $share2) { + yield $share1; + yield $share2; + }); + $extraProvider->method('getAllShares') + ->willReturnCallback(function () use ($share3, $share4) { + yield $share3; + yield $share4; + }); + + // "yield from", used in "getAllShares()", does not reset the keys, so + // "use_keys" has to be disabled to collect all the values while + // ignoring the keys returned by the generator. + $result = iterator_to_array($manager->getAllShares(), $use_keys = false); + + $expects = [$share1, $share2, $share3, $share4]; + + $this->assertSame($expects, $result); + } + + public function dataCurrentUserCanEnumerateTargetUser(): array { + return [ + 'Full match guest' => [true, true, false, false, false, false, false, true], + 'Full match user' => [false, true, false, false, false, false, false, true], + 'Enumeration off guest' => [true, false, false, false, false, false, false, false], + 'Enumeration off user' => [false, false, false, false, false, false, false, false], + 'Enumeration guest' => [true, false, true, false, false, false, false, true], + 'Enumeration user' => [false, false, true, false, false, false, false, true], + + // Restricted enumerations guests never works + 'Guest phone' => [true, false, true, true, false, false, false, false], + 'Guest group' => [true, false, true, false, true, false, false, false], + 'Guest both' => [true, false, true, true, true, false, false, false], + + // Restricted enumerations users + 'User phone but not known' => [false, false, true, true, false, false, false, false], + 'User phone known' => [false, false, true, true, false, true, false, true], + 'User group but no match' => [false, false, true, false, true, false, false, false], + 'User group with match' => [false, false, true, false, true, false, true, true], + ]; + } + + /** + * @dataProvider dataCurrentUserCanEnumerateTargetUser + * @param bool $expected + */ + public function testCurrentUserCanEnumerateTargetUser(bool $currentUserIsGuest, bool $allowEnumerationFullMatch, bool $allowEnumeration, bool $limitEnumerationToPhone, bool $limitEnumerationToGroups, bool $isKnownToUser, bool $haveCommonGroup, bool $expected): void { + /** @var IManager|MockObject $manager */ + $manager = $this->createManagerMock() + ->setMethods([ + 'allowEnumerationFullMatch', + 'allowEnumeration', + 'limitEnumerationToPhone', + 'limitEnumerationToGroups', + ]) + ->getMock(); + + $manager->method('allowEnumerationFullMatch') + ->willReturn($allowEnumerationFullMatch); + $manager->method('allowEnumeration') + ->willReturn($allowEnumeration); + $manager->method('limitEnumerationToPhone') + ->willReturn($limitEnumerationToPhone); + $manager->method('limitEnumerationToGroups') + ->willReturn($limitEnumerationToGroups); + + $this->knownUserService->method('isKnownToUser') + ->with('current', 'target') + ->willReturn($isKnownToUser); + + $currentUser = null; + if (!$currentUserIsGuest) { + $currentUser = $this->createMock(IUser::class); + $currentUser->method('getUID') + ->willReturn('current'); + } + $targetUser = $this->createMock(IUser::class); + $targetUser->method('getUID') + ->willReturn('target'); + + if ($haveCommonGroup) { + $this->groupManager->method('getUserGroupIds') + ->willReturnMap([ + [$targetUser, ['gid1', 'gid2']], + [$currentUser, ['gid2', 'gid3']], + ]); + } else { + $this->groupManager->method('getUserGroupIds') + ->willReturnMap([ + [$targetUser, ['gid1', 'gid2']], + [$currentUser, ['gid3', 'gid4']], + ]); + } + + $this->assertSame($expected, $manager->currentUserCanEnumerateTargetUser($currentUser, $targetUser)); + } +} + +class DummyFactory implements IProviderFactory { + /** @var IShareProvider */ + protected $provider; + + public function __construct(\OCP\IServerContainer $serverContainer) { + } + + /** + * @param IShareProvider $provider + */ + public function setProvider($provider) { + $this->provider = $provider; + } + + /** + * @param string $id + * @return IShareProvider + */ + public function getProvider($id) { + return $this->provider; + } + + /** + * @param int $shareType + * @return IShareProvider + */ + public function getProviderForType($shareType) { + return $this->provider; + } + + /** + * @return IShareProvider[] + */ + public function getAllProviders() { + return [$this->provider]; + } + + public function registerProvider(string $shareProvier): void { + } +} + +class DummyFactory2 extends DummyFactory { + /** @var IShareProvider */ + private $provider2; + + /** + * @param IShareProvider $provider + */ + public function setSecondProvider($provider) { + $this->provider2 = $provider; + } + + public function getAllProviders() { + return [$this->provider, $this->provider2]; + } + + public function registerProvider(string $shareProvier): void { + } +} diff --git a/tests/lib/Template/ResourceLocatorTest.php b/tests/lib/Template/ResourceLocatorTest.php index 65d4c7938f9..d308968d861 100644 --- a/tests/lib/Template/ResourceLocatorTest.php +++ b/tests/lib/Template/ResourceLocatorTest.php @@ -32,7 +32,7 @@ class ResourceLocatorTest extends \Test\TestCase { ->with('theme', '') ->willReturn($theme); $this->overwriteService(SystemConfig::class, $systemConfig); - return $this->getMockForAbstractClass('OC\Template\ResourceLocator', + return $this->getMockForAbstractClass(\OC\Template\ResourceLocator::class, [$this->logger], '', true, true, true, []); } diff --git a/tests/lib/TestCase.php b/tests/lib/TestCase.php index 9369a20eb81..460e695f7dc 100644 --- a/tests/lib/TestCase.php +++ b/tests/lib/TestCase.php @@ -534,7 +534,7 @@ abstract class TestCase extends \PHPUnit\Framework\TestCase { $requestToken = 12345; /** @var Defaults|\PHPUnit\Framework\MockObject\MockObject $l10n */ - $theme = $this->getMockBuilder('\OCP\Defaults') + $theme = $this->getMockBuilder(\OCP\Defaults::class) ->disableOriginalConstructor()->getMock(); $theme->expects($this->any()) ->method('getName') diff --git a/tests/lib/Traits/MountProviderTrait.php b/tests/lib/Traits/MountProviderTrait.php index 6d947d645dd..c957379aa3c 100644 --- a/tests/lib/Traits/MountProviderTrait.php +++ b/tests/lib/Traits/MountProviderTrait.php @@ -46,7 +46,7 @@ trait MountProviderTrait { protected function setUpMountProviderTrait() { $this->storageFactory = new StorageFactory(); - $this->mountProvider = $this->getMockBuilder('\OCP\Files\Config\IMountProvider')->getMock(); + $this->mountProvider = $this->getMockBuilder(\OCP\Files\Config\IMountProvider::class)->getMock(); $this->mountProvider->expects($this->any()) ->method('getMountsForUser') ->will($this->returnCallback(function (IUser $user) { diff --git a/tests/lib/Updater/ReleaseMetadataTest.php b/tests/lib/Updater/ReleaseMetadataTest.php index 72c6da5064d..87961613ce6 100644 --- a/tests/lib/Updater/ReleaseMetadataTest.php +++ b/tests/lib/Updater/ReleaseMetadataTest.php @@ -100,14 +100,14 @@ class ReleaseMetadataTest extends \Test\TestCase { 'apps' => [ 'testing' => [ '30000Date20240102030405' => [ - 'class' => 'OCP\\Migration\\Attributes\\DropTable', + 'class' => \OCP\Migration\Attributes\DropTable::class, 'table' => 'old_table', 'description' => '', 'notes' => [], 'columns' => [] ], [ - 'class' => 'OCP\\Migration\\Attributes\\CreateTable', + 'class' => \OCP\Migration\Attributes\CreateTable::class, 'table' => 'new_table', 'description' => 'Table is used to store things, but also to get more things', 'notes' => [ @@ -117,7 +117,7 @@ class ReleaseMetadataTest extends \Test\TestCase { 'columns' => [] ], [ - 'class' => 'OCP\\Migration\\Attributes\\AddColumn', + 'class' => \OCP\Migration\Attributes\AddColumn::class, 'table' => 'my_table', 'description' => '', 'notes' => [], @@ -125,7 +125,7 @@ class ReleaseMetadataTest extends \Test\TestCase { 'type' => '' ], [ - 'class' => 'OCP\\Migration\\Attributes\\AddColumn', + 'class' => \OCP\Migration\Attributes\AddColumn::class, 'table' => 'my_table', 'description' => '', 'notes' => [], @@ -133,7 +133,7 @@ class ReleaseMetadataTest extends \Test\TestCase { 'type' => '' ], [ - 'class' => 'OCP\\Migration\\Attributes\\AddColumn', + 'class' => \OCP\Migration\Attributes\AddColumn::class, 'table' => 'other_table', 'description' => '', 'notes' => [], @@ -141,21 +141,21 @@ class ReleaseMetadataTest extends \Test\TestCase { 'type' => 'date' ], [ - 'class' => 'OCP\\Migration\\Attributes\\AddIndex', + 'class' => \OCP\Migration\Attributes\AddIndex::class, 'table' => 'my_table', 'description' => '', 'notes' => [], 'type' => '' ], [ - 'class' => 'OCP\\Migration\\Attributes\\AddIndex', + 'class' => \OCP\Migration\Attributes\AddIndex::class, 'table' => 'my_table', 'description' => '', 'notes' => [], 'type' => 'primary' ], [ - 'class' => 'OCP\\Migration\\Attributes\\DropColumn', + 'class' => \OCP\Migration\Attributes\DropColumn::class, 'table' => 'other_table', 'description' => '', 'notes' => [], @@ -163,7 +163,7 @@ class ReleaseMetadataTest extends \Test\TestCase { 'type' => '' ], [ - 'class' => 'OCP\\Migration\\Attributes\\DropColumn', + 'class' => \OCP\Migration\Attributes\DropColumn::class, 'table' => 'other_table', 'description' => 'field is not used anymore and replaced by \'last_one\'', 'notes' => [], @@ -171,14 +171,14 @@ class ReleaseMetadataTest extends \Test\TestCase { 'type' => '' ], [ - 'class' => 'OCP\\Migration\\Attributes\\DropIndex', + 'class' => \OCP\Migration\Attributes\DropIndex::class, 'table' => 'other_table', 'description' => '', 'notes' => [], 'type' => '' ], [ - 'class' => 'OCP\\Migration\\Attributes\\ModifyColumn', + 'class' => \OCP\Migration\Attributes\ModifyColumn::class, 'table' => 'other_table', 'description' => '', 'notes' => [], @@ -186,7 +186,7 @@ class ReleaseMetadataTest extends \Test\TestCase { 'type' => '' ], [ - 'class' => 'OCP\\Migration\\Attributes\\ModifyColumn', + 'class' => \OCP\Migration\Attributes\ModifyColumn::class, 'table' => 'other_table', 'description' => '', 'notes' => [], @@ -194,7 +194,7 @@ class ReleaseMetadataTest extends \Test\TestCase { 'type' => '' ], [ - 'class' => 'OCP\\Migration\\Attributes\\ModifyColumn', + 'class' => \OCP\Migration\Attributes\ModifyColumn::class, 'table' => 'other_table', 'description' => '', 'notes' => [], diff --git a/tests/lib/UtilCheckServerTest.php b/tests/lib/UtilCheckServerTest.php index ca4cd7d108f..b8351a5d2b3 100644 --- a/tests/lib/UtilCheckServerTest.php +++ b/tests/lib/UtilCheckServerTest.php @@ -22,7 +22,7 @@ class UtilCheckServerTest extends \Test\TestCase { protected function getConfig($systemOptions) { $systemOptions['datadirectory'] = $this->datadir; $systemOptions['appstoreenabled'] = false; //it's likely that there is no app folder we can write in - $config = $this->getMockBuilder('\OC\SystemConfig') + $config = $this->getMockBuilder(\OC\SystemConfig::class) ->disableOriginalConstructor() ->getMock(); diff --git a/tests/preseed-config.php b/tests/preseed-config.php index f9c15939469..6a0d17f5bcb 100644 --- a/tests/preseed-config.php +++ b/tests/preseed-config.php @@ -25,7 +25,7 @@ if (is_dir(OC::$SERVERROOT.'/apps2')) { if (getenv('OBJECT_STORE') === 's3') { $CONFIG['objectstore'] = [ - 'class' => 'OC\\Files\\ObjectStore\\S3', + 'class' => \OC\Files\ObjectStore\S3::class, 'arguments' => [ 'bucket' => 'nextcloud', 'autocreate' => true, @@ -40,7 +40,7 @@ if (getenv('OBJECT_STORE') === 's3') { ]; } elseif (getenv('OBJECT_STORE') === 'azure') { $CONFIG['objectstore'] = [ - 'class' => 'OC\\Files\\ObjectStore\\Azure', + 'class' => \OC\Files\ObjectStore\Azure::class, 'arguments' => [ 'container' => 'test', 'account_name' => getenv('OBJECT_STORE_KEY') ?: 'devstoreaccount1', @@ -53,7 +53,7 @@ if (getenv('OBJECT_STORE') === 's3') { $swiftHost = getenv('OBJECT_STORE_HOST') ?: 'localhost:5000'; $CONFIG['objectstore'] = [ - 'class' => 'OC\\Files\\ObjectStore\\Swift', + 'class' => \OC\Files\ObjectStore\Swift::class, 'arguments' => [ 'autocreate' => true, 'user' => [ diff --git a/tests/redis-cluster.config.php b/tests/redis-cluster.config.php index d9951218384..c8226ddcbc7 100644 --- a/tests/redis-cluster.config.php +++ b/tests/redis-cluster.config.php @@ -4,9 +4,9 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ $CONFIG = [ - 'memcache.local' => '\\OC\\Memcache\\Redis', - 'memcache.distributed' => '\\OC\\Memcache\\Redis', - 'memcache.locking' => '\\OC\\Memcache\\Redis', + 'memcache.local' => \OC\Memcache\Redis::class, + 'memcache.distributed' => \OC\Memcache\Redis::class, + 'memcache.locking' => \OC\Memcache\Redis::class, 'redis.cluster' => [ 'seeds' => [ // provide some/all of the cluster servers to bootstrap discovery, port required 'cache-cluster:7000', diff --git a/tests/redis.config.php b/tests/redis.config.php index 9068d1ad3d5..5d3219cab4b 100644 --- a/tests/redis.config.php +++ b/tests/redis.config.php @@ -4,9 +4,9 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ $CONFIG = [ - 'memcache.local' => '\\OC\\Memcache\\Redis', - 'memcache.distributed' => '\\OC\\Memcache\\Redis', - 'memcache.locking' => '\\OC\\Memcache\\Redis', + 'memcache.local' => \OC\Memcache\Redis::class, + 'memcache.distributed' => \OC\Memcache\Redis::class, + 'memcache.locking' => \OC\Memcache\Redis::class, 'redis' => [ 'host' => 'localhost', 'port' => 6379, |