diff options
22 files changed, 383 insertions, 113 deletions
diff --git a/3rdparty b/3rdparty -Subproject 747d4ceb41b707622a960d79ac2694b2919b7c2 +Subproject 05ca07b2981cbe64e58825aeb9362d88c8fc5ac diff --git a/apps/dav/lib/Connector/Sabre/FilesPlugin.php b/apps/dav/lib/Connector/Sabre/FilesPlugin.php index 156507e4467..0fc7ac4af4e 100644 --- a/apps/dav/lib/Connector/Sabre/FilesPlugin.php +++ b/apps/dav/lib/Connector/Sabre/FilesPlugin.php @@ -76,6 +76,8 @@ class FilesPlugin extends ServerPlugin { public const UPLOAD_TIME_PROPERTYNAME = '{http://nextcloud.org/ns}upload_time'; public const CREATION_TIME_PROPERTYNAME = '{http://nextcloud.org/ns}creation_time'; public const SHARE_NOTE = '{http://nextcloud.org/ns}note'; + public const SUBFOLDER_COUNT_PROPERTYNAME = '{http://nextcloud.org/ns}contained-folder-count'; + public const SUBFILE_COUNT_PROPERTYNAME = '{http://nextcloud.org/ns}contained-file-count'; /** * Reference to main server object @@ -429,7 +431,7 @@ class FilesPlugin extends ServerPlugin { }); } - if ($node instanceof \OCA\DAV\Connector\Sabre\Directory) { + if ($node instanceof Directory) { $propFind->handle(self::SIZE_PROPERTYNAME, function () use ($node) { return $node->getSize(); }); @@ -437,6 +439,23 @@ class FilesPlugin extends ServerPlugin { $propFind->handle(self::IS_ENCRYPTED_PROPERTYNAME, function () use ($node) { return $node->getFileInfo()->isEncrypted() ? '1' : '0'; }); + + $requestProperties = $propFind->getRequestedProperties(); + if (in_array(self::SUBFILE_COUNT_PROPERTYNAME, $requestProperties, true) + || in_array(self::SUBFOLDER_COUNT_PROPERTYNAME, $requestProperties, true)) { + $nbFiles = 0; + $nbFolders = 0; + foreach ($node->getChildren() as $child) { + if ($child instanceof File) { + $nbFiles++; + } elseif ($child instanceof Directory) { + $nbFolders++; + } + } + + $propFind->handle(self::SUBFILE_COUNT_PROPERTYNAME, $nbFiles); + $propFind->handle(self::SUBFOLDER_COUNT_PROPERTYNAME, $nbFolders); + } } } diff --git a/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php b/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php index f19e251fc7a..fe0c7a11ab7 100644 --- a/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php +++ b/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php @@ -36,6 +36,7 @@ use OCP\AppFramework\OCS\OCSException; use OCP\AppFramework\OCS\OCSForbiddenException; use OCP\AppFramework\OCSController; use OCP\Constants; +use OCP\EventDispatcher\IEventDispatcher; use OCP\Federation\Exceptions\ProviderCouldNotAddShareException; use OCP\Federation\Exceptions\ProviderDoesNotExistsException; use OCP\Federation\ICloudFederationFactory; @@ -44,6 +45,7 @@ use OCP\Federation\ICloudIdManager; use OCP\IDBConnection; use OCP\IRequest; use OCP\IUserManager; +use OCP\Log\Audit\CriticalActionPerformedEvent; use OCP\Share; use OCP\Share\Exceptions\ShareNotFound; use Psr\Log\LoggerInterface; @@ -83,6 +85,9 @@ class RequestHandlerController extends OCSController { /** @var ICloudFederationProviderManager */ private $cloudFederationProviderManager; + /** @var IEventDispatcher */ + private $eventDispatcher; + public function __construct(string $appName, IRequest $request, FederatedShareProvider $federatedShareProvider, @@ -94,7 +99,8 @@ class RequestHandlerController extends OCSController { ICloudIdManager $cloudIdManager, LoggerInterface $logger, ICloudFederationFactory $cloudFederationFactory, - ICloudFederationProviderManager $cloudFederationProviderManager + ICloudFederationProviderManager $cloudFederationProviderManager, + IEventDispatcher $eventDispatcher ) { parent::__construct($appName, $request); @@ -108,6 +114,7 @@ class RequestHandlerController extends OCSController { $this->logger = $logger; $this->cloudFederationFactory = $cloudFederationFactory; $this->cloudFederationProviderManager = $cloudFederationProviderManager; + $this->eventDispatcher = $eventDispatcher; } /** @@ -156,6 +163,11 @@ class RequestHandlerController extends OCSController { try { $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file'); $provider->shareReceived($share); + if ($sharedByFederatedId === $ownerFederatedId) { + $this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('A new federated share with "%s" was created by "%s" and shared with "%s"', [$name, $ownerFederatedId, $shareWith])); + } else { + $this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('A new federated share with "%s" was shared by "%s" (resource owner is: "%s") and shared with "%s"', [$name, $sharedByFederatedId, $ownerFederatedId, $shareWith])); + } } catch (ProviderDoesNotExistsException $e) { throw new OCSException('Server does not support federated cloud sharing', 503); } catch (ProviderCouldNotAddShareException $e) { @@ -243,6 +255,7 @@ class RequestHandlerController extends OCSController { try { $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file'); $provider->notificationReceived('SHARE_ACCEPTED', $id, $notification); + $this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('Federated share with id "%s" was accepted', [$id])); } catch (ProviderDoesNotExistsException $e) { throw new OCSException('Server does not support federated cloud sharing', 503); } catch (ShareNotFound $e) { @@ -275,6 +288,7 @@ class RequestHandlerController extends OCSController { try { $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file'); $provider->notificationReceived('SHARE_DECLINED', $id, $notification); + $this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('Federated share with id "%s" was declined', [$id])); } catch (ProviderDoesNotExistsException $e) { throw new OCSException('Server does not support federated cloud sharing', 503); } catch (ShareNotFound $e) { @@ -307,6 +321,7 @@ class RequestHandlerController extends OCSController { $provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file'); $notification = ['sharedSecret' => $token]; $provider->notificationReceived('SHARE_UNSHARED', $id, $notification); + $this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('Federated share with id "%s" was unshared', [$id])); } catch (\Exception $e) { $this->logger->debug('processing unshare notification failed: ' . $e->getMessage(), ['exception' => $e]); } @@ -381,6 +396,7 @@ class RequestHandlerController extends OCSController { $ocmPermissions = $this->ncPermissions2ocmPermissions((int)$ncPermissions); $notification = ['sharedSecret' => $token, 'permission' => $ocmPermissions]; $provider->notificationReceived('RESHARE_CHANGE_PERMISSION', $id, $notification); + $this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('Federated share with id "%s" has updated permissions "%s"', [$id, implode(', ', $ocmPermissions)])); } catch (\Exception $e) { $this->logger->debug($e->getMessage(), ['exception' => $e]); throw new OCSBadRequestException(); diff --git a/apps/federatedfilesharing/tests/Controller/RequestHandlerControllerTest.php b/apps/federatedfilesharing/tests/Controller/RequestHandlerControllerTest.php index 0cb91fac1ae..77f7fde70fa 100644 --- a/apps/federatedfilesharing/tests/Controller/RequestHandlerControllerTest.php +++ b/apps/federatedfilesharing/tests/Controller/RequestHandlerControllerTest.php @@ -34,6 +34,7 @@ use OCP\Federation\ICloudFederationProvider; use OCP\Federation\ICloudFederationProviderManager; use OCP\Federation\ICloudFederationShare; use OCP\Federation\ICloudIdManager; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IDBConnection; use OCP\IRequest; use OCP\IUserManager; @@ -100,6 +101,9 @@ class RequestHandlerControllerTest extends \Test\TestCase { /** @var ICloudFederationShare|\PHPUnit\Framework\MockObject\MockObject */ private $cloudFederationShare; + /** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */ + private $eventDispatcher; + protected function setUp(): void { $this->share = $this->getMockBuilder(IShare::class)->getMock(); $this->federatedShareProvider = $this->getMockBuilder('OCA\FederatedFileSharing\FederatedShareProvider') @@ -124,7 +128,8 @@ class RequestHandlerControllerTest extends \Test\TestCase { $this->cloudFederationProviderManager = $this->createMock(ICloudFederationProviderManager::class); $this->cloudFederationProvider = $this->createMock(ICloudFederationProvider::class); $this->cloudFederationShare = $this->createMock(ICloudFederationShare::class); - + $this->eventDispatcher = $this->createMock(IEventDispatcher::class); + $this->eventDispatcher->expects($this->any())->method('dispatchTyped'); $this->logger = $this->createMock(LoggerInterface::class); @@ -140,7 +145,8 @@ class RequestHandlerControllerTest extends \Test\TestCase { $this->cloudIdManager, $this->logger, $this->cloudFederationFactory, - $this->cloudFederationProviderManager + $this->cloudFederationProviderManager, + $this->eventDispatcher ); } diff --git a/apps/settings/lib/Controller/AuthSettingsController.php b/apps/settings/lib/Controller/AuthSettingsController.php index 3255fcce56e..38db7be1e91 100644 --- a/apps/settings/lib/Controller/AuthSettingsController.php +++ b/apps/settings/lib/Controller/AuthSettingsController.php @@ -145,6 +145,10 @@ class AuthSettingsController extends Controller { return $this->getServiceNotAvailableResponse(); } + if (mb_strlen($name) > 128) { + $name = mb_substr($name, 0, 120) . '…'; + } + $token = $this->generateRandomDeviceToken(); $deviceToken = $this->tokenProvider->generateToken($token, $this->uid, $loginName, $password, $name, IToken::PERMANENT_TOKEN); $tokenData = $deviceToken->jsonSerialize(); @@ -241,6 +245,10 @@ class AuthSettingsController extends Controller { $this->publishActivity($scope['filesystem'] ? Provider::APP_TOKEN_FILESYSTEM_GRANTED : Provider::APP_TOKEN_FILESYSTEM_REVOKED, $token->getId(), ['name' => $currentName]); } + if (mb_strlen($name) > 128) { + $name = mb_substr($name, 0, 120) . '…'; + } + if ($token instanceof INamedToken && $name !== $currentName) { $token->setName($name); $this->publishActivity(Provider::APP_TOKEN_RENAMED, $token->getId(), ['name' => $currentName, 'newName' => $name]); diff --git a/apps/settings/lib/Controller/CheckSetupController.php b/apps/settings/lib/Controller/CheckSetupController.php index 4b825c2622f..b9f176f97c5 100644 --- a/apps/settings/lib/Controller/CheckSetupController.php +++ b/apps/settings/lib/Controller/CheckSetupController.php @@ -713,20 +713,6 @@ Raw output $recommendedPHPModules[] = 'intl'; } - if (!extension_loaded('bcmath')) { - $recommendedPHPModules[] = 'bcmath'; - } - - if (!extension_loaded('gmp')) { - $recommendedPHPModules[] = 'gmp'; - } - - if ($this->config->getAppValue('theming', 'enabled', 'no') === 'yes') { - if (!extension_loaded('imagick')) { - $recommendedPHPModules[] = 'imagick'; - } - } - if (!defined('PASSWORD_ARGON2I') && PHP_VERSION_ID >= 70400) { // Installing php-sodium on >=php7.4 will provide PASSWORD_ARGON2I // on previous version argon2 wasn't part of the "standard" extension @@ -738,6 +724,25 @@ Raw output return $recommendedPHPModules; } + protected function isImagickEnabled(): bool { + if ($this->config->getAppValue('theming', 'enabled', 'no') === 'yes') { + if (!extension_loaded('imagick')) { + return false; + } + } + return true; + } + + protected function areWebauthnExtensionsEnabled(): bool { + if (!extension_loaded('bcmath')) { + return false; + } + if (!extension_loaded('gmp')) { + return false; + } + return true; + } + protected function isMysqlUsedWithoutUTF8MB4(): bool { return ($this->config->getSystemValue('dbtype', 'sqlite') === 'mysql') && ($this->config->getSystemValue('mysql.utf8mb4', false) === false); } @@ -869,6 +874,8 @@ Raw output 'databaseConversionDocumentation' => $this->urlGenerator->linkToDocs('admin-db-conversion'), 'isMemoryLimitSufficient' => $this->memoryInfo->isMemoryLimitSufficient(), 'appDirsWithDifferentOwner' => $this->getAppDirsWithDifferentOwner(), + 'isImagickEnabled' => $this->isImagickEnabled(), + 'areWebauthnExtensionsEnabled' => $this->areWebauthnExtensionsEnabled(), 'recommendedPHPModules' => $this->hasRecommendedPHPModules(), 'pendingBigIntConversionColumns' => $this->hasBigIntConversionPendingColumns(), 'isMysqlUsedWithoutUTF8MB4' => $this->isMysqlUsedWithoutUTF8MB4(), diff --git a/apps/settings/tests/Controller/CheckSetupControllerTest.php b/apps/settings/tests/Controller/CheckSetupControllerTest.php index 4349994570b..8a1e062f58b 100644 --- a/apps/settings/tests/Controller/CheckSetupControllerTest.php +++ b/apps/settings/tests/Controller/CheckSetupControllerTest.php @@ -550,6 +550,16 @@ class CheckSetupControllerTest extends TestCase { $this->checkSetupController ->expects($this->once()) + ->method('isImagickEnabled') + ->willReturn(false); + + $this->checkSetupController + ->expects($this->once()) + ->method('areWebauthnExtensionsEnabled') + ->willReturn(false); + + $this->checkSetupController + ->expects($this->once()) ->method('hasRecommendedPHPModules') ->willReturn([]); @@ -642,6 +652,8 @@ class CheckSetupControllerTest extends TestCase { 'missingColumns' => [], 'isMemoryLimitSufficient' => true, 'appDirsWithDifferentOwner' => [], + 'isImagickEnabled' => false, + 'areWebauthnExtensionsEnabled' => false, 'recommendedPHPModules' => [], 'pendingBigIntConversionColumns' => [], 'isMysqlUsedWithoutUTF8MB4' => false, diff --git a/apps/user_ldap/lib/Wizard.php b/apps/user_ldap/lib/Wizard.php index 9b037b47134..6e0d6f80f8d 100644 --- a/apps/user_ldap/lib/Wizard.php +++ b/apps/user_ldap/lib/Wizard.php @@ -1331,7 +1331,7 @@ class Wizard extends LDAPUtility { $this->configuration->ldapAgentName, $this->configuration->ldapAgentPassword); if ($lo === true) { - $this->$cr = $cr; + $this->cr = $cr; return $cr; } diff --git a/core/Controller/ClientFlowLoginController.php b/core/Controller/ClientFlowLoginController.php index 2ba26deb0e7..d67a065a14e 100644 --- a/core/Controller/ClientFlowLoginController.php +++ b/core/Controller/ClientFlowLoginController.php @@ -162,12 +162,8 @@ class ClientFlowLoginController extends Controller { * @PublicPage * @NoCSRFRequired * @UseSession - * - * @param string $clientIdentifier - * - * @return StandaloneTemplateResponse */ - public function showAuthPickerPage($clientIdentifier = '') { + public function showAuthPickerPage(string $clientIdentifier = '', int $direct = 0): StandaloneTemplateResponse { $clientName = $this->getClientName(); $client = null; if ($clientIdentifier !== '') { @@ -218,6 +214,7 @@ class ClientFlowLoginController extends Controller { 'stateToken' => $stateToken, 'serverHost' => $this->getServerPath(), 'oauthState' => $this->session->get('oauth.state'), + 'direct' => $direct, ], 'guest' ); @@ -231,13 +228,10 @@ class ClientFlowLoginController extends Controller { * @NoCSRFRequired * @NoSameSiteCookieRequired * @UseSession - * - * @param string $stateToken - * @param string $clientIdentifier - * @return StandaloneTemplateResponse */ - public function grantPage($stateToken = '', - $clientIdentifier = '') { + public function grantPage(string $stateToken = '', + string $clientIdentifier = '', + int $direct = 0): StandaloneTemplateResponse { if (!$this->isValidToken($stateToken)) { return $this->stateTokenForbiddenResponse(); } @@ -267,6 +261,7 @@ class ClientFlowLoginController extends Controller { 'stateToken' => $stateToken, 'serverHost' => $this->getServerPath(), 'oauthState' => $this->session->get('oauth.state'), + 'direct' => $direct, ], 'guest' ); diff --git a/core/js/setupchecks.js b/core/js/setupchecks.js index fa67528de5d..266f35a9552 100644 --- a/core/js/setupchecks.js +++ b/core/js/setupchecks.js @@ -423,6 +423,24 @@ type: OC.SetupChecks.MESSAGE_TYPE_INFO }) } + if (!data.isImagickEnabled) { + messages.push({ + msg: t( + 'core', + 'The PHP module "imagick" is not enabled although the theming app is. For favicon generation to work correctly, you need to install and enable this module.' + ), + type: OC.SetupChecks.MESSAGE_TYPE_INFO + }) + } + if (!data.areWebauthnExtensionsEnabled) { + messages.push({ + msg: t( + 'core', + 'The PHP modules "gmp" and/or "bcmath" are not enabled. If you use WebAuthn passwordless authentication, these modules are required.' + ), + type: OC.SetupChecks.MESSAGE_TYPE_INFO + }) + } if (data.imageMagickLacksSVGSupport) { messages.push({ msg: t( diff --git a/core/js/tests/specs/setupchecksSpec.js b/core/js/tests/specs/setupchecksSpec.js index 5975c875c3b..5914a6f2449 100644 --- a/core/js/tests/specs/setupchecksSpec.js +++ b/core/js/tests/specs/setupchecksSpec.js @@ -249,6 +249,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: true, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, @@ -307,6 +309,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: true, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, @@ -366,6 +370,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: true, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, @@ -423,6 +429,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: true, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, @@ -478,6 +486,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: true, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, @@ -533,6 +543,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: true, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, @@ -590,6 +602,8 @@ describe('OC.SetupChecks tests', function() { appDirsWithDifferentOwner: [ '/some/path' ], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, @@ -645,6 +659,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: true, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, @@ -700,6 +716,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: true, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, @@ -755,6 +773,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: false, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, @@ -831,6 +851,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: true, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, @@ -886,6 +908,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: true, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, @@ -941,6 +965,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: true, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, @@ -996,6 +1022,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: true, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: true, @@ -1055,6 +1083,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: true, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, @@ -1111,6 +1141,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: true, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, @@ -1164,6 +1196,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: true, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, @@ -1183,6 +1217,122 @@ describe('OC.SetupChecks tests', function() { }); }); + + it('should return an error if imagick is not enabled', function(done) { + var async = OC.SetupChecks.checkSetup(); + + suite.server.requests[0].respond( + 200, + { + 'Content-Type': 'application/json', + }, + JSON.stringify({ + hasFileinfoInstalled: true, + isGetenvServerWorking: true, + isReadOnlyConfig: false, + wasEmailTestSuccessful: true, + hasWorkingFileLocking: true, + hasValidTransactionIsolationLevel: true, + suggestedOverwriteCliURL: '', + isRandomnessSecure: true, + securityDocs: 'https://docs.nextcloud.com/myDocs.html', + isFairUseOfFreePushService: true, + serverHasInternetConnectionProblems: false, + isMemcacheConfigured: true, + forwardedForHeadersWorking: true, + isCorrectMemcachedPHPModuleInstalled: true, + hasPassedCodeIntegrityCheck: true, + OpcacheSetupRecommendations: [], + isSettimelimitAvailable: true, + hasFreeTypeSupport: true, + missingIndexes: [], + missingPrimaryKeys: [], + missingColumns: [], + cronErrors: [], + cronInfo: { + diffInSeconds: 0 + }, + isMemoryLimitSufficient: true, + appDirsWithDifferentOwner: [], + isImagickEnabled: false, + areWebauthnExtensionsEnabled: true, + recommendedPHPModules: [], + pendingBigIntConversionColumns: [], + isMysqlUsedWithoutUTF8MB4: false, + isDefaultPhoneRegionSet: true, + isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed: true, + reverseProxyGeneratedURL: 'https://server', + temporaryDirectoryWritable: true, + }) + ); + + async.done(function( data, s, x ){ + expect(data).toEqual([{ + msg: 'The PHP module "imagick" is not enabled although the theming app is. For favicon generation to work correctly, you need to install and enable this module.', + type: OC.SetupChecks.MESSAGE_TYPE_INFO + }]); + done(); + }); + }); + + + it('should return an error if gmp or bcmath are not enabled', function(done) { + var async = OC.SetupChecks.checkSetup(); + + suite.server.requests[0].respond( + 200, + { + 'Content-Type': 'application/json', + }, + JSON.stringify({ + hasFileinfoInstalled: true, + isGetenvServerWorking: true, + isReadOnlyConfig: false, + wasEmailTestSuccessful: true, + hasWorkingFileLocking: true, + hasValidTransactionIsolationLevel: true, + suggestedOverwriteCliURL: '', + isRandomnessSecure: true, + securityDocs: 'https://docs.nextcloud.com/myDocs.html', + isFairUseOfFreePushService: true, + serverHasInternetConnectionProblems: false, + isMemcacheConfigured: true, + forwardedForHeadersWorking: true, + isCorrectMemcachedPHPModuleInstalled: true, + hasPassedCodeIntegrityCheck: true, + OpcacheSetupRecommendations: [], + isSettimelimitAvailable: true, + hasFreeTypeSupport: true, + missingIndexes: [], + missingPrimaryKeys: [], + missingColumns: [], + cronErrors: [], + cronInfo: { + diffInSeconds: 0 + }, + isMemoryLimitSufficient: true, + appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: false, + recommendedPHPModules: [], + pendingBigIntConversionColumns: [], + isMysqlUsedWithoutUTF8MB4: false, + isDefaultPhoneRegionSet: true, + isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed: true, + reverseProxyGeneratedURL: 'https://server', + temporaryDirectoryWritable: true, + }) + ); + + async.done(function( data, s, x ){ + expect(data).toEqual([{ + msg: 'The PHP modules "gmp" and/or "bcmath" are not enabled. If you use WebAuthn passwordless authentication, these modules are required.', + type: OC.SetupChecks.MESSAGE_TYPE_INFO + }]); + done(); + }); + }); + it('should return an info if there is no default phone region', function(done) { var async = OC.SetupChecks.checkSetup(); @@ -1219,6 +1369,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: true, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, @@ -1274,6 +1426,8 @@ describe('OC.SetupChecks tests', function() { }, isMemoryLimitSufficient: true, appDirsWithDifferentOwner: [], + isImagickEnabled: true, + areWebauthnExtensionsEnabled: true, recommendedPHPModules: [], pendingBigIntConversionColumns: [], isMysqlUsedWithoutUTF8MB4: false, diff --git a/core/templates/loginflow/authpicker.php b/core/templates/loginflow/authpicker.php index 02b4b9cc003..4c4c8fd6d53 100644 --- a/core/templates/loginflow/authpicker.php +++ b/core/templates/loginflow/authpicker.php @@ -46,7 +46,7 @@ $urlGenerator = $_['urlGenerator']; <br/> <p id="redirect-link"> - <a href="<?php p($urlGenerator->linkToRoute('core.ClientFlowLogin.grantPage', ['stateToken' => $_['stateToken'], 'clientIdentifier' => $_['clientIdentifier'], 'oauthState' => $_['oauthState']])) ?>"> + <a href="<?php p($urlGenerator->linkToRoute('core.ClientFlowLogin.grantPage', ['stateToken' => $_['stateToken'], 'clientIdentifier' => $_['clientIdentifier'], 'oauthState' => $_['oauthState'], 'direct' => $_['direct']])) ?>"> <input type="submit" class="login primary icon-confirm-white" value="<?php p($l->t('Log in')) ?>"> </a> </p> @@ -62,6 +62,9 @@ $urlGenerator = $_['urlGenerator']; </p> <input type="hidden" name="stateToken" value="<?php p($_['stateToken']) ?>" /> <input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>"> + <?php if ($_['direct'] !== 0) { ?> + <input type="hidden" name="direct" value="<?php p($_['direct']) ?>"> + <?php } ?> <input id="submit-app-token-login" type="submit" class="login primary icon-confirm-white" value="<?php p($l->t('Grant access')) ?>"> </form> </div> diff --git a/core/templates/loginflow/grant.php b/core/templates/loginflow/grant.php index 0f1b9235a89..c537c47ea64 100644 --- a/core/templates/loginflow/grant.php +++ b/core/templates/loginflow/grant.php @@ -39,14 +39,17 @@ $urlGenerator = $_['urlGenerator']; <br/> <p id="redirect-link"> - <form method="POST" action="<?php p($urlGenerator->linkToRouteAbsolute('core.ClientFlowLogin.generateAppPassword')) ?>"> - <input type="hidden" name="clientIdentifier" value="<?php p($_['clientIdentifier']) ?>" /> - <input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>" /> - <input type="hidden" name="stateToken" value="<?php p($_['stateToken']) ?>" /> - <input type="hidden" name="oauthState" value="<?php p($_['oauthState']) ?>" /> + <form method="POST" action="<?php p($urlGenerator->linkToRouteAbsolute('core.ClientFlowLogin.generateAppPassword')) ?>"> + <input type="hidden" name="clientIdentifier" value="<?php p($_['clientIdentifier']) ?>" /> + <input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>" /> + <input type="hidden" name="stateToken" value="<?php p($_['stateToken']) ?>" /> + <input type="hidden" name="oauthState" value="<?php p($_['oauthState']) ?>" /> + <?php if (p($_['direct'])) { ?> + <input type="hidden" name="direct" value="1" /> + <?php } ?> <div id="submit-wrapper"> <input type="submit" class="login primary icon-confirm-white" title="" value="<?php p($l->t('Grant access')); ?>" /> - </div> + </div> </form> </p> </div> diff --git a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php index d162bb54108..041535e54bd 100644 --- a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php +++ b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php @@ -260,6 +260,9 @@ class SecurityMiddleware extends Middleware { if (isset($this->request->server['REQUEST_URI'])) { $params['redirect_url'] = $this->request->server['REQUEST_URI']; } + if ($this->request->getParam('direct')) { + $params['direct'] = 1; + } $url = $this->urlGenerator->linkToRoute('core.login.showLoginForm', $params); $response = new RedirectResponse($url); } else { diff --git a/lib/private/Authentication/Token/IProvider.php b/lib/private/Authentication/Token/IProvider.php index e604ac715c2..0a145bfd7e6 100644 --- a/lib/private/Authentication/Token/IProvider.php +++ b/lib/private/Authentication/Token/IProvider.php @@ -44,7 +44,7 @@ interface IProvider { * @param string $uid * @param string $loginName * @param string|null $password - * @param string $name + * @param string $name Name will be trimmed to 120 chars when longer * @param int $type token type * @param int $remember whether the session token should be used for remember-me * @return IToken diff --git a/lib/private/Authentication/Token/Manager.php b/lib/private/Authentication/Token/Manager.php index b718ce73ea4..cadc5f408e4 100644 --- a/lib/private/Authentication/Token/Manager.php +++ b/lib/private/Authentication/Token/Manager.php @@ -53,7 +53,7 @@ class Manager implements IProvider { * @param string $uid * @param string $loginName * @param string|null $password - * @param string $name + * @param string $name Name will be trimmed to 120 chars when longer * @param int $type token type * @param int $remember whether the session token should be used for remember-me * @return IToken @@ -65,6 +65,10 @@ class Manager implements IProvider { string $name, int $type = IToken::TEMPORARY_TOKEN, int $remember = IToken::DO_NOT_REMEMBER): IToken { + if (mb_strlen($name) > 128) { + $name = mb_substr($name, 0, 120) . '…'; + } + try { return $this->publicKeyTokenProvider->generateToken( $token, diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php index b7c8a8e9c24..ddf477b3463 100644 --- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php +++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php @@ -84,6 +84,10 @@ class PublicKeyTokenProvider implements IProvider { string $name, int $type = IToken::TEMPORARY_TOKEN, int $remember = IToken::DO_NOT_REMEMBER): IToken { + if (mb_strlen($name) > 128) { + throw new InvalidTokenException('The given name is too long'); + } + $dbToken = $this->newToken($token, $uid, $loginName, $password, $name, $type, $remember); $this->mapper->insert($dbToken); diff --git a/lib/private/Preview/Bundled.php b/lib/private/Preview/Bundled.php index f026d3259f5..6b5a8aa2d12 100644 --- a/lib/private/Preview/Bundled.php +++ b/lib/private/Preview/Bundled.php @@ -46,7 +46,7 @@ abstract class Bundled extends ProviderV2 { $image->fixOrientation(); return $image; - } catch (\Exception $e) { + } catch (\Throwable $e) { return null; } } diff --git a/tests/Core/Controller/ClientFlowLoginControllerTest.php b/tests/Core/Controller/ClientFlowLoginControllerTest.php index 51a17743c93..c60c89407bd 100644 --- a/tests/Core/Controller/ClientFlowLoginControllerTest.php +++ b/tests/Core/Controller/ClientFlowLoginControllerTest.php @@ -183,6 +183,7 @@ class ClientFlowLoginControllerTest extends TestCase { 'stateToken' => 'StateToken', 'serverHost' => 'https://example.com', 'oauthState' => 'OauthStateToken', + 'direct' => 0, ], 'guest' ); @@ -246,6 +247,7 @@ class ClientFlowLoginControllerTest extends TestCase { 'stateToken' => 'StateToken', 'serverHost' => 'https://example.com', 'oauthState' => 'OauthStateToken', + 'direct' => 0, ], 'guest' ); diff --git a/tests/lib/Authentication/Token/ManagerTest.php b/tests/lib/Authentication/Token/ManagerTest.php index fb92b3e5018..ee2b3cdc768 100644 --- a/tests/lib/Authentication/Token/ManagerTest.php +++ b/tests/lib/Authentication/Token/ManagerTest.php @@ -127,6 +127,37 @@ class ManagerTest extends TestCase { $this->assertSame($token, $actual); } + public function testGenerateTokenTooLongName() { + $token = $this->createMock(IToken::class); + $token->method('getName') + ->willReturn(str_repeat('a', 120) . '…'); + + + $this->publicKeyTokenProvider->expects($this->once()) + ->method('generateToken') + ->with( + 'token', + 'uid', + 'loginName', + 'password', + str_repeat('a', 120) . '…', + IToken::TEMPORARY_TOKEN, + IToken::REMEMBER + )->willReturn($token); + + $actual = $this->manager->generateToken( + 'token', + 'uid', + 'loginName', + 'password', + str_repeat('a', 200), + IToken::TEMPORARY_TOKEN, + IToken::REMEMBER + ); + + $this->assertSame(121, mb_strlen($actual->getName())); + } + public function tokenData(): array { return [ [new DefaultToken()], diff --git a/tests/lib/Authentication/Token/PublicKeyTokenProviderTest.php b/tests/lib/Authentication/Token/PublicKeyTokenProviderTest.php index 486660f17c6..767e7897c58 100644 --- a/tests/lib/Authentication/Token/PublicKeyTokenProviderTest.php +++ b/tests/lib/Authentication/Token/PublicKeyTokenProviderTest.php @@ -82,10 +82,7 @@ class PublicKeyTokenProviderTest extends TestCase { $uid = 'user'; $user = 'User'; $password = 'passme'; - $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; + $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; $type = IToken::PERMANENT_TOKEN; $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER); @@ -98,6 +95,22 @@ class PublicKeyTokenProviderTest extends TestCase { $this->assertSame($password, $this->tokenProvider->getPassword($actual, $token)); } + public function testGenerateTokenInvalidName() { + $this->expectException(\OC\Authentication\Exceptions\InvalidTokenException::class); + + $token = 'token'; + $uid = 'user'; + $user = 'User'; + $password = 'passme'; + $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' + . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' + . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' + . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; + $type = IToken::PERMANENT_TOKEN; + + $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER); + } + public function testUpdateToken() { $tk = new PublicKeyToken(); $this->mapper->expects($this->once()) @@ -139,10 +152,7 @@ class PublicKeyTokenProviderTest extends TestCase { $uid = 'user'; $user = 'User'; $password = 'passme'; - $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; + $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; $type = IToken::PERMANENT_TOKEN; $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER); @@ -169,10 +179,7 @@ class PublicKeyTokenProviderTest extends TestCase { $uid = 'user'; $user = 'User'; $password = 'passme'; - $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; + $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; $type = IToken::PERMANENT_TOKEN; $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER); @@ -185,10 +192,7 @@ class PublicKeyTokenProviderTest extends TestCase { $uid = 'user'; $user = 'User'; $password = 'passme'; - $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; + $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; $type = IToken::PERMANENT_TOKEN; $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER); @@ -248,12 +252,12 @@ class PublicKeyTokenProviderTest extends TestCase { ['session_lifetime', $defaultSessionLifetime, 150], ['remember_login_cookie_lifetime', $defaultRememberMeLifetime, 300], ]); - $this->mapper->expects($this->at(0)) - ->method('invalidateOld') - ->with($this->time - 150); - $this->mapper->expects($this->at(1)) + $this->mapper->expects($this->exactly(2)) ->method('invalidateOld') - ->with($this->time - 300); + ->withConsecutive( + [$this->time - 150], + [$this->time - 300] + ); $this->tokenProvider->invalidateOldTokens(); } @@ -263,21 +267,18 @@ class PublicKeyTokenProviderTest extends TestCase { $uid = 'user'; $user = 'User'; $password = null; - $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; + $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; $type = IToken::PERMANENT_TOKEN; $oldToken = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER); $this->mapper - ->expects($this->at(0)) + ->expects($this->once()) ->method('getToken') ->with(hash('sha512', 'oldId' . '1f4h9s')) ->willReturn($oldToken); $this->mapper - ->expects($this->at(1)) + ->expects($this->once()) ->method('insert') ->with($this->callback(function (PublicKeyToken $token) use ($user, $uid, $name) { return $token->getUID() === $uid && @@ -288,7 +289,7 @@ class PublicKeyTokenProviderTest extends TestCase { $token->getPassword() === null; })); $this->mapper - ->expects($this->at(2)) + ->expects($this->once()) ->method('delete') ->with($this->callback(function ($token) use ($oldToken) { return $token === $oldToken; @@ -302,21 +303,18 @@ class PublicKeyTokenProviderTest extends TestCase { $uid = 'user'; $user = 'User'; $password = 'password'; - $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; + $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; $type = IToken::PERMANENT_TOKEN; $oldToken = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER); $this->mapper - ->expects($this->at(0)) + ->expects($this->once()) ->method('getToken') ->with(hash('sha512', 'oldId' . '1f4h9s')) ->willReturn($oldToken); $this->mapper - ->expects($this->at(1)) + ->expects($this->once()) ->method('insert') ->with($this->callback(function (PublicKeyToken $token) use ($user, $uid, $name) { return $token->getUID() === $uid && @@ -328,7 +326,7 @@ class PublicKeyTokenProviderTest extends TestCase { $this->tokenProvider->getPassword($token, 'newId') === 'password'; })); $this->mapper - ->expects($this->at(2)) + ->expects($this->once()) ->method('delete') ->with($this->callback(function ($token) use ($oldToken) { return $token === $oldToken; @@ -372,10 +370,7 @@ class PublicKeyTokenProviderTest extends TestCase { $uid = 'user'; $user = 'User'; $password = 'passme'; - $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; + $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; $type = IToken::PERMANENT_TOKEN; $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER); @@ -440,10 +435,7 @@ class PublicKeyTokenProviderTest extends TestCase { $uid = 'user'; $user = 'User'; $password = 'password'; - $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; + $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; $type = IToken::PERMANENT_TOKEN; $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER); @@ -458,10 +450,7 @@ class PublicKeyTokenProviderTest extends TestCase { $uid = 'user'; $user = 'User'; $password = null; - $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12' - . 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; + $name = 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12'; $type = IToken::PERMANENT_TOKEN; $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER); diff --git a/tests/lib/Authentication/TwoFactorAuth/ManagerTest.php b/tests/lib/Authentication/TwoFactorAuth/ManagerTest.php index fc921b8016b..ae6fadc790c 100644 --- a/tests/lib/Authentication/TwoFactorAuth/ManagerTest.php +++ b/tests/lib/Authentication/TwoFactorAuth/ManagerTest.php @@ -376,13 +376,13 @@ class ManagerTest extends TestCase { ->method('get') ->with('two_factor_remember_login') ->willReturn(false); - $this->session->expects($this->at(1)) + $this->session->expects($this->exactly(2)) ->method('remove') - ->with('two_factor_auth_uid'); - $this->session->expects($this->at(2)) - ->method('remove') - ->with('two_factor_remember_login'); - $this->session->expects($this->at(3)) + ->withConsecutive( + ['two_factor_auth_uid'], + ['two_factor_remember_login'] + ); + $this->session->expects($this->once()) ->method('set') ->with(Manager::SESSION_UID_DONE, 'jos'); $this->session->method('getId') @@ -494,17 +494,13 @@ class ManagerTest extends TestCase { public function testNeedsSecondFactor() { $user = $this->createMock(IUser::class); - $this->session->expects($this->at(0)) - ->method('exists') - ->with('app_password') - ->willReturn(false); - $this->session->expects($this->at(1)) + $this->session->expects($this->exactly(3)) ->method('exists') - ->with('two_factor_auth_uid') - ->willReturn(false); - $this->session->expects($this->at(2)) - ->method('exists') - ->with(Manager::SESSION_UID_DONE) + ->withConsecutive( + ['app_password'], + ['two_factor_auth_uid'], + [Manager::SESSION_UID_DONE], + ) ->willReturn(false); $this->session->method('getId') @@ -575,12 +571,12 @@ class ManagerTest extends TestCase { $this->user->method('getUID') ->willReturn('ferdinand'); - $this->session->expects($this->at(0)) - ->method('set') - ->with('two_factor_auth_uid', 'ferdinand'); - $this->session->expects($this->at(1)) + $this->session->expects($this->exactly(2)) ->method('set') - ->with('two_factor_remember_login', true); + ->withConsecutive( + ['two_factor_auth_uid', 'ferdinand'], + ['two_factor_remember_login', true] + ); $this->session->method('getId') ->willReturn('mysessionid'); @@ -605,12 +601,12 @@ class ManagerTest extends TestCase { $this->user->method('getUID') ->willReturn('ferdinand'); - $this->session->expects($this->at(0)) - ->method('set') - ->with('two_factor_auth_uid', 'ferdinand'); - $this->session->expects($this->at(1)) + $this->session->expects($this->exactly(2)) ->method('set') - ->with('two_factor_remember_login', false); + ->withConsecutive( + ['two_factor_auth_uid', 'ferdinand'], + ['two_factor_remember_login', false] + ); $this->session->method('getId') ->willReturn('mysessionid'); |