diff options
Diffstat (limited to 'tests/lib')
-rw-r--r-- | tests/lib/App/AppManagerTest.php | 71 | ||||
-rw-r--r-- | tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php | 262 | ||||
-rw-r--r-- | tests/lib/AppTest.php | 4 | ||||
-rw-r--r-- | tests/lib/Authentication/Token/ManagerTest.php | 44 | ||||
-rw-r--r-- | tests/lib/Preview/BackgroundCleanupJobTest.php | 4 | ||||
-rw-r--r-- | tests/lib/Security/CredentialsManagerTest.php | 23 | ||||
-rw-r--r-- | tests/lib/Security/RateLimiting/Backend/MemoryCacheBackendTest.php | 9 | ||||
-rw-r--r-- | tests/lib/SystemTag/SystemTagObjectMapperTest.php | 21 | ||||
-rw-r--r-- | tests/lib/Template/JSResourceLocatorTest.php | 76 | ||||
-rw-r--r-- | tests/lib/TemplateFunctionsTest.php | 29 | ||||
-rw-r--r-- | tests/lib/UrlGeneratorTest.php | 80 | ||||
-rw-r--r-- | tests/lib/User/SessionTest.php | 97 |
12 files changed, 558 insertions, 162 deletions
diff --git a/tests/lib/App/AppManagerTest.php b/tests/lib/App/AppManagerTest.php index de515837406..3518ada3314 100644 --- a/tests/lib/App/AppManagerTest.php +++ b/tests/lib/App/AppManagerTest.php @@ -14,7 +14,10 @@ namespace Test\App; use OC\App\AppManager; use OC\AppConfig; use OCP\App\AppPathNotFoundException; +use OCP\App\Events\AppDisableEvent; +use OCP\App\Events\AppEnableEvent; use OCP\App\IAppManager; +use OCP\EventDispatcher\IEventDispatcher; use OCP\ICache; use OCP\ICacheFactory; use OCP\IConfig; @@ -91,6 +94,9 @@ class AppManagerTest extends TestCase { protected $cacheFactory; /** @var EventDispatcherInterface|MockObject */ + protected $legacyEventDispatcher; + + /** @var IEventDispatcher|MockObject */ protected $eventDispatcher; /** @var LoggerInterface|MockObject */ @@ -108,7 +114,8 @@ class AppManagerTest extends TestCase { $this->appConfig = $this->getAppConfig(); $this->cacheFactory = $this->createMock(ICacheFactory::class); $this->cache = $this->createMock(ICache::class); - $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class); + $this->legacyEventDispatcher = $this->createMock(EventDispatcherInterface::class); + $this->eventDispatcher = $this->createMock(IEventDispatcher::class); $this->logger = $this->createMock(LoggerInterface::class); $this->cacheFactory->expects($this->any()) ->method('createDistributed') @@ -120,6 +127,7 @@ class AppManagerTest extends TestCase { $this->appConfig, $this->groupManager, $this->cacheFactory, + $this->legacyEventDispatcher, $this->eventDispatcher, $this->logger ); @@ -137,12 +145,14 @@ class AppManagerTest extends TestCase { if ($this->manager->isEnabledForUser('files_trashbin')) { $this->manager->disableApp('files_trashbin'); } + $this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppEnableEvent('files_trashbin')); $this->manager->enableApp('files_trashbin'); $this->assertEquals('yes', $this->appConfig->getValue('files_trashbin', 'enabled', 'no')); } public function testDisableApp() { $this->expectClearCache(); + $this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppDisableEvent('files_trashbin')); $this->manager->disableApp('files_trashbin'); $this->assertEquals('no', $this->appConfig->getValue('files_trashbin', 'enabled', 'no')); } @@ -175,7 +185,7 @@ class AppManagerTest extends TestCase { /** @var AppManager|MockObject $manager */ $manager = $this->getMockBuilder(AppManager::class) ->setConstructorArgs([ - $this->userSession, $this->config, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher, $this->logger + $this->userSession, $this->config, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->legacyEventDispatcher, $this->eventDispatcher, $this->logger ]) ->setMethods([ 'getAppPath', @@ -187,6 +197,8 @@ class AppManagerTest extends TestCase { ->with('test') ->willReturn('apps/test'); + $this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppEnableEvent('test', ['group1', 'group2'])); + $manager->enableAppForGroups('test', $groups); $this->assertEquals('["group1","group2"]', $this->appConfig->getValue('test', 'enabled', 'no')); } @@ -222,7 +234,7 @@ class AppManagerTest extends TestCase { /** @var AppManager|MockObject $manager */ $manager = $this->getMockBuilder(AppManager::class) ->setConstructorArgs([ - $this->userSession, $this->config, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher, $this->logger + $this->userSession, $this->config, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->legacyEventDispatcher, $this->eventDispatcher, $this->logger ]) ->setMethods([ 'getAppPath', @@ -240,6 +252,8 @@ class AppManagerTest extends TestCase { ->with('test') ->willReturn($appInfo); + $this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppEnableEvent('test', ['group1', 'group2'])); + $manager->enableAppForGroups('test', $groups); $this->assertEquals('["group1","group2"]', $this->appConfig->getValue('test', 'enabled', 'no')); } @@ -276,7 +290,7 @@ class AppManagerTest extends TestCase { /** @var AppManager|MockObject $manager */ $manager = $this->getMockBuilder(AppManager::class) ->setConstructorArgs([ - $this->userSession, $this->config, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher, $this->logger + $this->userSession, $this->config, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->legacyEventDispatcher, $this->eventDispatcher, $this->logger ]) ->setMethods([ 'getAppPath', @@ -296,6 +310,8 @@ class AppManagerTest extends TestCase { 'types' => [$type], ]); + $this->eventDispatcher->expects($this->never())->method('dispatchTyped')->with(new AppEnableEvent('test', ['group1', 'group2'])); + $manager->enableAppForGroups('test', $groups); } @@ -470,7 +486,7 @@ class AppManagerTest extends TestCase { public function testGetAppsNeedingUpgrade() { /** @var AppManager|MockObject $manager */ $manager = $this->getMockBuilder(AppManager::class) - ->setConstructorArgs([$this->userSession, $this->config, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher, $this->logger]) + ->setConstructorArgs([$this->userSession, $this->config, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->legacyEventDispatcher, $this->eventDispatcher, $this->logger]) ->setMethods(['getAppInfo']) ->getMock(); @@ -521,7 +537,7 @@ class AppManagerTest extends TestCase { public function testGetIncompatibleApps() { /** @var AppManager|MockObject $manager */ $manager = $this->getMockBuilder(AppManager::class) - ->setConstructorArgs([$this->userSession, $this->config, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher, $this->logger]) + ->setConstructorArgs([$this->userSession, $this->config, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->legacyEventDispatcher, $this->eventDispatcher, $this->logger]) ->setMethods(['getAppInfo']) ->getMock(); @@ -601,4 +617,47 @@ class AppManagerTest extends TestCase { $this->assertEquals([], $this->manager->getAppRestriction('test2')); $this->assertEquals(['foo'], $this->manager->getAppRestriction('test3')); } + + public function provideDefaultApps(): array { + return [ + // none specified, default to files + [ + '', + 'files', + ], + // unexisting or inaccessible app specified, default to files + [ + 'unexist', + 'files', + ], + // non-standard app + [ + 'settings', + 'settings', + ], + // non-standard app with fallback + [ + 'unexist,settings', + 'settings', + ], + ]; + } + + /** + * @dataProvider provideDefaultApps + */ + public function testGetDefaultAppForUser($defaultApps, $expectedApp) { + $user = $this->newUser('user1'); + + $this->userSession->expects($this->once()) + ->method('getUser') + ->willReturn($user); + + $this->config->expects($this->once()) + ->method('getSystemValueString') + ->with('defaultapp', $this->anything()) + ->willReturn($defaultApps); + + $this->assertEquals($expectedApp, $this->manager->getDefaultAppForUser()); + } } diff --git a/tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php index 7dfcfe22261..388b2fbf534 100644 --- a/tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php +++ b/tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php @@ -1,5 +1,6 @@ <?php /** + * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com> * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> * * @license GNU AGPL version 3 or any later version @@ -25,44 +26,60 @@ use OC\AppFramework\Middleware\Security\BruteForceMiddleware; use OC\AppFramework\Utility\ControllerMethodReflector; use OC\Security\Bruteforce\Throttler; use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Attribute\BruteForceProtection; use OCP\AppFramework\Http\Response; use OCP\IRequest; +use Psr\Log\LoggerInterface; use Test\TestCase; +class TestController extends Controller { + /** + * @BruteForceProtection(action=login) + */ + public function testMethodWithAnnotation() { + } + + public function testMethodWithoutAnnotation() { + } + + #[BruteForceProtection(action: 'single')] + public function singleAttribute(): void { + } + + #[BruteForceProtection(action: 'first')] + #[BruteForceProtection(action: 'second')] + public function multipleAttributes(): void { + } +} + class BruteForceMiddlewareTest extends TestCase { - /** @var ControllerMethodReflector|\PHPUnit\Framework\MockObject\MockObject */ + /** @var ControllerMethodReflector */ private $reflector; /** @var Throttler|\PHPUnit\Framework\MockObject\MockObject */ private $throttler; /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */ private $request; + /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */ + private $logger; private BruteForceMiddleware $bruteForceMiddleware; protected function setUp(): void { parent::setUp(); - $this->reflector = $this->createMock(ControllerMethodReflector::class); + $this->reflector = new ControllerMethodReflector(); $this->throttler = $this->createMock(Throttler::class); $this->request = $this->createMock(IRequest::class); + $this->logger = $this->createMock(LoggerInterface::class); $this->bruteForceMiddleware = new BruteForceMiddleware( $this->reflector, $this->throttler, - $this->request + $this->request, + $this->logger, ); } - public function testBeforeControllerWithAnnotation() { - $this->reflector - ->expects($this->once()) - ->method('hasAnnotation') - ->with('BruteForceProtection') - ->willReturn(true); - $this->reflector - ->expects($this->once()) - ->method('getAnnotationParameter') - ->with('BruteForceProtection', 'action') - ->willReturn('login'); + public function testBeforeControllerWithAnnotation(): void { $this->request ->expects($this->once()) ->method('getRemoteAddress') @@ -72,20 +89,45 @@ class BruteForceMiddlewareTest extends TestCase { ->method('sleepDelayOrThrowOnMax') ->with('127.0.0.1', 'login'); - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */ - $controller = $this->createMock(Controller::class); - $this->bruteForceMiddleware->beforeController($controller, 'testMethod'); + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'testMethodWithAnnotation'); + $this->bruteForceMiddleware->beforeController($controller, 'testMethodWithAnnotation'); } - public function testBeforeControllerWithoutAnnotation() { - $this->reflector + public function testBeforeControllerWithSingleAttribute(): void { + $this->request ->expects($this->once()) - ->method('hasAnnotation') - ->with('BruteForceProtection') - ->willReturn(false); - $this->reflector - ->expects($this->never()) - ->method('getAnnotationParameter'); + ->method('getRemoteAddress') + ->willReturn('::1'); + $this->throttler + ->expects($this->once()) + ->method('sleepDelayOrThrowOnMax') + ->with('::1', 'single'); + + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'singleAttribute'); + $this->bruteForceMiddleware->beforeController($controller, 'singleAttribute'); + } + + public function testBeforeControllerWithMultipleAttributes(): void { + $this->request + ->expects($this->once()) + ->method('getRemoteAddress') + ->willReturn('::1'); + $this->throttler + ->expects($this->exactly(2)) + ->method('sleepDelayOrThrowOnMax') + ->withConsecutive( + ['::1', 'first'], + ['::1', 'second'], + ); + + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'multipleAttributes'); + $this->bruteForceMiddleware->beforeController($controller, 'multipleAttributes'); + } + + public function testBeforeControllerWithoutAnnotation(): void { $this->request ->expects($this->never()) ->method('getRemoteAddress'); @@ -93,19 +135,14 @@ class BruteForceMiddlewareTest extends TestCase { ->expects($this->never()) ->method('sleepDelayOrThrowOnMax'); - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */ - $controller = $this->createMock(Controller::class); - $this->bruteForceMiddleware->beforeController($controller, 'testMethod'); + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'testMethodWithoutAnnotation'); + $this->bruteForceMiddleware->beforeController($controller, 'testMethodWithoutAnnotation'); } - public function testAfterControllerWithAnnotationAndThrottledRequest() { + public function testAfterControllerWithAnnotationAndThrottledRequest(): void { /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */ $response = $this->createMock(Response::class); - $this->reflector - ->expects($this->once()) - ->method('hasAnnotation') - ->with('BruteForceProtection') - ->willReturn(true); $response ->expects($this->once()) ->method('isThrottled') @@ -114,11 +151,6 @@ class BruteForceMiddlewareTest extends TestCase { ->expects($this->once()) ->method('getThrottleMetadata') ->willReturn([]); - $this->reflector - ->expects($this->once()) - ->method('getAnnotationParameter') - ->with('BruteForceProtection', 'action') - ->willReturn('login'); $this->request ->expects($this->once()) ->method('getRemoteAddress') @@ -132,26 +164,18 @@ class BruteForceMiddlewareTest extends TestCase { ->method('registerAttempt') ->with('login', '127.0.0.1'); - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */ - $controller = $this->createMock(Controller::class); - $this->bruteForceMiddleware->afterController($controller, 'testMethod', $response); + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'testMethodWithAnnotation'); + $this->bruteForceMiddleware->afterController($controller, 'testMethodWithAnnotation', $response); } - public function testAfterControllerWithAnnotationAndNotThrottledRequest() { + public function testAfterControllerWithAnnotationAndNotThrottledRequest(): void { /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */ $response = $this->createMock(Response::class); - $this->reflector - ->expects($this->once()) - ->method('hasAnnotation') - ->with('BruteForceProtection') - ->willReturn(true); $response ->expects($this->once()) ->method('isThrottled') ->willReturn(false); - $this->reflector - ->expects($this->never()) - ->method('getAnnotationParameter'); $this->request ->expects($this->never()) ->method('getRemoteAddress'); @@ -162,20 +186,123 @@ class BruteForceMiddlewareTest extends TestCase { ->expects($this->never()) ->method('registerAttempt'); - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */ - $controller = $this->createMock(Controller::class); - $this->bruteForceMiddleware->afterController($controller, 'testMethod', $response); + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'testMethodWithAnnotation'); + $this->bruteForceMiddleware->afterController($controller, 'testMethodWithAnnotation', $response); } - public function testAfterControllerWithoutAnnotation() { - $this->reflector + public function testAfterControllerWithSingleAttribute(): void { + /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */ + $response = $this->createMock(Response::class); + $response ->expects($this->once()) - ->method('hasAnnotation') - ->with('BruteForceProtection') - ->willReturn(false); - $this->reflector + ->method('isThrottled') + ->willReturn(true); + $response + ->expects($this->once()) + ->method('getThrottleMetadata') + ->willReturn([]); + + $this->request + ->expects($this->once()) + ->method('getRemoteAddress') + ->willReturn('::1'); + $this->throttler + ->expects($this->once()) + ->method('sleepDelay') + ->with('::1', 'single'); + $this->throttler + ->expects($this->once()) + ->method('registerAttempt') + ->with('single', '::1'); + + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'singleAttribute'); + $this->bruteForceMiddleware->afterController($controller, 'singleAttribute', $response); + } + + public function testAfterControllerWithMultipleAttributesGeneralMatch(): void { + /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */ + $response = $this->createMock(Response::class); + $response + ->expects($this->once()) + ->method('isThrottled') + ->willReturn(true); + $response + ->expects($this->once()) + ->method('getThrottleMetadata') + ->willReturn([]); + + $this->request + ->expects($this->once()) + ->method('getRemoteAddress') + ->willReturn('::1'); + $this->throttler + ->expects($this->exactly(2)) + ->method('sleepDelay') + ->withConsecutive( + ['::1', 'first'], + ['::1', 'second'], + ); + $this->throttler + ->expects($this->exactly(2)) + ->method('registerAttempt') + ->withConsecutive( + ['first', '::1'], + ['second', '::1'], + ); + + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'multipleAttributes'); + $this->bruteForceMiddleware->afterController($controller, 'multipleAttributes', $response); + } + + public function testAfterControllerWithMultipleAttributesSpecificMatch(): void { + /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */ + $response = $this->createMock(Response::class); + $response + ->expects($this->once()) + ->method('isThrottled') + ->willReturn(true); + $response + ->expects($this->once()) + ->method('getThrottleMetadata') + ->willReturn(['action' => 'second']); + + $this->request + ->expects($this->once()) + ->method('getRemoteAddress') + ->willReturn('::1'); + $this->throttler + ->expects($this->once()) + ->method('sleepDelay') + ->with('::1', 'second'); + $this->throttler + ->expects($this->once()) + ->method('registerAttempt') + ->with('second', '::1'); + + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'multipleAttributes'); + $this->bruteForceMiddleware->afterController($controller, 'multipleAttributes', $response); + } + + public function testAfterControllerWithoutAnnotation(): void { + $this->request ->expects($this->never()) - ->method('getAnnotationParameter'); + ->method('getRemoteAddress'); + $this->throttler + ->expects($this->never()) + ->method('sleepDelay'); + + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'testMethodWithoutAnnotation'); + /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */ + $response = $this->createMock(Response::class); + $this->bruteForceMiddleware->afterController($controller, 'testMethodWithoutAnnotation', $response); + } + + public function testAfterControllerWithThrottledResponseButUnhandled(): void { $this->request ->expects($this->never()) ->method('getRemoteAddress'); @@ -183,10 +310,17 @@ class BruteForceMiddlewareTest extends TestCase { ->expects($this->never()) ->method('sleepDelay'); - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */ - $controller = $this->createMock(Controller::class); + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'testMethodWithoutAnnotation'); /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */ $response = $this->createMock(Response::class); - $this->bruteForceMiddleware->afterController($controller, 'testMethod', $response); + $response->method('isThrottled') + ->willReturn(true); + + $this->logger->expects($this->once()) + ->method('debug') + ->with('Response for Test\AppFramework\Middleware\Security\TestController::testMethodWithoutAnnotation got bruteforce throttled but has no annotation nor attribute defined.'); + + $this->bruteForceMiddleware->afterController($controller, 'testMethodWithoutAnnotation', $response); } } diff --git a/tests/lib/AppTest.php b/tests/lib/AppTest.php index 4b2619a3761..5cdee5e1200 100644 --- a/tests/lib/AppTest.php +++ b/tests/lib/AppTest.php @@ -12,6 +12,7 @@ namespace Test; use OC\App\AppManager; use OC\App\InfoParser; use OC\AppConfig; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IAppConfig; use Psr\Log\LoggerInterface; @@ -553,13 +554,14 @@ class AppTest extends \Test\TestCase { */ private function registerAppConfig(AppConfig $appConfig) { $this->overwriteService(AppConfig::class, $appConfig); - $this->overwriteService(AppManager::class, new \OC\App\AppManager( + $this->overwriteService(AppManager::class, new AppManager( \OC::$server->getUserSession(), \OC::$server->getConfig(), $appConfig, \OC::$server->getGroupManager(), \OC::$server->getMemCacheFactory(), \OC::$server->getEventDispatcher(), + \OC::$server->get(IEventDispatcher::class), \OC::$server->get(LoggerInterface::class) )); } diff --git a/tests/lib/Authentication/Token/ManagerTest.php b/tests/lib/Authentication/Token/ManagerTest.php index 5f024bb1d43..de3e5e1c362 100644 --- a/tests/lib/Authentication/Token/ManagerTest.php +++ b/tests/lib/Authentication/Token/ManagerTest.php @@ -355,4 +355,48 @@ class ManagerTest extends TestCase { $this->manager->updatePasswords('uid', 'pass'); } + + public function testInvalidateTokensOfUserNoClientName() { + $t1 = new PublicKeyToken(); + $t2 = new PublicKeyToken(); + $t1->setId(123); + $t2->setId(456); + + $this->publicKeyTokenProvider + ->expects($this->once()) + ->method('getTokenByUser') + ->with('theUser') + ->willReturn([$t1, $t2]); + $this->publicKeyTokenProvider + ->expects($this->exactly(2)) + ->method('invalidateTokenById') + ->withConsecutive( + ['theUser', 123], + ['theUser', 456], + ); + $this->manager->invalidateTokensOfUser('theUser', null); + } + + public function testInvalidateTokensOfUserClientNameGiven() { + $t1 = new PublicKeyToken(); + $t2 = new PublicKeyToken(); + $t3 = new PublicKeyToken(); + $t1->setId(123); + $t1->setName('Firefox session'); + $t2->setId(456); + $t2->setName('My Client Name'); + $t3->setId(789); + $t3->setName('mobile client'); + + $this->publicKeyTokenProvider + ->expects($this->once()) + ->method('getTokenByUser') + ->with('theUser') + ->willReturn([$t1, $t2, $t3]); + $this->publicKeyTokenProvider + ->expects($this->once()) + ->method('invalidateTokenById') + ->with('theUser', 456); + $this->manager->invalidateTokensOfUser('theUser', 'My Client Name'); + } } diff --git a/tests/lib/Preview/BackgroundCleanupJobTest.php b/tests/lib/Preview/BackgroundCleanupJobTest.php index c1c225bd179..aa15ea7f562 100644 --- a/tests/lib/Preview/BackgroundCleanupJobTest.php +++ b/tests/lib/Preview/BackgroundCleanupJobTest.php @@ -69,7 +69,7 @@ class BackgroundCleanupJobTest extends \Test\TestCase { parent::setUp(); $this->userId = $this->getUniqueID(); - $this->createUser($this->userId, $this->userId); + $user = $this->createUser($this->userId, $this->userId); $storage = new \OC\Files\Storage\Temporary([]); $this->registerMount($this->userId, $storage, ''); @@ -79,7 +79,7 @@ class BackgroundCleanupJobTest extends \Test\TestCase { $this->loginAsUser($this->userId); $appManager = \OC::$server->getAppManager(); - $this->trashEnabled = $appManager->isEnabledForUser('files_trashbin', $this->userId); + $this->trashEnabled = $appManager->isEnabledForUser('files_trashbin', $user); $appManager->disableApp('files_trashbin'); $this->connection = \OC::$server->getDatabaseConnection(); diff --git a/tests/lib/Security/CredentialsManagerTest.php b/tests/lib/Security/CredentialsManagerTest.php index 6f535c84275..bb4feb8b6a9 100644 --- a/tests/lib/Security/CredentialsManagerTest.php +++ b/tests/lib/Security/CredentialsManagerTest.php @@ -24,6 +24,9 @@ declare(strict_types=1); namespace Test\Security; +use OCP\Security\ICredentialsManager; +use OCP\Server; + /** * @group DB */ @@ -32,7 +35,7 @@ class CredentialsManagerTest extends \Test\TestCase { * @dataProvider credentialsProvider */ public function testWithDB($userId, $identifier) { - $credentialsManager = \OC::$server->getCredentialsManager(); + $credentialsManager = Server::get(ICredentialsManager::class); $secrets = 'Open Sesame'; @@ -45,7 +48,23 @@ class CredentialsManagerTest extends \Test\TestCase { $this->assertSame(1, $removedRows); } - public function credentialsProvider() { + /** + * @dataProvider credentialsProvider + */ + public function testUpdate($userId, $identifier): void { + $credentialsManager = Server::get(ICredentialsManager::class); + + $secrets = 'Open Sesame'; + $secretsRev = strrev($secrets); + + $credentialsManager->store($userId, $identifier, $secrets); + $credentialsManager->store($userId, $identifier, $secretsRev); + $received = $credentialsManager->retrieve($userId, $identifier); + + $this->assertSame($secretsRev, $received); + } + + public function credentialsProvider(): array { return [ [ 'alice', diff --git a/tests/lib/Security/RateLimiting/Backend/MemoryCacheBackendTest.php b/tests/lib/Security/RateLimiting/Backend/MemoryCacheBackendTest.php index e7cb4a93a29..a48b1211587 100644 --- a/tests/lib/Security/RateLimiting/Backend/MemoryCacheBackendTest.php +++ b/tests/lib/Security/RateLimiting/Backend/MemoryCacheBackendTest.php @@ -28,9 +28,12 @@ use OC\Security\RateLimiting\Backend\MemoryCacheBackend; use OCP\AppFramework\Utility\ITimeFactory; use OCP\ICache; use OCP\ICacheFactory; +use OCP\IConfig; use Test\TestCase; class MemoryCacheBackendTest extends TestCase { + /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ + private $config; /** @var ICacheFactory|\PHPUnit\Framework\MockObject\MockObject */ private $cacheFactory; /** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */ @@ -43,6 +46,7 @@ class MemoryCacheBackendTest extends TestCase { protected function setUp(): void { parent::setUp(); + $this->config = $this->createMock(IConfig::class); $this->cacheFactory = $this->createMock(ICacheFactory::class); $this->timeFactory = $this->createMock(ITimeFactory::class); $this->cache = $this->createMock(ICache::class); @@ -53,7 +57,12 @@ class MemoryCacheBackendTest extends TestCase { ->with('OC\Security\RateLimiting\Backend\MemoryCacheBackend') ->willReturn($this->cache); + $this->config->method('getSystemValueBool') + ->with('ratelimit.protection.enabled') + ->willReturn(true); + $this->memoryCache = new MemoryCacheBackend( + $this->config, $this->cacheFactory, $this->timeFactory ); diff --git a/tests/lib/SystemTag/SystemTagObjectMapperTest.php b/tests/lib/SystemTag/SystemTagObjectMapperTest.php index c988db69c30..e77709c781f 100644 --- a/tests/lib/SystemTag/SystemTagObjectMapperTest.php +++ b/tests/lib/SystemTag/SystemTagObjectMapperTest.php @@ -141,6 +141,17 @@ class SystemTagObjectMapperTest extends TestCase { $this->assertEquals([], $tagIdMapping); } + public function testGetTagIdsForALotOfObjects() { + $ids = range(1, 10500); + $tagIdMapping = $this->tagMapper->getTagIdsForObjects( + $ids, + 'testtype' + ); + + $this->assertEquals(10500, count($tagIdMapping)); + $this->assertEquals([$this->tag1->getId(), $this->tag2->getId()], $tagIdMapping[1]); + } + public function testGetObjectsForTags() { $objectIds = $this->tagMapper->getObjectIdsForTags( [$this->tag1->getId(), $this->tag2->getId(), $this->tag3->getId()], @@ -165,7 +176,7 @@ class SystemTagObjectMapperTest extends TestCase { ], $objectIds); } - + public function testGetObjectsForTagsLimitWithMultipleTags() { $this->expectException(\InvalidArgumentException::class); @@ -189,7 +200,7 @@ class SystemTagObjectMapperTest extends TestCase { ], $objectIds); } - + public function testGetObjectsForNonExistingTag() { $this->expectException(\OCP\SystemTag\TagNotFoundException::class); @@ -227,7 +238,7 @@ class SystemTagObjectMapperTest extends TestCase { $this->assertTrue(true, 'No error when reassigning/unassigning'); } - + public function testAssignNonExistingTags() { $this->expectException(\OCP\SystemTag\TagNotFoundException::class); @@ -254,7 +265,7 @@ class SystemTagObjectMapperTest extends TestCase { ], $tagIdMapping, 'None of the tags got assigned'); } - + public function testUnassignNonExistingTags() { $this->expectException(\OCP\SystemTag\TagNotFoundException::class); @@ -385,7 +396,7 @@ class SystemTagObjectMapperTest extends TestCase { ); } - + public function testHaveTagNonExisting() { $this->expectException(\OCP\SystemTag\TagNotFoundException::class); diff --git a/tests/lib/Template/JSResourceLocatorTest.php b/tests/lib/Template/JSResourceLocatorTest.php index 20fd79a91b5..627fe676680 100644 --- a/tests/lib/Template/JSResourceLocatorTest.php +++ b/tests/lib/Template/JSResourceLocatorTest.php @@ -26,6 +26,7 @@ namespace Test\Template; use OC\SystemConfig; use OC\Template\JSCombiner; use OC\Template\JSResourceLocator; +use OCP\App\IAppManager; use OCP\Files\IAppData; use OCP\ICacheFactory; use OCP\IURLGenerator; @@ -42,6 +43,8 @@ class JSResourceLocatorTest extends \Test\TestCase { protected $cacheFactory; /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */ protected $logger; + /** @var IAppManager|\PHPUnit\Framework\MockObject\MockObject */ + protected $appManager; protected function setUp(): void { parent::setUp(); @@ -51,6 +54,7 @@ class JSResourceLocatorTest extends \Test\TestCase { $this->config = $this->createMock(SystemConfig::class); $this->cacheFactory = $this->createMock(ICacheFactory::class); $this->logger = $this->createMock(LoggerInterface::class); + $this->appManager = $this->createMock(IAppManager::class); } private function jsResourceLocator() { @@ -63,7 +67,8 @@ class JSResourceLocatorTest extends \Test\TestCase { ); return new JSResourceLocator( $this->logger, - $jsCombiner + $jsCombiner, + $this->appManager, ); } @@ -84,25 +89,34 @@ class JSResourceLocatorTest extends \Test\TestCase { } public function testFindWithAppPathSymlink() { + $appName = 'test-js-app'; + // First create new apps path, and a symlink to it $apps_dirname = $this->randomString(); $new_apps_path = sys_get_temp_dir() . '/' . $apps_dirname; $new_apps_path_symlink = $new_apps_path . '_link'; - mkdir($new_apps_path); - symlink($apps_dirname, $new_apps_path_symlink); + $this->assertTrue(( + mkdir($new_apps_path) && symlink($apps_dirname, $new_apps_path_symlink) + ), 'Setup of apps path failed'); // Create an app within that path - mkdir($new_apps_path . '/' . 'test-js-app'); + $this->assertTrue(( + mkdir($new_apps_path . '/' . $appName) && touch($new_apps_path . '/' . $appName . '/' . 'test-file.js') + ), 'Setup of app within the new apps path failed'); // Use the symlink as the app path - \OC::$APPSROOTS[] = [ - 'path' => $new_apps_path_symlink, - 'url' => '/js-apps-test', - 'writable' => false, - ]; - + $this->appManager->expects($this->once()) + ->method('getAppPath') + ->with($appName) + ->willReturn("$new_apps_path_symlink/$appName"); + $this->appManager->expects($this->once()) + ->method('getAppWebPath') + ->with($appName) + ->willReturn("/js-apps-test/$appName"); + + // Run the tests $locator = $this->jsResourceLocator(); - $locator->find(['test-js-app/test-file']); + $locator->find(["$appName/test-file"]); $resources = $locator->getResources(); $this->assertCount(1, $resources); @@ -122,7 +136,45 @@ class JSResourceLocatorTest extends \Test\TestCase { $this->assertEquals($expectedFile, $file); array_pop(\OC::$APPSROOTS); - unlink($new_apps_path_symlink); + //unlink($new_apps_path_symlink); + //$this->rrmdir($new_apps_path); + } + + public function testFindModuleJSWithFallback() { + // First create new apps path, and a symlink to it + $apps_dirname = $this->randomString(); + $new_apps_path = sys_get_temp_dir() . '/' . $apps_dirname; + mkdir($new_apps_path); + + // Create an app within that path + mkdir("$new_apps_path/test-js-app"); + touch("$new_apps_path/test-js-app/module.mjs"); + touch("$new_apps_path/test-js-app/both.mjs"); + touch("$new_apps_path/test-js-app/both.js"); + touch("$new_apps_path/test-js-app/plain.js"); + + // Use the app path + $this->appManager->expects($this->any()) + ->method('getAppPath') + ->with('test-js-app') + ->willReturn("$new_apps_path/test-js-app"); + + $locator = $this->jsResourceLocator(); + $locator->find(['test-js-app/module', 'test-js-app/both', 'test-js-app/plain']); + + $resources = $locator->getResources(); + $this->assertCount(3, $resources); + + $expectedRoot = $new_apps_path . '/test-js-app'; + $expectedWebRoot = \OC::$WEBROOT . '/js-apps-test/test-js-app'; + $expectedFiles = ['module.mjs', 'both.mjs', 'plain.js']; + + for ($idx = 0; $idx++; $idx < 3) { + $this->assertEquals($expectedWebRoot, $resources[$idx][1]); + $this->assertEquals($expectedFiles[$idx], $resources[$idx][2]); + } + + array_pop(\OC::$APPSROOTS); $this->rrmdir($new_apps_path); } } diff --git a/tests/lib/TemplateFunctionsTest.php b/tests/lib/TemplateFunctionsTest.php index caecdfc76ac..b2b25ab654c 100644 --- a/tests/lib/TemplateFunctionsTest.php +++ b/tests/lib/TemplateFunctionsTest.php @@ -57,6 +57,35 @@ class TemplateFunctionsTest extends \Test\TestCase { print_unescaped($string); } + public function testEmitScriptTagWithContent() { + $this->expectOutputRegex('/<script nonce="[^"]+">\nalert\(\)\n<\/script>\n?/'); + emit_script_tag('', 'alert()'); + } + + public function testEmitScriptTagWithSource() { + $this->expectOutputRegex('/<script nonce=".*" defer src="some.js"><\/script>/'); + emit_script_tag('some.js'); + } + + public function testEmitScriptTagWithModuleSource() { + $this->expectOutputRegex('/<script nonce=".*" defer src="some.mjs" type="module"><\/script>/'); + emit_script_tag('some.mjs', '', 'module'); + } + + public function testEmitScriptLoadingTags() { + // Test mjs js and inline content + $pattern = '/src="some\.mjs"[^>]+type="module"[^>]*>.+\n'; // some.mjs with type = module + $pattern .= '<script[^>]+src="other\.js"[^>]*>.+\n'; // other.js as plain javascript + $pattern .= '<script[^>]*>\n?.*inline.*\n?<\/script>'; // inline content + $pattern .= '/'; // no flags + + $this->expectOutputRegex($pattern); + emit_script_loading_tags([ + 'jsfiles' => ['some.mjs', 'other.js'], + 'inline_ocjs' => '// inline' + ]); + } + // --------------------------------------------------------------------------- // Test relative_modified_date with dates only // --------------------------------------------------------------------------- diff --git a/tests/lib/UrlGeneratorTest.php b/tests/lib/UrlGeneratorTest.php index 420b2fe4eb9..523616b4532 100644 --- a/tests/lib/UrlGeneratorTest.php +++ b/tests/lib/UrlGeneratorTest.php @@ -13,7 +13,6 @@ use OCP\ICacheFactory; use OCP\IConfig; use OCP\IRequest; use OCP\IURLGenerator; -use OCP\IUser; use OCP\IUserSession; /** @@ -216,21 +215,16 @@ class UrlGeneratorTest extends \Test\TestCase { ]; } - private function mockLinkToDefaultPageUrl(string $defaultAppConfig = '', bool $ignoreFrontControllerConfig = false) { - $this->config->expects($this->exactly(2)) - ->method('getSystemValue') - ->withConsecutive( - ['defaultapp', $this->anything()], - ['htaccess.IgnoreFrontController', $this->anything()], - ) - ->will($this->onConsecutiveCalls( - $defaultAppConfig, - $ignoreFrontControllerConfig - )); + private function mockLinkToDefaultPageUrl(bool $ignoreFrontControllerConfig = false) { $this->config->expects($this->once()) ->method('getAppValue') ->with('core', 'defaultpage') ->willReturn(''); + + $this->config->expects($this->once()) + ->method('getSystemValue') + ->with('htaccess.IgnoreFrontController', $this->anything()) + ->willReturn($ignoreFrontControllerConfig); } public function testLinkToDefaultPageUrlWithRedirectUrlWithoutFrontController() { @@ -246,7 +240,7 @@ class UrlGeneratorTest extends \Test\TestCase { putenv('front_controller_active=false'); $_REQUEST['redirect_url'] = 'myRedirectUrl.com@foo.com:a'; - $this->assertSame('http://localhost' . \OC::$WEBROOT . '/index.php/apps/files/', $this->urlGenerator->linkToDefaultPageUrl()); + $this->assertSame('http://localhost' . \OC::$WEBROOT . '/index.php/apps/dashboard/', $this->urlGenerator->linkToDefaultPageUrl()); } public function testLinkToDefaultPageUrlWithRedirectUrlRedirectBypassWithFrontController() { @@ -255,70 +249,16 @@ class UrlGeneratorTest extends \Test\TestCase { putenv('front_controller_active=true'); $_REQUEST['redirect_url'] = 'myRedirectUrl.com@foo.com:a'; - $this->assertSame('http://localhost' . \OC::$WEBROOT . '/apps/files/', $this->urlGenerator->linkToDefaultPageUrl()); + $this->assertSame('http://localhost' . \OC::$WEBROOT . '/apps/dashboard/', $this->urlGenerator->linkToDefaultPageUrl()); } public function testLinkToDefaultPageUrlWithRedirectUrlWithIgnoreFrontController() { $this->mockBaseUrl(); - $this->mockLinkToDefaultPageUrl('', true); + $this->mockLinkToDefaultPageUrl(true); putenv('front_controller_active=false'); $_REQUEST['redirect_url'] = 'myRedirectUrl.com@foo.com:a'; - $this->assertSame('http://localhost' . \OC::$WEBROOT . '/apps/files/', $this->urlGenerator->linkToDefaultPageUrl()); - } - - /** - * @dataProvider provideDefaultApps - */ - public function testLinkToDefaultPageUrlWithDefaultApps($defaultAppConfig, $expectedPath) { - $userId = $this->getUniqueID(); - - /** @var \PHPUnit\Framework\MockObject\MockObject|IUser $userMock */ - $userMock = $this->createMock(IUser::class); - $userMock->expects($this->once()) - ->method('getUID') - ->willReturn($userId); - - $this->mockBaseUrl(); - $this->mockLinkToDefaultPageUrl($defaultAppConfig); - - $this->config->expects($this->once()) - ->method('getUserValue') - ->with($userId, 'core', 'defaultapp') - ->willReturn(''); - $this->userSession->expects($this->once()) - ->method('isLoggedIn') - ->willReturn(true); - $this->userSession->expects($this->once()) - ->method('getUser') - ->willReturn($userMock); - - $this->assertEquals('http://localhost' . \OC::$WEBROOT . $expectedPath, $this->urlGenerator->linkToDefaultPageUrl()); - } - - public function provideDefaultApps(): array { - return [ - // none specified, default to files - [ - '', - '/index.php/apps/files/', - ], - // unexisting or inaccessible app specified, default to files - [ - 'unexist', - '/index.php/apps/files/', - ], - // non-standard app - [ - 'settings', - '/index.php/apps/settings/', - ], - // non-standard app with fallback - [ - 'unexist,settings', - '/index.php/apps/settings/', - ], - ]; + $this->assertSame('http://localhost' . \OC::$WEBROOT . '/apps/dashboard/', $this->urlGenerator->linkToDefaultPageUrl()); } public function imagePathProvider(): array { diff --git a/tests/lib/User/SessionTest.php b/tests/lib/User/SessionTest.php index 735a3b3d06a..4928744ed1c 100644 --- a/tests/lib/User/SessionTest.php +++ b/tests/lib/User/SessionTest.php @@ -9,6 +9,7 @@ namespace Test\User; use OC\AppFramework\Http\Request; +use OC\Authentication\Events\LoginFailed; use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\PasswordLoginForbiddenException; use OC\Authentication\Token\IProvider; @@ -1057,4 +1058,100 @@ class SessionTest extends \Test\TestCase { $this->userSession->updateTokens('uid', 'pass'); } + + public function testLogClientInThrottlerUsername() { + $manager = $this->createMock(Manager::class); + $session = $this->createMock(ISession::class); + $request = $this->createMock(IRequest::class); + + /** @var Session $userSession */ + $userSession = $this->getMockBuilder(Session::class) + ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) + ->setMethods(['isTokenPassword', 'login', 'supportsCookies', 'createSessionToken', 'getUser']) + ->getMock(); + + $userSession->expects($this->once()) + ->method('isTokenPassword') + ->willReturn(true); + $userSession->expects($this->once()) + ->method('login') + ->with('john', 'I-AM-AN-PASSWORD') + ->willReturn(false); + + $session->expects($this->never()) + ->method('set'); + $request + ->method('getRemoteAddress') + ->willReturn('192.168.0.1'); + $this->throttler + ->expects($this->exactly(2)) + ->method('sleepDelay') + ->with('192.168.0.1'); + $this->throttler + ->expects($this->any()) + ->method('getDelay') + ->with('192.168.0.1') + ->willReturn(0); + + $this->throttler + ->expects($this->once()) + ->method('registerAttempt') + ->with('login', '192.168.0.1', ['user' => 'john']); + $this->dispatcher + ->expects($this->once()) + ->method('dispatchTyped') + ->with(new LoginFailed('john', 'I-AM-AN-PASSWORD')); + + $this->assertFalse($userSession->logClientIn('john', 'I-AM-AN-PASSWORD', $request, $this->throttler)); + } + + public function testLogClientInThrottlerEmail() { + $manager = $this->createMock(Manager::class); + $session = $this->createMock(ISession::class); + $request = $this->createMock(IRequest::class); + + /** @var Session $userSession */ + $userSession = $this->getMockBuilder(Session::class) + ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher]) + ->setMethods(['isTokenPassword', 'login', 'supportsCookies', 'createSessionToken', 'getUser']) + ->getMock(); + + $userSession->expects($this->once()) + ->method('isTokenPassword') + ->willReturn(true); + $userSession->expects($this->once()) + ->method('login') + ->with('john@foo.bar', 'I-AM-AN-PASSWORD') + ->willReturn(false); + $manager + ->method('getByEmail') + ->with('john@foo.bar') + ->willReturn([]); + + $session->expects($this->never()) + ->method('set'); + $request + ->method('getRemoteAddress') + ->willReturn('192.168.0.1'); + $this->throttler + ->expects($this->exactly(2)) + ->method('sleepDelay') + ->with('192.168.0.1'); + $this->throttler + ->expects($this->any()) + ->method('getDelay') + ->with('192.168.0.1') + ->willReturn(0); + + $this->throttler + ->expects($this->once()) + ->method('registerAttempt') + ->with('login', '192.168.0.1', ['user' => 'john@foo.bar']); + $this->dispatcher + ->expects($this->once()) + ->method('dispatchTyped') + ->with(new LoginFailed('john@foo.bar', 'I-AM-AN-PASSWORD')); + + $this->assertFalse($userSession->logClientIn('john@foo.bar', 'I-AM-AN-PASSWORD', $request, $this->throttler)); + } } |