| @@ -21,79 +21,79 @@ discard block | ||
| 21 | 21 | $nextcloudDir = dirname(__DIR__); | 
| 22 | 22 | |
| 23 | 23 |  class NextcloudNamespaceSkipVoter implements ClassNameImportSkipVoterInterface { | 
| 24 | - private array $namespacePrefixes = [ | |
| 25 | - 'OC', | |
| 26 | - 'OCA', | |
| 27 | - 'OCP', | |
| 28 | - ]; | |
| 29 | - private array $skippedClassNames = [ | |
| 30 | - 'Backend', | |
| 31 | - 'Connection', | |
| 32 | - 'Exception', | |
| 33 | - 'IManager', | |
| 34 | - 'IProvider', | |
| 35 | - 'Manager', | |
| 36 | - 'Plugin', | |
| 37 | - 'Provider', | |
| 38 | - ]; | |
| 39 | -	public function shouldSkip(File $file, FullyQualifiedObjectType $fullyQualifiedObjectType, Node $node) : bool { | |
| 40 | -		if (in_array($fullyQualifiedObjectType->getShortName(), $this->skippedClassNames)) { | |
| 41 | - // Skip common class names to avoid confusion | |
| 42 | - return true; | |
| 43 | - } | |
| 44 | -		foreach ($this->namespacePrefixes as $prefix) { | |
| 45 | -			if (str_starts_with($fullyQualifiedObjectType->getClassName(), $prefix . '\\')) { | |
| 46 | - // Import Nextcloud namespaces | |
| 47 | - return false; | |
| 48 | - } | |
| 49 | - } | |
| 50 | - // Skip everything else | |
| 51 | - return true; | |
| 52 | - } | |
| 24 | + private array $namespacePrefixes = [ | |
| 25 | + 'OC', | |
| 26 | + 'OCA', | |
| 27 | + 'OCP', | |
| 28 | + ]; | |
| 29 | + private array $skippedClassNames = [ | |
| 30 | + 'Backend', | |
| 31 | + 'Connection', | |
| 32 | + 'Exception', | |
| 33 | + 'IManager', | |
| 34 | + 'IProvider', | |
| 35 | + 'Manager', | |
| 36 | + 'Plugin', | |
| 37 | + 'Provider', | |
| 38 | + ]; | |
| 39 | +    public function shouldSkip(File $file, FullyQualifiedObjectType $fullyQualifiedObjectType, Node $node) : bool { | |
| 40 | +        if (in_array($fullyQualifiedObjectType->getShortName(), $this->skippedClassNames)) { | |
| 41 | + // Skip common class names to avoid confusion | |
| 42 | + return true; | |
| 43 | + } | |
| 44 | +        foreach ($this->namespacePrefixes as $prefix) { | |
| 45 | +            if (str_starts_with($fullyQualifiedObjectType->getClassName(), $prefix . '\\')) { | |
| 46 | + // Import Nextcloud namespaces | |
| 47 | + return false; | |
| 48 | + } | |
| 49 | + } | |
| 50 | + // Skip everything else | |
| 51 | + return true; | |
| 52 | + } | |
| 53 | 53 | } | 
| 54 | 54 | |
| 55 | 55 | $config = RectorConfig::configure() | 
| 56 | - ->withPaths([ | |
| 57 | - $nextcloudDir . '/apps', | |
| 58 | - $nextcloudDir . '/core', | |
| 59 | - $nextcloudDir . '/ocs', | |
| 60 | - $nextcloudDir . '/ocs-provider', | |
| 61 | - $nextcloudDir . '/console.php', | |
| 62 | - $nextcloudDir . '/cron.php', | |
| 63 | - $nextcloudDir . '/index.php', | |
| 64 | - $nextcloudDir . '/occ', | |
| 65 | - $nextcloudDir . '/public.php', | |
| 66 | - $nextcloudDir . '/remote.php', | |
| 67 | - $nextcloudDir . '/status.php', | |
| 68 | - $nextcloudDir . '/version.php', | |
| 69 | - $nextcloudDir . '/lib/private/Share20/ProviderFactory.php', | |
| 70 | - $nextcloudDir . '/tests', | |
| 71 | - // $nextcloudDir . '/config', | |
| 72 | - // $nextcloudDir . '/lib', | |
| 73 | - // $nextcloudDir . '/themes', | |
| 74 | - ]) | |
| 75 | - ->withSkip([ | |
| 76 | - $nextcloudDir . '/apps/*/3rdparty/*', | |
| 77 | - $nextcloudDir . '/apps/*/build/stubs/*', | |
| 78 | - $nextcloudDir . '/apps/*/composer/*', | |
| 79 | - $nextcloudDir . '/apps/*/config/*', | |
| 80 | - ]) | |
| 81 | - // uncomment to reach your current PHP version | |
| 82 | - // ->withPhpSets() | |
| 83 | - ->withImportNames(importShortClasses:false) | |
| 84 | - ->withTypeCoverageLevel(0) | |
| 85 | - ->withRules([ | |
| 86 | - UseSpecificWillMethodRector::class, | |
| 87 | - StaticDataProviderClassMethodRector::class, | |
| 88 | - DataProviderAnnotationToAttributeRector::class, | |
| 89 | - ]) | |
| 90 | - ->withConfiguredRule(ClassPropertyAssignToConstructorPromotionRector::class, [ | |
| 91 | - 'inline_public' => true, | |
| 92 | - 'rename_property' => true, | |
| 93 | - ]) | |
| 94 | - ->withSets([ | |
| 95 | - NextcloudSets::NEXTCLOUD_25, | |
| 96 | - ]); | |
| 56 | + ->withPaths([ | |
| 57 | + $nextcloudDir . '/apps', | |
| 58 | + $nextcloudDir . '/core', | |
| 59 | + $nextcloudDir . '/ocs', | |
| 60 | + $nextcloudDir . '/ocs-provider', | |
| 61 | + $nextcloudDir . '/console.php', | |
| 62 | + $nextcloudDir . '/cron.php', | |
| 63 | + $nextcloudDir . '/index.php', | |
| 64 | + $nextcloudDir . '/occ', | |
| 65 | + $nextcloudDir . '/public.php', | |
| 66 | + $nextcloudDir . '/remote.php', | |
| 67 | + $nextcloudDir . '/status.php', | |
| 68 | + $nextcloudDir . '/version.php', | |
| 69 | + $nextcloudDir . '/lib/private/Share20/ProviderFactory.php', | |
| 70 | + $nextcloudDir . '/tests', | |
| 71 | + // $nextcloudDir . '/config', | |
| 72 | + // $nextcloudDir . '/lib', | |
| 73 | + // $nextcloudDir . '/themes', | |
| 74 | + ]) | |
| 75 | + ->withSkip([ | |
| 76 | + $nextcloudDir . '/apps/*/3rdparty/*', | |
| 77 | + $nextcloudDir . '/apps/*/build/stubs/*', | |
| 78 | + $nextcloudDir . '/apps/*/composer/*', | |
| 79 | + $nextcloudDir . '/apps/*/config/*', | |
| 80 | + ]) | |
| 81 | + // uncomment to reach your current PHP version | |
| 82 | + // ->withPhpSets() | |
| 83 | + ->withImportNames(importShortClasses:false) | |
| 84 | + ->withTypeCoverageLevel(0) | |
| 85 | + ->withRules([ | |
| 86 | + UseSpecificWillMethodRector::class, | |
| 87 | + StaticDataProviderClassMethodRector::class, | |
| 88 | + DataProviderAnnotationToAttributeRector::class, | |
| 89 | + ]) | |
| 90 | + ->withConfiguredRule(ClassPropertyAssignToConstructorPromotionRector::class, [ | |
| 91 | + 'inline_public' => true, | |
| 92 | + 'rename_property' => true, | |
| 93 | + ]) | |
| 94 | + ->withSets([ | |
| 95 | + NextcloudSets::NEXTCLOUD_25, | |
| 96 | + ]); | |
| 97 | 97 | |
| 98 | 98 | $config->registerService(NextcloudNamespaceSkipVoter::class, tag:ClassNameImportSkipVoterInterface::class); | 
| 99 | 99 | |
| @@ -105,11 +105,11 @@ discard block | ||
| 105 | 105 | $ignoredEntries = array_values($ignoredEntries); | 
| 106 | 106 | |
| 107 | 107 |  foreach ($ignoredEntries as $ignoredEntry) { | 
| 108 | -	if (str_ends_with($ignoredEntry, '/')) { | |
| 109 | - $config->withSkip([$ignoredEntry . '*']); | |
| 110 | -	} else { | |
| 111 | - $config->withSkip([$ignoredEntry . '/*']); | |
| 112 | - } | |
| 108 | +    if (str_ends_with($ignoredEntry, '/')) { | |
| 109 | + $config->withSkip([$ignoredEntry . '*']); | |
| 110 | +    } else { | |
| 111 | + $config->withSkip([$ignoredEntry . '/*']); | |
| 112 | + } | |
| 113 | 113 | } | 
| 114 | 114 | |
| 115 | 115 | return $config; | 
| @@ -31,7 +31,7 @@ discard block | ||
| 31 | 31 | use Psr\Log\LoggerInterface; | 
| 32 | 32 | |
| 33 | 33 |  if (!str_contains(@ini_get('disable_functions'), 'set_time_limit')) { | 
| 34 | - @set_time_limit(0); | |
| 34 | + @set_time_limit(0); | |
| 35 | 35 | } | 
| 36 | 36 | |
| 37 | 37 | require_once '../../lib/base.php'; | 
| @@ -46,117 +46,117 @@ discard block | ||
| 46 | 46 |  $eventSource->send('success', $l->t('Preparing update')); | 
| 47 | 47 | |
| 48 | 48 |  if (Util::needUpgrade()) { | 
| 49 | - $config = Server::get(SystemConfig::class); | |
| 50 | -	if ($config->getValue('upgrade.disable-web', false)) { | |
| 51 | -		$eventSource->send('failure', $l->t('Please use the command line updater because updating via browser is disabled in your config.php.')); | |
| 52 | - $eventSource->close(); | |
| 53 | - exit(); | |
| 54 | - } | |
| 49 | + $config = Server::get(SystemConfig::class); | |
| 50 | +    if ($config->getValue('upgrade.disable-web', false)) { | |
| 51 | +        $eventSource->send('failure', $l->t('Please use the command line updater because updating via browser is disabled in your config.php.')); | |
| 52 | + $eventSource->close(); | |
| 53 | + exit(); | |
| 54 | + } | |
| 55 | 55 | |
| 56 | - // if a user is currently logged in, their session must be ignored to | |
| 57 | - // avoid side effects | |
| 58 | - \OC_User::setIncognitoMode(true); | |
| 56 | + // if a user is currently logged in, their session must be ignored to | |
| 57 | + // avoid side effects | |
| 58 | + \OC_User::setIncognitoMode(true); | |
| 59 | 59 | |
| 60 | - $config = Server::get(IConfig::class); | |
| 61 | - $updater = new Updater( | |
| 62 | - Server::get(ServerVersion::class), | |
| 63 | - $config, | |
| 64 | - Server::get(IAppConfig::class), | |
| 65 | - Server::get(Checker::class), | |
| 66 | - Server::get(LoggerInterface::class), | |
| 67 | - Server::get(Installer::class) | |
| 68 | - ); | |
| 69 | - $incompatibleApps = []; | |
| 70 | -	$incompatibleOverwrites = $config->getSystemValue('app_install_overwrite', []); | |
| 60 | + $config = Server::get(IConfig::class); | |
| 61 | + $updater = new Updater( | |
| 62 | + Server::get(ServerVersion::class), | |
| 63 | + $config, | |
| 64 | + Server::get(IAppConfig::class), | |
| 65 | + Server::get(Checker::class), | |
| 66 | + Server::get(LoggerInterface::class), | |
| 67 | + Server::get(Installer::class) | |
| 68 | + ); | |
| 69 | + $incompatibleApps = []; | |
| 70 | +    $incompatibleOverwrites = $config->getSystemValue('app_install_overwrite', []); | |
| 71 | 71 | |
| 72 | - /** @var IEventDispatcher $dispatcher */ | |
| 73 | - $dispatcher = Server::get(IEventDispatcher::class); | |
| 74 | - $dispatcher->addListener( | |
| 75 | - MigratorExecuteSqlEvent::class, | |
| 76 | -		function (MigratorExecuteSqlEvent $event) use ($eventSource, $l): void { | |
| 77 | -			$eventSource->send('success', $l->t('[%d / %d]: %s', [$event->getCurrentStep(), $event->getMaxStep(), $event->getSql()])); | |
| 78 | - } | |
| 79 | - ); | |
| 80 | - $feedBack = new FeedBackHandler($eventSource, $l); | |
| 81 | - $dispatcher->addListener(RepairStartEvent::class, [$feedBack, 'handleRepairFeedback']); | |
| 82 | - $dispatcher->addListener(RepairAdvanceEvent::class, [$feedBack, 'handleRepairFeedback']); | |
| 83 | - $dispatcher->addListener(RepairFinishEvent::class, [$feedBack, 'handleRepairFeedback']); | |
| 84 | - $dispatcher->addListener(RepairStepEvent::class, [$feedBack, 'handleRepairFeedback']); | |
| 85 | - $dispatcher->addListener(RepairInfoEvent::class, [$feedBack, 'handleRepairFeedback']); | |
| 86 | - $dispatcher->addListener(RepairWarningEvent::class, [$feedBack, 'handleRepairFeedback']); | |
| 87 | - $dispatcher->addListener(RepairErrorEvent::class, [$feedBack, 'handleRepairFeedback']); | |
| 72 | + /** @var IEventDispatcher $dispatcher */ | |
| 73 | + $dispatcher = Server::get(IEventDispatcher::class); | |
| 74 | + $dispatcher->addListener( | |
| 75 | + MigratorExecuteSqlEvent::class, | |
| 76 | +        function (MigratorExecuteSqlEvent $event) use ($eventSource, $l): void { | |
| 77 | +            $eventSource->send('success', $l->t('[%d / %d]: %s', [$event->getCurrentStep(), $event->getMaxStep(), $event->getSql()])); | |
| 78 | + } | |
| 79 | + ); | |
| 80 | + $feedBack = new FeedBackHandler($eventSource, $l); | |
| 81 | + $dispatcher->addListener(RepairStartEvent::class, [$feedBack, 'handleRepairFeedback']); | |
| 82 | + $dispatcher->addListener(RepairAdvanceEvent::class, [$feedBack, 'handleRepairFeedback']); | |
| 83 | + $dispatcher->addListener(RepairFinishEvent::class, [$feedBack, 'handleRepairFeedback']); | |
| 84 | + $dispatcher->addListener(RepairStepEvent::class, [$feedBack, 'handleRepairFeedback']); | |
| 85 | + $dispatcher->addListener(RepairInfoEvent::class, [$feedBack, 'handleRepairFeedback']); | |
| 86 | + $dispatcher->addListener(RepairWarningEvent::class, [$feedBack, 'handleRepairFeedback']); | |
| 87 | + $dispatcher->addListener(RepairErrorEvent::class, [$feedBack, 'handleRepairFeedback']); | |
| 88 | 88 | |
| 89 | -	$updater->listen('\OC\Updater', 'maintenanceEnabled', function () use ($eventSource, $l): void { | |
| 90 | -		$eventSource->send('success', $l->t('Turned on maintenance mode')); | |
| 91 | - }); | |
| 92 | -	$updater->listen('\OC\Updater', 'maintenanceDisabled', function () use ($eventSource, $l): void { | |
| 93 | -		$eventSource->send('success', $l->t('Turned off maintenance mode')); | |
| 94 | - }); | |
| 95 | -	$updater->listen('\OC\Updater', 'maintenanceActive', function () use ($eventSource, $l): void { | |
| 96 | -		$eventSource->send('success', $l->t('Maintenance mode is kept active')); | |
| 97 | - }); | |
| 98 | -	$updater->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($eventSource, $l): void { | |
| 99 | -		$eventSource->send('success', $l->t('Updating database schema')); | |
| 100 | - }); | |
| 101 | -	$updater->listen('\OC\Updater', 'dbUpgrade', function () use ($eventSource, $l): void { | |
| 102 | -		$eventSource->send('success', $l->t('Updated database')); | |
| 103 | - }); | |
| 104 | -	$updater->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($eventSource, $l): void { | |
| 105 | -		$eventSource->send('success', $l->t('Update app "%s" from App Store', [$app])); | |
| 106 | - }); | |
| 107 | -	$updater->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($eventSource, $l): void { | |
| 108 | -		$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])); | |
| 109 | - }); | |
| 110 | -	$updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($eventSource, $l): void { | |
| 111 | -		$eventSource->send('success', $l->t('Updated "%1$s" to %2$s', [$app, $version])); | |
| 112 | - }); | |
| 113 | -	$updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use (&$incompatibleApps, &$incompatibleOverwrites): void { | |
| 114 | -		if (!in_array($app, $incompatibleOverwrites)) { | |
| 115 | - $incompatibleApps[] = $app; | |
| 116 | - } | |
| 117 | - }); | |
| 118 | -	$updater->listen('\OC\Updater', 'failure', function ($message) use ($eventSource, $config): void { | |
| 119 | -		$eventSource->send('failure', $message); | |
| 120 | - $eventSource->close(); | |
| 121 | -		$config->setSystemValue('maintenance', false); | |
| 122 | - }); | |
| 123 | -	$updater->listen('\OC\Updater', 'setDebugLogLevel', function ($logLevel, $logLevelName) use ($eventSource, $l): void { | |
| 124 | -		$eventSource->send('success', $l->t('Set log level to debug')); | |
| 125 | - }); | |
| 126 | -	$updater->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($eventSource, $l): void { | |
| 127 | -		$eventSource->send('success', $l->t('Reset log level')); | |
| 128 | - }); | |
| 129 | -	$updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($eventSource, $l): void { | |
| 130 | -		$eventSource->send('success', $l->t('Starting code integrity check')); | |
| 131 | - }); | |
| 132 | -	$updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($eventSource, $l): void { | |
| 133 | -		$eventSource->send('success', $l->t('Finished code integrity check')); | |
| 134 | - }); | |
| 89 | +    $updater->listen('\OC\Updater', 'maintenanceEnabled', function () use ($eventSource, $l): void { | |
| 90 | +        $eventSource->send('success', $l->t('Turned on maintenance mode')); | |
| 91 | + }); | |
| 92 | +    $updater->listen('\OC\Updater', 'maintenanceDisabled', function () use ($eventSource, $l): void { | |
| 93 | +        $eventSource->send('success', $l->t('Turned off maintenance mode')); | |
| 94 | + }); | |
| 95 | +    $updater->listen('\OC\Updater', 'maintenanceActive', function () use ($eventSource, $l): void { | |
| 96 | +        $eventSource->send('success', $l->t('Maintenance mode is kept active')); | |
| 97 | + }); | |
| 98 | +    $updater->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($eventSource, $l): void { | |
| 99 | +        $eventSource->send('success', $l->t('Updating database schema')); | |
| 100 | + }); | |
| 101 | +    $updater->listen('\OC\Updater', 'dbUpgrade', function () use ($eventSource, $l): void { | |
| 102 | +        $eventSource->send('success', $l->t('Updated database')); | |
| 103 | + }); | |
| 104 | +    $updater->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($eventSource, $l): void { | |
| 105 | +        $eventSource->send('success', $l->t('Update app "%s" from App Store', [$app])); | |
| 106 | + }); | |
| 107 | +    $updater->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($eventSource, $l): void { | |
| 108 | +        $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])); | |
| 109 | + }); | |
| 110 | +    $updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($eventSource, $l): void { | |
| 111 | +        $eventSource->send('success', $l->t('Updated "%1$s" to %2$s', [$app, $version])); | |
| 112 | + }); | |
| 113 | +    $updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use (&$incompatibleApps, &$incompatibleOverwrites): void { | |
| 114 | +        if (!in_array($app, $incompatibleOverwrites)) { | |
| 115 | + $incompatibleApps[] = $app; | |
| 116 | + } | |
| 117 | + }); | |
| 118 | +    $updater->listen('\OC\Updater', 'failure', function ($message) use ($eventSource, $config): void { | |
| 119 | +        $eventSource->send('failure', $message); | |
| 120 | + $eventSource->close(); | |
| 121 | +        $config->setSystemValue('maintenance', false); | |
| 122 | + }); | |
| 123 | +    $updater->listen('\OC\Updater', 'setDebugLogLevel', function ($logLevel, $logLevelName) use ($eventSource, $l): void { | |
| 124 | +        $eventSource->send('success', $l->t('Set log level to debug')); | |
| 125 | + }); | |
| 126 | +    $updater->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($eventSource, $l): void { | |
| 127 | +        $eventSource->send('success', $l->t('Reset log level')); | |
| 128 | + }); | |
| 129 | +    $updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($eventSource, $l): void { | |
| 130 | +        $eventSource->send('success', $l->t('Starting code integrity check')); | |
| 131 | + }); | |
| 132 | +    $updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($eventSource, $l): void { | |
| 133 | +        $eventSource->send('success', $l->t('Finished code integrity check')); | |
| 134 | + }); | |
| 135 | 135 | |
| 136 | -	try { | |
| 137 | - $updater->upgrade(); | |
| 138 | -	} catch (\Exception $e) { | |
| 139 | - Server::get(LoggerInterface::class)->error( | |
| 140 | - $e->getMessage(), | |
| 141 | - [ | |
| 142 | - 'exception' => $e, | |
| 143 | - 'app' => 'update', | |
| 144 | - ]); | |
| 145 | -		$eventSource->send('failure', get_class($e) . ': ' . $e->getMessage()); | |
| 146 | - $eventSource->close(); | |
| 147 | - exit(); | |
| 148 | - } | |
| 136 | +    try { | |
| 137 | + $updater->upgrade(); | |
| 138 | +    } catch (\Exception $e) { | |
| 139 | + Server::get(LoggerInterface::class)->error( | |
| 140 | + $e->getMessage(), | |
| 141 | + [ | |
| 142 | + 'exception' => $e, | |
| 143 | + 'app' => 'update', | |
| 144 | + ]); | |
| 145 | +        $eventSource->send('failure', get_class($e) . ': ' . $e->getMessage()); | |
| 146 | + $eventSource->close(); | |
| 147 | + exit(); | |
| 148 | + } | |
| 149 | 149 | |
| 150 | - $disabledApps = []; | |
| 151 | -	foreach ($incompatibleApps as $app) { | |
| 152 | -		$disabledApps[$app] = $l->t('%s (incompatible)', [$app]); | |
| 153 | - } | |
| 150 | + $disabledApps = []; | |
| 151 | +    foreach ($incompatibleApps as $app) { | |
| 152 | +        $disabledApps[$app] = $l->t('%s (incompatible)', [$app]); | |
| 153 | + } | |
| 154 | 154 | |
| 155 | -	if (!empty($disabledApps)) { | |
| 156 | -		$eventSource->send('notice', $l->t('The following apps have been disabled: %s', [implode(', ', $disabledApps)])); | |
| 157 | - } | |
| 155 | +    if (!empty($disabledApps)) { | |
| 156 | +        $eventSource->send('notice', $l->t('The following apps have been disabled: %s', [implode(', ', $disabledApps)])); | |
| 157 | + } | |
| 158 | 158 |  } else { | 
| 159 | -	$eventSource->send('notice', $l->t('Already up to date')); | |
| 159 | +    $eventSource->send('notice', $l->t('Already up to date')); | |
| 160 | 160 | } | 
| 161 | 161 | |
| 162 | 162 |  $eventSource->send('done', ''); | 
| @@ -27,139 +27,139 @@ | ||
| 27 | 27 | * @group DB | 
| 28 | 28 | */ | 
| 29 | 29 |  class AccountMigratorTest extends TestCase { | 
| 30 | - private IUserManager $userManager; | |
| 31 | - private IAvatarManager $avatarManager; | |
| 32 | - private AccountMigrator $migrator; | |
| 33 | - private IImportSource&MockObject $importSource; | |
| 34 | - private IExportDestination&MockObject $exportDestination; | |
| 35 | - private OutputInterface&MockObject $output; | |
| 36 | - | |
| 37 | - private const ASSETS_DIR = __DIR__ . '/assets/'; | |
| 38 | - | |
| 39 | - private const REGEX_ACCOUNT_FILE = '/^' . Application::APP_ID . '\/' . '[a-z]+\.json' . '$/'; | |
| 40 | - | |
| 41 | - private const REGEX_AVATAR_FILE = '/^' . Application::APP_ID . '\/' . 'avatar\.(jpg|png)' . '$/'; | |
| 42 | - | |
| 43 | - private const REGEX_CONFIG_FILE = '/^' . Application::APP_ID . '\/' . '[a-z]+\.json' . '$/'; | |
| 44 | - | |
| 45 | -	protected function setUp(): void { | |
| 46 | - parent::setUp(); | |
| 47 | - | |
| 48 | - $app = new App(Application::APP_ID); | |
| 49 | - $container = $app->getContainer(); | |
| 50 | -		$container->get(IConfig::class)->setSystemValue('has_internet_connection', false); | |
| 51 | - | |
| 52 | - $this->userManager = $container->get(IUserManager::class); | |
| 53 | - $this->avatarManager = $container->get(IAvatarManager::class); | |
| 54 | - $this->migrator = $container->get(AccountMigrator::class); | |
| 55 | - | |
| 56 | - $this->importSource = $this->createMock(IImportSource::class); | |
| 57 | - $this->exportDestination = $this->createMock(IExportDestination::class); | |
| 58 | - $this->output = $this->createMock(OutputInterface::class); | |
| 59 | - } | |
| 60 | - | |
| 61 | -	protected function tearDown(): void { | |
| 62 | -		Server::get(IConfig::class)->setSystemValue('has_internet_connection', true); | |
| 63 | - parent::tearDown(); | |
| 64 | - } | |
| 65 | - | |
| 66 | -	public static function dataImportExportAccount(): array { | |
| 67 | - return array_map( | |
| 68 | -			static function (string $filename): array { | |
| 69 | - $dataPath = static::ASSETS_DIR . $filename; | |
| 70 | - // For each account json file there is an avatar image and a config json file with the same basename | |
| 71 | - $basename = pathinfo($filename, PATHINFO_FILENAME); | |
| 72 | - $avatarPath = static::ASSETS_DIR . (file_exists(static::ASSETS_DIR . "$basename.jpg") ? "$basename.jpg" : "$basename.png"); | |
| 73 | - $configPath = static::ASSETS_DIR . "$basename-config." . pathinfo($filename, PATHINFO_EXTENSION); | |
| 74 | - return [ | |
| 75 | - UUIDUtil::getUUID(), | |
| 76 | - json_decode(file_get_contents($dataPath), true, 512, JSON_THROW_ON_ERROR), | |
| 77 | - $avatarPath, | |
| 78 | - json_decode(file_get_contents($configPath), true, 512, JSON_THROW_ON_ERROR), | |
| 79 | - ]; | |
| 80 | - }, | |
| 81 | - array_filter( | |
| 82 | - scandir(static::ASSETS_DIR), | |
| 83 | - fn (string $filename) => pathinfo($filename, PATHINFO_EXTENSION) === 'json' && mb_strpos(pathinfo($filename, PATHINFO_FILENAME), 'config') === false, | |
| 84 | - ), | |
| 85 | - ); | |
| 86 | - } | |
| 87 | - | |
| 88 | -	#[\PHPUnit\Framework\Attributes\DataProvider('dataImportExportAccount')] | |
| 89 | -	public function testImportExportAccount(string $userId, array $importData, string $avatarPath, array $importConfig): void { | |
| 90 | - $user = $this->userManager->createUser($userId, 'topsecretpassword'); | |
| 91 | - $avatarExt = pathinfo($avatarPath, PATHINFO_EXTENSION); | |
| 92 | - $exportData = $importData; | |
| 93 | - $exportConfig = $importConfig; | |
| 94 | - // Verification status of email will be set to in progress on import so we set the export data to reflect that | |
| 95 | - $exportData[IAccountManager::PROPERTY_EMAIL]['verified'] = IAccountManager::VERIFICATION_IN_PROGRESS; | |
| 96 | - | |
| 97 | - $this->importSource | |
| 98 | - ->expects($this->once()) | |
| 99 | -			->method('getMigratorVersion') | |
| 100 | - ->with($this->migrator->getId()) | |
| 101 | - ->willReturn(1); | |
| 102 | - | |
| 103 | - $calls = [ | |
| 104 | - [static::REGEX_ACCOUNT_FILE, json_encode($importData)], | |
| 105 | - [static::REGEX_CONFIG_FILE, json_encode($importConfig)], | |
| 106 | - ]; | |
| 107 | - $this->importSource | |
| 108 | - ->expects($this->exactly(2)) | |
| 109 | -			->method('getFileContents') | |
| 110 | -			->willReturnCallback(function ($path) use (&$calls) { | |
| 111 | - $expected = array_shift($calls); | |
| 112 | - $this->assertMatchesRegularExpression($expected[0], $path); | |
| 113 | - return $expected[1]; | |
| 114 | - }); | |
| 115 | - | |
| 116 | - $this->importSource | |
| 117 | - ->expects($this->once()) | |
| 118 | -			->method('getFolderListing') | |
| 119 | - ->with(Application::APP_ID . '/') | |
| 120 | - ->willReturn(["avatar.$avatarExt"]); | |
| 121 | - | |
| 122 | - $this->importSource | |
| 123 | - ->expects($this->once()) | |
| 124 | -			->method('getFileAsStream') | |
| 125 | - ->with($this->matchesRegularExpression(static::REGEX_AVATAR_FILE)) | |
| 126 | - ->willReturn(fopen($avatarPath, 'r')); | |
| 127 | - | |
| 128 | - $this->migrator->import($user, $this->importSource, $this->output); | |
| 129 | - | |
| 130 | - $importedAvatar = $this->avatarManager->getAvatar($user->getUID()); | |
| 131 | - $this->assertTrue($importedAvatar->isCustomAvatar()); | |
| 132 | - | |
| 133 | - /** | |
| 134 | - * Avatar images are re-encoded on import therefore JPEG images which use lossy compression cannot be checked for equality | |
| 135 | - * @see https://github.com/nextcloud/server/blob/9644b7e505dc90a1e683f77ad38dc6dc4e90fa2f/lib/private/legacy/OC_Image.php#L383-L390 | |
| 136 | - */ | |
| 137 | - | |
| 138 | -		if ($avatarExt !== 'jpg') { | |
| 139 | - $this->assertStringEqualsFile( | |
| 140 | - $avatarPath, | |
| 141 | - $importedAvatar->getFile(-1)->getContent(), | |
| 142 | - ); | |
| 143 | - } | |
| 144 | - | |
| 145 | - $calls = [ | |
| 146 | - [static::REGEX_ACCOUNT_FILE, new JsonMatches(json_encode($importData))], | |
| 147 | - [static::REGEX_CONFIG_FILE,new JsonMatches(json_encode($importConfig))], | |
| 148 | - ]; | |
| 149 | - $this->exportDestination | |
| 150 | - ->expects($this->exactly(2)) | |
| 151 | -			->method('addFileContents') | |
| 152 | -			->willReturnCallback(function ($path) use (&$calls) { | |
| 153 | - $expected = array_shift($calls); | |
| 154 | - $this->assertMatchesRegularExpression($expected[0], $path); | |
| 155 | - return $expected[1]; | |
| 156 | - }); | |
| 157 | - | |
| 158 | - $this->exportDestination | |
| 159 | - ->expects($this->once()) | |
| 160 | -			->method('addFileAsStream') | |
| 161 | -			->with($this->matchesRegularExpression(static::REGEX_AVATAR_FILE), $this->isType('resource')); | |
| 162 | - | |
| 163 | - $this->migrator->export($user, $this->exportDestination, $this->output); | |
| 164 | - } | |
| 30 | + private IUserManager $userManager; | |
| 31 | + private IAvatarManager $avatarManager; | |
| 32 | + private AccountMigrator $migrator; | |
| 33 | + private IImportSource&MockObject $importSource; | |
| 34 | + private IExportDestination&MockObject $exportDestination; | |
| 35 | + private OutputInterface&MockObject $output; | |
| 36 | + | |
| 37 | + private const ASSETS_DIR = __DIR__ . '/assets/'; | |
| 38 | + | |
| 39 | + private const REGEX_ACCOUNT_FILE = '/^' . Application::APP_ID . '\/' . '[a-z]+\.json' . '$/'; | |
| 40 | + | |
| 41 | + private const REGEX_AVATAR_FILE = '/^' . Application::APP_ID . '\/' . 'avatar\.(jpg|png)' . '$/'; | |
| 42 | + | |
| 43 | + private const REGEX_CONFIG_FILE = '/^' . Application::APP_ID . '\/' . '[a-z]+\.json' . '$/'; | |
| 44 | + | |
| 45 | +    protected function setUp(): void { | |
| 46 | + parent::setUp(); | |
| 47 | + | |
| 48 | + $app = new App(Application::APP_ID); | |
| 49 | + $container = $app->getContainer(); | |
| 50 | +        $container->get(IConfig::class)->setSystemValue('has_internet_connection', false); | |
| 51 | + | |
| 52 | + $this->userManager = $container->get(IUserManager::class); | |
| 53 | + $this->avatarManager = $container->get(IAvatarManager::class); | |
| 54 | + $this->migrator = $container->get(AccountMigrator::class); | |
| 55 | + | |
| 56 | + $this->importSource = $this->createMock(IImportSource::class); | |
| 57 | + $this->exportDestination = $this->createMock(IExportDestination::class); | |
| 58 | + $this->output = $this->createMock(OutputInterface::class); | |
| 59 | + } | |
| 60 | + | |
| 61 | +    protected function tearDown(): void { | |
| 62 | +        Server::get(IConfig::class)->setSystemValue('has_internet_connection', true); | |
| 63 | + parent::tearDown(); | |
| 64 | + } | |
| 65 | + | |
| 66 | +    public static function dataImportExportAccount(): array { | |
| 67 | + return array_map( | |
| 68 | +            static function (string $filename): array { | |
| 69 | + $dataPath = static::ASSETS_DIR . $filename; | |
| 70 | + // For each account json file there is an avatar image and a config json file with the same basename | |
| 71 | + $basename = pathinfo($filename, PATHINFO_FILENAME); | |
| 72 | + $avatarPath = static::ASSETS_DIR . (file_exists(static::ASSETS_DIR . "$basename.jpg") ? "$basename.jpg" : "$basename.png"); | |
| 73 | + $configPath = static::ASSETS_DIR . "$basename-config." . pathinfo($filename, PATHINFO_EXTENSION); | |
| 74 | + return [ | |
| 75 | + UUIDUtil::getUUID(), | |
| 76 | + json_decode(file_get_contents($dataPath), true, 512, JSON_THROW_ON_ERROR), | |
| 77 | + $avatarPath, | |
| 78 | + json_decode(file_get_contents($configPath), true, 512, JSON_THROW_ON_ERROR), | |
| 79 | + ]; | |
| 80 | + }, | |
| 81 | + array_filter( | |
| 82 | + scandir(static::ASSETS_DIR), | |
| 83 | + fn (string $filename) => pathinfo($filename, PATHINFO_EXTENSION) === 'json' && mb_strpos(pathinfo($filename, PATHINFO_FILENAME), 'config') === false, | |
| 84 | + ), | |
| 85 | + ); | |
| 86 | + } | |
| 87 | + | |
| 88 | +    #[\PHPUnit\Framework\Attributes\DataProvider('dataImportExportAccount')] | |
| 89 | +    public function testImportExportAccount(string $userId, array $importData, string $avatarPath, array $importConfig): void { | |
| 90 | + $user = $this->userManager->createUser($userId, 'topsecretpassword'); | |
| 91 | + $avatarExt = pathinfo($avatarPath, PATHINFO_EXTENSION); | |
| 92 | + $exportData = $importData; | |
| 93 | + $exportConfig = $importConfig; | |
| 94 | + // Verification status of email will be set to in progress on import so we set the export data to reflect that | |
| 95 | + $exportData[IAccountManager::PROPERTY_EMAIL]['verified'] = IAccountManager::VERIFICATION_IN_PROGRESS; | |
| 96 | + | |
| 97 | + $this->importSource | |
| 98 | + ->expects($this->once()) | |
| 99 | +            ->method('getMigratorVersion') | |
| 100 | + ->with($this->migrator->getId()) | |
| 101 | + ->willReturn(1); | |
| 102 | + | |
| 103 | + $calls = [ | |
| 104 | + [static::REGEX_ACCOUNT_FILE, json_encode($importData)], | |
| 105 | + [static::REGEX_CONFIG_FILE, json_encode($importConfig)], | |
| 106 | + ]; | |
| 107 | + $this->importSource | |
| 108 | + ->expects($this->exactly(2)) | |
| 109 | +            ->method('getFileContents') | |
| 110 | +            ->willReturnCallback(function ($path) use (&$calls) { | |
| 111 | + $expected = array_shift($calls); | |
| 112 | + $this->assertMatchesRegularExpression($expected[0], $path); | |
| 113 | + return $expected[1]; | |
| 114 | + }); | |
| 115 | + | |
| 116 | + $this->importSource | |
| 117 | + ->expects($this->once()) | |
| 118 | +            ->method('getFolderListing') | |
| 119 | + ->with(Application::APP_ID . '/') | |
| 120 | + ->willReturn(["avatar.$avatarExt"]); | |
| 121 | + | |
| 122 | + $this->importSource | |
| 123 | + ->expects($this->once()) | |
| 124 | +            ->method('getFileAsStream') | |
| 125 | + ->with($this->matchesRegularExpression(static::REGEX_AVATAR_FILE)) | |
| 126 | + ->willReturn(fopen($avatarPath, 'r')); | |
| 127 | + | |
| 128 | + $this->migrator->import($user, $this->importSource, $this->output); | |
| 129 | + | |
| 130 | + $importedAvatar = $this->avatarManager->getAvatar($user->getUID()); | |
| 131 | + $this->assertTrue($importedAvatar->isCustomAvatar()); | |
| 132 | + | |
| 133 | + /** | |
| 134 | + * Avatar images are re-encoded on import therefore JPEG images which use lossy compression cannot be checked for equality | |
| 135 | + * @see https://github.com/nextcloud/server/blob/9644b7e505dc90a1e683f77ad38dc6dc4e90fa2f/lib/private/legacy/OC_Image.php#L383-L390 | |
| 136 | + */ | |
| 137 | + | |
| 138 | +        if ($avatarExt !== 'jpg') { | |
| 139 | + $this->assertStringEqualsFile( | |
| 140 | + $avatarPath, | |
| 141 | + $importedAvatar->getFile(-1)->getContent(), | |
| 142 | + ); | |
| 143 | + } | |
| 144 | + | |
| 145 | + $calls = [ | |
| 146 | + [static::REGEX_ACCOUNT_FILE, new JsonMatches(json_encode($importData))], | |
| 147 | + [static::REGEX_CONFIG_FILE,new JsonMatches(json_encode($importConfig))], | |
| 148 | + ]; | |
| 149 | + $this->exportDestination | |
| 150 | + ->expects($this->exactly(2)) | |
| 151 | +            ->method('addFileContents') | |
| 152 | +            ->willReturnCallback(function ($path) use (&$calls) { | |
| 153 | + $expected = array_shift($calls); | |
| 154 | + $this->assertMatchesRegularExpression($expected[0], $path); | |
| 155 | + return $expected[1]; | |
| 156 | + }); | |
| 157 | + | |
| 158 | + $this->exportDestination | |
| 159 | + ->expects($this->once()) | |
| 160 | +            ->method('addFileAsStream') | |
| 161 | +            ->with($this->matchesRegularExpression(static::REGEX_AVATAR_FILE), $this->isType('resource')); | |
| 162 | + | |
| 163 | + $this->migrator->export($user, $this->exportDestination, $this->output); | |
| 164 | + } | |
| 165 | 165 | } | 
| @@ -28,36 +28,36 @@ | ||
| 28 | 28 | * @group DB | 
| 29 | 29 | */ | 
| 30 | 30 |  class ApplicationTest extends TestCase { | 
| 31 | - protected Application $app; | |
| 32 | - protected IAppContainer $container; | |
| 33 | - | |
| 34 | -	protected function setUp(): void { | |
| 35 | - parent::setUp(); | |
| 36 | - $this->app = new Application(); | |
| 37 | - $this->container = $this->app->getContainer(); | |
| 38 | - } | |
| 39 | - | |
| 40 | -	public function testContainerAppName(): void { | |
| 41 | - $this->app = new Application(); | |
| 42 | -		$this->assertEquals('settings', $this->container->getAppName()); | |
| 43 | - } | |
| 44 | - | |
| 45 | -	public static function dataContainerQuery(): array { | |
| 46 | - return [ | |
| 47 | - [AdminSettingsController::class, Controller::class], | |
| 48 | - [AppSettingsController::class, Controller::class], | |
| 49 | - [AuthSettingsController::class, Controller::class], | |
| 50 | - [CheckSetupController::class, Controller::class], | |
| 51 | - [LogSettingsController::class, Controller::class], | |
| 52 | - [MailSettingsController::class, Controller::class], | |
| 53 | - [UsersController::class, Controller::class], | |
| 54 | - | |
| 55 | - [SubadminMiddleware::class, Middleware::class], | |
| 56 | - ]; | |
| 57 | - } | |
| 58 | - | |
| 59 | -	#[\PHPUnit\Framework\Attributes\DataProvider('dataContainerQuery')] | |
| 60 | -	public function testContainerQuery(string $service, string $expected): void { | |
| 61 | - $this->assertTrue($this->container->query($service) instanceof $expected); | |
| 62 | - } | |
| 31 | + protected Application $app; | |
| 32 | + protected IAppContainer $container; | |
| 33 | + | |
| 34 | +    protected function setUp(): void { | |
| 35 | + parent::setUp(); | |
| 36 | + $this->app = new Application(); | |
| 37 | + $this->container = $this->app->getContainer(); | |
| 38 | + } | |
| 39 | + | |
| 40 | +    public function testContainerAppName(): void { | |
| 41 | + $this->app = new Application(); | |
| 42 | +        $this->assertEquals('settings', $this->container->getAppName()); | |
| 43 | + } | |
| 44 | + | |
| 45 | +    public static function dataContainerQuery(): array { | |
| 46 | + return [ | |
| 47 | + [AdminSettingsController::class, Controller::class], | |
| 48 | + [AppSettingsController::class, Controller::class], | |
| 49 | + [AuthSettingsController::class, Controller::class], | |
| 50 | + [CheckSetupController::class, Controller::class], | |
| 51 | + [LogSettingsController::class, Controller::class], | |
| 52 | + [MailSettingsController::class, Controller::class], | |
| 53 | + [UsersController::class, Controller::class], | |
| 54 | + | |
| 55 | + [SubadminMiddleware::class, Middleware::class], | |
| 56 | + ]; | |
| 57 | + } | |
| 58 | + | |
| 59 | +    #[\PHPUnit\Framework\Attributes\DataProvider('dataContainerQuery')] | |
| 60 | +    public function testContainerQuery(string $service, string $expected): void { | |
| 61 | + $this->assertTrue($this->container->query($service) instanceof $expected); | |
| 62 | + } | |
| 63 | 63 | } | 
| @@ -17,103 +17,103 @@ | ||
| 17 | 17 | use Test\TestCase; | 
| 18 | 18 | |
| 19 | 19 |  class ForwardedForHeadersTest extends TestCase { | 
| 20 | - private IL10N $l10n; | |
| 21 | - private IConfig $config; | |
| 22 | - private IURLGenerator $urlGenerator; | |
| 23 | - private IRequest $request; | |
| 24 | - private ForwardedForHeaders $check; | |
| 20 | + private IL10N $l10n; | |
| 21 | + private IConfig $config; | |
| 22 | + private IURLGenerator $urlGenerator; | |
| 23 | + private IRequest $request; | |
| 24 | + private ForwardedForHeaders $check; | |
| 25 | 25 | |
| 26 | -	protected function setUp(): void { | |
| 27 | - parent::setUp(); | |
| 26 | +    protected function setUp(): void { | |
| 27 | + parent::setUp(); | |
| 28 | 28 | |
| 29 | - $this->l10n = $this->createMock(IL10N::class); | |
| 30 | - $this->l10n->expects($this->any()) | |
| 31 | -			->method('t') | |
| 32 | -			->willReturnCallback(function ($message, array $replace) { | |
| 33 | - return vsprintf($message, $replace); | |
| 34 | - }); | |
| 35 | - $this->config = $this->getMockBuilder(IConfig::class)->getMock(); | |
| 36 | - $this->urlGenerator = $this->getMockBuilder(IURLGenerator::class)->getMock(); | |
| 37 | - $this->request = $this->getMockBuilder(IRequest::class)->getMock(); | |
| 38 | - $this->check = new ForwardedForHeaders( | |
| 39 | - $this->l10n, | |
| 40 | - $this->config, | |
| 41 | - $this->urlGenerator, | |
| 42 | - $this->request, | |
| 43 | - ); | |
| 44 | - } | |
| 29 | + $this->l10n = $this->createMock(IL10N::class); | |
| 30 | + $this->l10n->expects($this->any()) | |
| 31 | +            ->method('t') | |
| 32 | +            ->willReturnCallback(function ($message, array $replace) { | |
| 33 | + return vsprintf($message, $replace); | |
| 34 | + }); | |
| 35 | + $this->config = $this->getMockBuilder(IConfig::class)->getMock(); | |
| 36 | + $this->urlGenerator = $this->getMockBuilder(IURLGenerator::class)->getMock(); | |
| 37 | + $this->request = $this->getMockBuilder(IRequest::class)->getMock(); | |
| 38 | + $this->check = new ForwardedForHeaders( | |
| 39 | + $this->l10n, | |
| 40 | + $this->config, | |
| 41 | + $this->urlGenerator, | |
| 42 | + $this->request, | |
| 43 | + ); | |
| 44 | + } | |
| 45 | 45 | |
| 46 | -	#[\PHPUnit\Framework\Attributes\DataProvider('dataForwardedForHeadersWorking')] | |
| 47 | -	public function testForwardedForHeadersWorking(array $trustedProxies, string $remoteAddrNotForwarded, string $remoteAddr, string $result): void { | |
| 48 | - $this->config->expects($this->once()) | |
| 49 | -			->method('getSystemValue') | |
| 50 | -			->with('trusted_proxies', []) | |
| 51 | - ->willReturn($trustedProxies); | |
| 52 | - $this->request->expects($this->atLeastOnce()) | |
| 53 | -			->method('getHeader') | |
| 54 | - ->willReturnMap([ | |
| 55 | - ['REMOTE_ADDR', $remoteAddrNotForwarded], | |
| 56 | - ['X-Forwarded-Host', ''] | |
| 57 | - ]); | |
| 58 | - $this->request->expects($this->any()) | |
| 59 | -			->method('getRemoteAddress') | |
| 60 | - ->willReturn($remoteAddr); | |
| 46 | +    #[\PHPUnit\Framework\Attributes\DataProvider('dataForwardedForHeadersWorking')] | |
| 47 | +    public function testForwardedForHeadersWorking(array $trustedProxies, string $remoteAddrNotForwarded, string $remoteAddr, string $result): void { | |
| 48 | + $this->config->expects($this->once()) | |
| 49 | +            ->method('getSystemValue') | |
| 50 | +            ->with('trusted_proxies', []) | |
| 51 | + ->willReturn($trustedProxies); | |
| 52 | + $this->request->expects($this->atLeastOnce()) | |
| 53 | +            ->method('getHeader') | |
| 54 | + ->willReturnMap([ | |
| 55 | + ['REMOTE_ADDR', $remoteAddrNotForwarded], | |
| 56 | + ['X-Forwarded-Host', ''] | |
| 57 | + ]); | |
| 58 | + $this->request->expects($this->any()) | |
| 59 | +            ->method('getRemoteAddress') | |
| 60 | + ->willReturn($remoteAddr); | |
| 61 | 61 | |
| 62 | - $this->assertEquals( | |
| 63 | - $result, | |
| 64 | - $this->check->run()->getSeverity() | |
| 65 | - ); | |
| 66 | - } | |
| 62 | + $this->assertEquals( | |
| 63 | + $result, | |
| 64 | + $this->check->run()->getSeverity() | |
| 65 | + ); | |
| 66 | + } | |
| 67 | 67 | |
| 68 | -	public static function dataForwardedForHeadersWorking(): array { | |
| 69 | - return [ | |
| 70 | -			// description => trusted proxies, getHeader('REMOTE_ADDR'), getRemoteAddr, expected result | |
| 71 | - 'no trusted proxies' => [[], '2.2.2.2', '2.2.2.2', SetupResult::SUCCESS], | |
| 72 | - 'trusted proxy, remote addr not trusted proxy' => [['1.1.1.1'], '2.2.2.2', '2.2.2.2', SetupResult::SUCCESS], | |
| 73 | - 'trusted proxy, remote addr is trusted proxy, x-forwarded-for working' => [['1.1.1.1'], '1.1.1.1', '2.2.2.2', SetupResult::SUCCESS], | |
| 74 | - 'trusted proxy, remote addr is trusted proxy, x-forwarded-for not set' => [['1.1.1.1'], '1.1.1.1', '1.1.1.1', SetupResult::WARNING], | |
| 75 | - ]; | |
| 76 | - } | |
| 68 | +    public static function dataForwardedForHeadersWorking(): array { | |
| 69 | + return [ | |
| 70 | +            // description => trusted proxies, getHeader('REMOTE_ADDR'), getRemoteAddr, expected result | |
| 71 | + 'no trusted proxies' => [[], '2.2.2.2', '2.2.2.2', SetupResult::SUCCESS], | |
| 72 | + 'trusted proxy, remote addr not trusted proxy' => [['1.1.1.1'], '2.2.2.2', '2.2.2.2', SetupResult::SUCCESS], | |
| 73 | + 'trusted proxy, remote addr is trusted proxy, x-forwarded-for working' => [['1.1.1.1'], '1.1.1.1', '2.2.2.2', SetupResult::SUCCESS], | |
| 74 | + 'trusted proxy, remote addr is trusted proxy, x-forwarded-for not set' => [['1.1.1.1'], '1.1.1.1', '1.1.1.1', SetupResult::WARNING], | |
| 75 | + ]; | |
| 76 | + } | |
| 77 | 77 | |
| 78 | -	public function testForwardedHostPresentButTrustedProxiesNotAnArray(): void { | |
| 79 | - $this->config->expects($this->once()) | |
| 80 | -			->method('getSystemValue') | |
| 81 | -			->with('trusted_proxies', []) | |
| 82 | -			->willReturn('1.1.1.1'); | |
| 83 | - $this->request->expects($this->atLeastOnce()) | |
| 84 | -			->method('getHeader') | |
| 85 | - ->willReturnMap([ | |
| 86 | - ['REMOTE_ADDR', '1.1.1.1'], | |
| 87 | - ['X-Forwarded-Host', 'nextcloud.test'] | |
| 88 | - ]); | |
| 89 | - $this->request->expects($this->any()) | |
| 90 | -			->method('getRemoteAddress') | |
| 91 | -			->willReturn('1.1.1.1'); | |
| 78 | +    public function testForwardedHostPresentButTrustedProxiesNotAnArray(): void { | |
| 79 | + $this->config->expects($this->once()) | |
| 80 | +            ->method('getSystemValue') | |
| 81 | +            ->with('trusted_proxies', []) | |
| 82 | +            ->willReturn('1.1.1.1'); | |
| 83 | + $this->request->expects($this->atLeastOnce()) | |
| 84 | +            ->method('getHeader') | |
| 85 | + ->willReturnMap([ | |
| 86 | + ['REMOTE_ADDR', '1.1.1.1'], | |
| 87 | + ['X-Forwarded-Host', 'nextcloud.test'] | |
| 88 | + ]); | |
| 89 | + $this->request->expects($this->any()) | |
| 90 | +            ->method('getRemoteAddress') | |
| 91 | +            ->willReturn('1.1.1.1'); | |
| 92 | 92 | |
| 93 | - $this->assertEquals( | |
| 94 | - SetupResult::ERROR, | |
| 95 | - $this->check->run()->getSeverity() | |
| 96 | - ); | |
| 97 | - } | |
| 93 | + $this->assertEquals( | |
| 94 | + SetupResult::ERROR, | |
| 95 | + $this->check->run()->getSeverity() | |
| 96 | + ); | |
| 97 | + } | |
| 98 | 98 | |
| 99 | -	public function testForwardedHostPresentButTrustedProxiesEmpty(): void { | |
| 100 | - $this->config->expects($this->once()) | |
| 101 | -			->method('getSystemValue') | |
| 102 | -			->with('trusted_proxies', []) | |
| 103 | - ->willReturn([]); | |
| 104 | - $this->request->expects($this->atLeastOnce()) | |
| 105 | -			->method('getHeader') | |
| 106 | - ->willReturnMap([ | |
| 107 | - ['REMOTE_ADDR', '1.1.1.1'], | |
| 108 | - ['X-Forwarded-Host', 'nextcloud.test'] | |
| 109 | - ]); | |
| 110 | - $this->request->expects($this->any()) | |
| 111 | -			->method('getRemoteAddress') | |
| 112 | -			->willReturn('1.1.1.1'); | |
| 99 | +    public function testForwardedHostPresentButTrustedProxiesEmpty(): void { | |
| 100 | + $this->config->expects($this->once()) | |
| 101 | +            ->method('getSystemValue') | |
| 102 | +            ->with('trusted_proxies', []) | |
| 103 | + ->willReturn([]); | |
| 104 | + $this->request->expects($this->atLeastOnce()) | |
| 105 | +            ->method('getHeader') | |
| 106 | + ->willReturnMap([ | |
| 107 | + ['REMOTE_ADDR', '1.1.1.1'], | |
| 108 | + ['X-Forwarded-Host', 'nextcloud.test'] | |
| 109 | + ]); | |
| 110 | + $this->request->expects($this->any()) | |
| 111 | +            ->method('getRemoteAddress') | |
| 112 | +            ->willReturn('1.1.1.1'); | |
| 113 | 113 | |
| 114 | - $this->assertEquals( | |
| 115 | - SetupResult::ERROR, | |
| 116 | - $this->check->run()->getSeverity() | |
| 117 | - ); | |
| 118 | - } | |
| 114 | + $this->assertEquals( | |
| 115 | + SetupResult::ERROR, | |
| 116 | + $this->check->run()->getSeverity() | |
| 117 | + ); | |
| 118 | + } | |
| 119 | 119 | } | 
| @@ -19,58 +19,58 @@ | ||
| 19 | 19 | use Test\TestCase; | 
| 20 | 20 | |
| 21 | 21 |  class LoggingLevelTest extends TestCase { | 
| 22 | - private IL10N&MockObject $l10n; | |
| 23 | - private IConfig&MockObject $config; | |
| 24 | - private IURLGenerator&MockObject $urlGenerator; | |
| 22 | + private IL10N&MockObject $l10n; | |
| 23 | + private IConfig&MockObject $config; | |
| 24 | + private IURLGenerator&MockObject $urlGenerator; | |
| 25 | 25 | |
| 26 | -	protected function setUp(): void { | |
| 27 | - parent::setUp(); | |
| 26 | +    protected function setUp(): void { | |
| 27 | + parent::setUp(); | |
| 28 | 28 | |
| 29 | - $this->l10n = $this->createMock(IL10N::class); | |
| 30 | - $this->l10n->expects($this->any()) | |
| 31 | -			->method('t') | |
| 32 | -			->willReturnCallback(function ($message, array $replace) { | |
| 33 | - return vsprintf($message, $replace); | |
| 34 | - }); | |
| 35 | - $this->config = $this->createMock(IConfig::class); | |
| 36 | - $this->urlGenerator = $this->createMock(IURLGenerator::class); | |
| 37 | - } | |
| 29 | + $this->l10n = $this->createMock(IL10N::class); | |
| 30 | + $this->l10n->expects($this->any()) | |
| 31 | +            ->method('t') | |
| 32 | +            ->willReturnCallback(function ($message, array $replace) { | |
| 33 | + return vsprintf($message, $replace); | |
| 34 | + }); | |
| 35 | + $this->config = $this->createMock(IConfig::class); | |
| 36 | + $this->urlGenerator = $this->createMock(IURLGenerator::class); | |
| 37 | + } | |
| 38 | 38 | |
| 39 | -	public static function dataRun(): array { | |
| 40 | - return [ | |
| 41 | - [ILogger::INFO, SetupResult::SUCCESS], | |
| 42 | - [ILogger::WARN, SetupResult::SUCCESS], | |
| 43 | - [ILogger::ERROR, SetupResult::SUCCESS], | |
| 44 | - [ILogger::FATAL, SetupResult::SUCCESS], | |
| 39 | +    public static function dataRun(): array { | |
| 40 | + return [ | |
| 41 | + [ILogger::INFO, SetupResult::SUCCESS], | |
| 42 | + [ILogger::WARN, SetupResult::SUCCESS], | |
| 43 | + [ILogger::ERROR, SetupResult::SUCCESS], | |
| 44 | + [ILogger::FATAL, SetupResult::SUCCESS], | |
| 45 | 45 | |
| 46 | - // Debug is valid but will result in an warning | |
| 47 | - [ILogger::DEBUG, SetupResult::WARNING], | |
| 46 | + // Debug is valid but will result in an warning | |
| 47 | + [ILogger::DEBUG, SetupResult::WARNING], | |
| 48 | 48 | |
| 49 | - // negative - invalid range | |
| 50 | - [-1, SetupResult::ERROR], | |
| 51 | - // string value instead of number | |
| 52 | - ['1', SetupResult::ERROR], | |
| 53 | - // random string value | |
| 54 | - ['error', SetupResult::ERROR], | |
| 55 | - // PSR logger value | |
| 56 | - [LogLevel::ALERT, SetupResult::ERROR], | |
| 57 | - // out of range | |
| 58 | - [ILogger::FATAL + 1, SetupResult::ERROR], | |
| 59 | - ]; | |
| 60 | - } | |
| 49 | + // negative - invalid range | |
| 50 | + [-1, SetupResult::ERROR], | |
| 51 | + // string value instead of number | |
| 52 | + ['1', SetupResult::ERROR], | |
| 53 | + // random string value | |
| 54 | + ['error', SetupResult::ERROR], | |
| 55 | + // PSR logger value | |
| 56 | + [LogLevel::ALERT, SetupResult::ERROR], | |
| 57 | + // out of range | |
| 58 | + [ILogger::FATAL + 1, SetupResult::ERROR], | |
| 59 | + ]; | |
| 60 | + } | |
| 61 | 61 | |
| 62 | -	#[\PHPUnit\Framework\Attributes\DataProvider('dataRun')] | |
| 63 | -	public function testRun(string|int $value, string $expected): void { | |
| 64 | -		$this->urlGenerator->method('linkToDocs')->willReturn('admin-logging'); | |
| 62 | +    #[\PHPUnit\Framework\Attributes\DataProvider('dataRun')] | |
| 63 | +    public function testRun(string|int $value, string $expected): void { | |
| 64 | +        $this->urlGenerator->method('linkToDocs')->willReturn('admin-logging'); | |
| 65 | 65 | |
| 66 | - $this->config->expects(self::once()) | |
| 67 | -			->method('getSystemValue') | |
| 68 | -			->with('loglevel', ILogger::WARN) | |
| 69 | - ->willReturn($value); | |
| 66 | + $this->config->expects(self::once()) | |
| 67 | +            ->method('getSystemValue') | |
| 68 | +            ->with('loglevel', ILogger::WARN) | |
| 69 | + ->willReturn($value); | |
| 70 | 70 | |
| 71 | - $check = new LoggingLevel($this->l10n, $this->config, $this->urlGenerator); | |
| 71 | + $check = new LoggingLevel($this->l10n, $this->config, $this->urlGenerator); | |
| 72 | 72 | |
| 73 | - $result = $check->run(); | |
| 74 | - $this->assertEquals($expected, $result->getSeverity()); | |
| 75 | - } | |
| 73 | + $result = $check->run(); | |
| 74 | + $this->assertEquals($expected, $result->getSeverity()); | |
| 75 | + } | |
| 76 | 76 | } | 
| @@ -29,7 +29,7 @@ discard block | ||
| 29 | 29 | $this->l10n = $this->createMock(IL10N::class); | 
| 30 | 30 | $this->l10n->expects($this->any()) | 
| 31 | 31 |  			->method('t') | 
| 32 | -			->willReturnCallback(function ($message, array $replace) { | |
| 32 | +			->willReturnCallback(function($message, array $replace) { | |
| 33 | 33 | return vsprintf($message, $replace); | 
| 34 | 34 | }); | 
| 35 | 35 | $this->config = $this->createMock(IConfig::class); | 
| @@ -60,7 +60,7 @@ discard block | ||
| 60 | 60 | } | 
| 61 | 61 | |
| 62 | 62 |  	#[\PHPUnit\Framework\Attributes\DataProvider('dataRun')] | 
| 63 | -	public function testRun(string|int $value, string $expected): void { | |
| 63 | +	public function testRun(string | int $value, string $expected): void { | |
| 64 | 64 |  		$this->urlGenerator->method('linkToDocs')->willReturn('admin-logging'); | 
| 65 | 65 | |
| 66 | 66 | $this->config->expects(self::once()) | 
| @@ -20,98 +20,98 @@ | ||
| 20 | 20 | use Test\TestCase; | 
| 21 | 21 | |
| 22 | 22 |  class DataDirectoryProtectedTest extends TestCase { | 
| 23 | - private IL10N&MockObject $l10n; | |
| 24 | - private IConfig&MockObject $config; | |
| 25 | - private IURLGenerator&MockObject $urlGenerator; | |
| 26 | - private IClientService&MockObject $clientService; | |
| 27 | - private LoggerInterface&MockObject $logger; | |
| 28 | - private DataDirectoryProtected&MockObject $setupcheck; | |
| 29 | - | |
| 30 | -	protected function setUp(): void { | |
| 31 | - parent::setUp(); | |
| 32 | - | |
| 33 | - $this->l10n = $this->createMock(IL10N::class); | |
| 34 | - $this->l10n->expects($this->any()) | |
| 35 | -			->method('t') | |
| 36 | -			->willReturnCallback(function ($message, array $replace) { | |
| 37 | - return vsprintf($message, $replace); | |
| 38 | - }); | |
| 39 | - | |
| 40 | - $this->config = $this->createMock(IConfig::class); | |
| 41 | - $this->urlGenerator = $this->createMock(IURLGenerator::class); | |
| 42 | - $this->clientService = $this->createMock(IClientService::class); | |
| 43 | - $this->logger = $this->createMock(LoggerInterface::class); | |
| 44 | - | |
| 45 | - $this->setupcheck = $this->getMockBuilder(DataDirectoryProtected::class) | |
| 46 | - ->onlyMethods(['runRequest']) | |
| 47 | - ->setConstructorArgs([ | |
| 48 | - $this->l10n, | |
| 49 | - $this->config, | |
| 50 | - $this->urlGenerator, | |
| 51 | - $this->clientService, | |
| 52 | - $this->logger, | |
| 53 | - ]) | |
| 54 | - ->getMock(); | |
| 55 | - } | |
| 56 | - | |
| 57 | -	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestStatusCode')] | |
| 58 | -	public function testStatusCode(array $status, string $expected, bool $hasBody): void { | |
| 59 | -		$responses = array_map(function ($state) use ($hasBody) { | |
| 60 | - $response = $this->createMock(IResponse::class); | |
| 61 | -			$response->expects($this->any())->method('getStatusCode')->willReturn($state); | |
| 62 | -			$response->expects(($this->atMost(1)))->method('getBody')->willReturn($hasBody ? '# Nextcloud data directory' : 'something else'); | |
| 63 | - return $response; | |
| 64 | - }, $status); | |
| 65 | - | |
| 66 | - $this->setupcheck | |
| 67 | - ->expects($this->once()) | |
| 68 | -			->method('runRequest') | |
| 69 | - ->will($this->generate($responses)); | |
| 70 | - | |
| 71 | - $this->config | |
| 72 | - ->expects($this->once()) | |
| 73 | -			->method('getSystemValueString') | |
| 74 | -			->willReturn(''); | |
| 75 | - | |
| 76 | - $result = $this->setupcheck->run(); | |
| 77 | - $this->assertEquals($expected, $result->getSeverity()); | |
| 78 | - } | |
| 79 | - | |
| 80 | -	public static function dataTestStatusCode(): array { | |
| 81 | - return [ | |
| 82 | - 'success: forbidden access' => [[403], SetupResult::SUCCESS, true], | |
| 83 | - 'success: forbidden access with redirect' => [[200], SetupResult::SUCCESS, false], | |
| 84 | - 'error: can access' => [[200], SetupResult::ERROR, true], | |
| 85 | - 'error: one forbidden one can access' => [[403, 200], SetupResult::ERROR, true], | |
| 86 | - 'warning: connection issue' => [[], SetupResult::WARNING, true], | |
| 87 | - ]; | |
| 88 | - } | |
| 89 | - | |
| 90 | -	public function testNoResponse(): void { | |
| 91 | - $response = $this->createMock(IResponse::class); | |
| 92 | -		$response->expects($this->any())->method('getStatusCode')->willReturn(200); | |
| 93 | - | |
| 94 | - $this->setupcheck | |
| 95 | - ->expects($this->once()) | |
| 96 | -			->method('runRequest') | |
| 97 | - ->will($this->generate([])); | |
| 98 | - | |
| 99 | - $this->config | |
| 100 | - ->expects($this->once()) | |
| 101 | -			->method('getSystemValueString') | |
| 102 | -			->willReturn(''); | |
| 103 | - | |
| 104 | - $result = $this->setupcheck->run(); | |
| 105 | - $this->assertEquals(SetupResult::WARNING, $result->getSeverity()); | |
| 106 | -		$this->assertMatchesRegularExpression('/^Could not check/', $result->getDescription()); | |
| 107 | - } | |
| 108 | - | |
| 109 | - /** | |
| 110 | - * Helper function creates a nicer interface for mocking Generator behavior | |
| 111 | - */ | |
| 112 | -	protected function generate(array $yield_values) { | |
| 113 | -		return $this->returnCallback(function () use ($yield_values) { | |
| 114 | - yield from $yield_values; | |
| 115 | - }); | |
| 116 | - } | |
| 23 | + private IL10N&MockObject $l10n; | |
| 24 | + private IConfig&MockObject $config; | |
| 25 | + private IURLGenerator&MockObject $urlGenerator; | |
| 26 | + private IClientService&MockObject $clientService; | |
| 27 | + private LoggerInterface&MockObject $logger; | |
| 28 | + private DataDirectoryProtected&MockObject $setupcheck; | |
| 29 | + | |
| 30 | +    protected function setUp(): void { | |
| 31 | + parent::setUp(); | |
| 32 | + | |
| 33 | + $this->l10n = $this->createMock(IL10N::class); | |
| 34 | + $this->l10n->expects($this->any()) | |
| 35 | +            ->method('t') | |
| 36 | +            ->willReturnCallback(function ($message, array $replace) { | |
| 37 | + return vsprintf($message, $replace); | |
| 38 | + }); | |
| 39 | + | |
| 40 | + $this->config = $this->createMock(IConfig::class); | |
| 41 | + $this->urlGenerator = $this->createMock(IURLGenerator::class); | |
| 42 | + $this->clientService = $this->createMock(IClientService::class); | |
| 43 | + $this->logger = $this->createMock(LoggerInterface::class); | |
| 44 | + | |
| 45 | + $this->setupcheck = $this->getMockBuilder(DataDirectoryProtected::class) | |
| 46 | + ->onlyMethods(['runRequest']) | |
| 47 | + ->setConstructorArgs([ | |
| 48 | + $this->l10n, | |
| 49 | + $this->config, | |
| 50 | + $this->urlGenerator, | |
| 51 | + $this->clientService, | |
| 52 | + $this->logger, | |
| 53 | + ]) | |
| 54 | + ->getMock(); | |
| 55 | + } | |
| 56 | + | |
| 57 | +    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestStatusCode')] | |
| 58 | +    public function testStatusCode(array $status, string $expected, bool $hasBody): void { | |
| 59 | +        $responses = array_map(function ($state) use ($hasBody) { | |
| 60 | + $response = $this->createMock(IResponse::class); | |
| 61 | +            $response->expects($this->any())->method('getStatusCode')->willReturn($state); | |
| 62 | +            $response->expects(($this->atMost(1)))->method('getBody')->willReturn($hasBody ? '# Nextcloud data directory' : 'something else'); | |
| 63 | + return $response; | |
| 64 | + }, $status); | |
| 65 | + | |
| 66 | + $this->setupcheck | |
| 67 | + ->expects($this->once()) | |
| 68 | +            ->method('runRequest') | |
| 69 | + ->will($this->generate($responses)); | |
| 70 | + | |
| 71 | + $this->config | |
| 72 | + ->expects($this->once()) | |
| 73 | +            ->method('getSystemValueString') | |
| 74 | +            ->willReturn(''); | |
| 75 | + | |
| 76 | + $result = $this->setupcheck->run(); | |
| 77 | + $this->assertEquals($expected, $result->getSeverity()); | |
| 78 | + } | |
| 79 | + | |
| 80 | +    public static function dataTestStatusCode(): array { | |
| 81 | + return [ | |
| 82 | + 'success: forbidden access' => [[403], SetupResult::SUCCESS, true], | |
| 83 | + 'success: forbidden access with redirect' => [[200], SetupResult::SUCCESS, false], | |
| 84 | + 'error: can access' => [[200], SetupResult::ERROR, true], | |
| 85 | + 'error: one forbidden one can access' => [[403, 200], SetupResult::ERROR, true], | |
| 86 | + 'warning: connection issue' => [[], SetupResult::WARNING, true], | |
| 87 | + ]; | |
| 88 | + } | |
| 89 | + | |
| 90 | +    public function testNoResponse(): void { | |
| 91 | + $response = $this->createMock(IResponse::class); | |
| 92 | +        $response->expects($this->any())->method('getStatusCode')->willReturn(200); | |
| 93 | + | |
| 94 | + $this->setupcheck | |
| 95 | + ->expects($this->once()) | |
| 96 | +            ->method('runRequest') | |
| 97 | + ->will($this->generate([])); | |
| 98 | + | |
| 99 | + $this->config | |
| 100 | + ->expects($this->once()) | |
| 101 | +            ->method('getSystemValueString') | |
| 102 | +            ->willReturn(''); | |
| 103 | + | |
| 104 | + $result = $this->setupcheck->run(); | |
| 105 | + $this->assertEquals(SetupResult::WARNING, $result->getSeverity()); | |
| 106 | +        $this->assertMatchesRegularExpression('/^Could not check/', $result->getDescription()); | |
| 107 | + } | |
| 108 | + | |
| 109 | + /** | |
| 110 | + * Helper function creates a nicer interface for mocking Generator behavior | |
| 111 | + */ | |
| 112 | +    protected function generate(array $yield_values) { | |
| 113 | +        return $this->returnCallback(function () use ($yield_values) { | |
| 114 | + yield from $yield_values; | |
| 115 | + }); | |
| 116 | + } | |
| 117 | 117 | } | 
| @@ -33,7 +33,7 @@ discard block | ||
| 33 | 33 | $this->l10n = $this->createMock(IL10N::class); | 
| 34 | 34 | $this->l10n->expects($this->any()) | 
| 35 | 35 |  			->method('t') | 
| 36 | -			->willReturnCallback(function ($message, array $replace) { | |
| 36 | +			->willReturnCallback(function($message, array $replace) { | |
| 37 | 37 | return vsprintf($message, $replace); | 
| 38 | 38 | }); | 
| 39 | 39 | |
| @@ -56,7 +56,7 @@ discard block | ||
| 56 | 56 | |
| 57 | 57 |  	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestStatusCode')] | 
| 58 | 58 |  	public function testStatusCode(array $status, string $expected, bool $hasBody): void { | 
| 59 | -		$responses = array_map(function ($state) use ($hasBody) { | |
| 59 | +		$responses = array_map(function($state) use ($hasBody) { | |
| 60 | 60 | $response = $this->createMock(IResponse::class); | 
| 61 | 61 |  			$response->expects($this->any())->method('getStatusCode')->willReturn($state); | 
| 62 | 62 |  			$response->expects(($this->atMost(1)))->method('getBody')->willReturn($hasBody ? '# Nextcloud data directory' : 'something else'); | 
| @@ -110,7 +110,7 @@ discard block | ||
| 110 | 110 | * Helper function creates a nicer interface for mocking Generator behavior | 
| 111 | 111 | */ | 
| 112 | 112 |  	protected function generate(array $yield_values) { | 
| 113 | -		return $this->returnCallback(function () use ($yield_values) { | |
| 113 | +		return $this->returnCallback(function() use ($yield_values) { | |
| 114 | 114 | yield from $yield_values; | 
| 115 | 115 | }); | 
| 116 | 116 | } | 
| @@ -20,177 +20,177 @@ | ||
| 20 | 20 | use Test\TestCase; | 
| 21 | 21 | |
| 22 | 22 |  class SecurityHeadersTest extends TestCase { | 
| 23 | - private IL10N&MockObject $l10n; | |
| 24 | - private IConfig&MockObject $config; | |
| 25 | - private IURLGenerator&MockObject $urlGenerator; | |
| 26 | - private IClientService&MockObject $clientService; | |
| 27 | - private LoggerInterface&MockObject $logger; | |
| 28 | - private SecurityHeaders&MockObject $setupcheck; | |
| 29 | - | |
| 30 | -	protected function setUp(): void { | |
| 31 | - parent::setUp(); | |
| 32 | - | |
| 33 | - $this->l10n = $this->createMock(IL10N::class); | |
| 34 | - $this->l10n->expects($this->any()) | |
| 35 | -			->method('t') | |
| 36 | -			->willReturnCallback(function ($message, array $replace) { | |
| 37 | - return vsprintf($message, $replace); | |
| 38 | - }); | |
| 39 | - | |
| 40 | - $this->config = $this->createMock(IConfig::class); | |
| 41 | - $this->urlGenerator = $this->createMock(IURLGenerator::class); | |
| 42 | - $this->clientService = $this->createMock(IClientService::class); | |
| 43 | - $this->logger = $this->createMock(LoggerInterface::class); | |
| 44 | - | |
| 45 | - $this->setupcheck = $this->getMockBuilder(SecurityHeaders::class) | |
| 46 | - ->onlyMethods(['runRequest']) | |
| 47 | - ->setConstructorArgs([ | |
| 48 | - $this->l10n, | |
| 49 | - $this->config, | |
| 50 | - $this->urlGenerator, | |
| 51 | - $this->clientService, | |
| 52 | - $this->logger, | |
| 53 | - ]) | |
| 54 | - ->getMock(); | |
| 55 | - } | |
| 56 | - | |
| 57 | -	public function testInvalidStatusCode(): void { | |
| 58 | - $this->setupResponse(500, []); | |
| 59 | - | |
| 60 | - $result = $this->setupcheck->run(); | |
| 61 | -		$this->assertMatchesRegularExpression('/^Could not check that your web server serves security headers correctly/', $result->getDescription()); | |
| 62 | - $this->assertEquals(SetupResult::WARNING, $result->getSeverity()); | |
| 63 | - } | |
| 64 | - | |
| 65 | -	public function testAllHeadersMissing(): void { | |
| 66 | - $this->setupResponse(200, []); | |
| 67 | - | |
| 68 | - $result = $this->setupcheck->run(); | |
| 69 | -		$this->assertMatchesRegularExpression('/^Some headers are not set correctly on your instance/', $result->getDescription()); | |
| 70 | - $this->assertEquals(SetupResult::WARNING, $result->getSeverity()); | |
| 71 | - } | |
| 72 | - | |
| 73 | -	public function testSomeHeadersMissing(): void { | |
| 74 | - $this->setupResponse( | |
| 75 | - 200, | |
| 76 | - [ | |
| 77 | - 'X-Robots-Tag' => 'noindex, nofollow', | |
| 78 | - 'X-Frame-Options' => 'SAMEORIGIN', | |
| 79 | - 'Strict-Transport-Security' => 'max-age=15768000;preload', | |
| 80 | - 'X-Permitted-Cross-Domain-Policies' => 'none', | |
| 81 | - 'Referrer-Policy' => 'no-referrer', | |
| 82 | - ] | |
| 83 | - ); | |
| 84 | - | |
| 85 | - $result = $this->setupcheck->run(); | |
| 86 | - $this->assertEquals( | |
| 87 | - "Some headers are not set correctly on your instance\n- The `X-Content-Type-Options` HTTP header is not set to `nosniff`. This is a potential security or privacy risk, as it is recommended to adjust this setting accordingly.\n", | |
| 88 | - $result->getDescription() | |
| 89 | - ); | |
| 90 | - $this->assertEquals(SetupResult::WARNING, $result->getSeverity()); | |
| 91 | - } | |
| 92 | - | |
| 93 | -	public static function dataSuccess(): array { | |
| 94 | - return [ | |
| 95 | - // description => modifiedHeaders | |
| 96 | - 'basic' => [[]], | |
| 97 | - 'no-space-in-x-robots' => [['X-Robots-Tag' => 'noindex,nofollow']], | |
| 98 | - 'strict-origin-when-cross-origin' => [['Referrer-Policy' => 'strict-origin-when-cross-origin']], | |
| 99 | - 'referrer-no-referrer-when-downgrade' => [['Referrer-Policy' => 'no-referrer-when-downgrade']], | |
| 100 | - 'referrer-strict-origin' => [['Referrer-Policy' => 'strict-origin']], | |
| 101 | - 'referrer-strict-origin-when-cross-origin' => [['Referrer-Policy' => 'strict-origin-when-cross-origin']], | |
| 102 | - 'referrer-same-origin' => [['Referrer-Policy' => 'same-origin']], | |
| 103 | - 'hsts-minimum' => [['Strict-Transport-Security' => 'max-age=15552000']], | |
| 104 | - 'hsts-include-subdomains' => [['Strict-Transport-Security' => 'max-age=99999999; includeSubDomains']], | |
| 105 | - 'hsts-include-subdomains-preload' => [['Strict-Transport-Security' => 'max-age=99999999; preload; includeSubDomains']], | |
| 106 | - ]; | |
| 107 | - } | |
| 108 | - | |
| 109 | -	#[\PHPUnit\Framework\Attributes\DataProvider('dataSuccess')] | |
| 110 | -	public function testSuccess(array $headers): void { | |
| 111 | - $headers = array_merge( | |
| 112 | - [ | |
| 113 | - 'X-Content-Type-Options' => 'nosniff', | |
| 114 | - 'X-Robots-Tag' => 'noindex, nofollow', | |
| 115 | - 'X-Frame-Options' => 'SAMEORIGIN', | |
| 116 | - 'Strict-Transport-Security' => 'max-age=15768000', | |
| 117 | - 'X-Permitted-Cross-Domain-Policies' => 'none', | |
| 118 | - 'Referrer-Policy' => 'no-referrer', | |
| 119 | - ], | |
| 120 | - $headers | |
| 121 | - ); | |
| 122 | - $this->setupResponse( | |
| 123 | - 200, | |
| 124 | - $headers | |
| 125 | - ); | |
| 126 | - | |
| 127 | - $result = $this->setupcheck->run(); | |
| 128 | - $this->assertEquals( | |
| 129 | - 'Your server is correctly configured to send security headers.', | |
| 130 | - $result->getDescription() | |
| 131 | - ); | |
| 132 | - $this->assertEquals(SetupResult::SUCCESS, $result->getSeverity()); | |
| 133 | - } | |
| 134 | - | |
| 135 | -	public static function dataFailure(): array { | |
| 136 | - return [ | |
| 137 | - // description => modifiedHeaders | |
| 138 | - 'x-robots-none' => [['X-Robots-Tag' => 'none'], "- The `X-Robots-Tag` HTTP header is not set to `noindex,nofollow`. This is a potential security or privacy risk, as it is recommended to adjust this setting accordingly.\n"], | |
| 139 | -			'referrer-origin' => [['Referrer-Policy' => 'origin'], "- The `Referrer-Policy` HTTP header is not set to `no-referrer`, `no-referrer-when-downgrade`, `strict-origin`, `strict-origin-when-cross-origin` or `same-origin`. This can leak referer information. See the {w3c-recommendation}.\n"], | |
| 140 | -			'referrer-origin-when-cross-origin' => [['Referrer-Policy' => 'origin-when-cross-origin'], "- The `Referrer-Policy` HTTP header is not set to `no-referrer`, `no-referrer-when-downgrade`, `strict-origin`, `strict-origin-when-cross-origin` or `same-origin`. This can leak referer information. See the {w3c-recommendation}.\n"], | |
| 141 | -			'referrer-unsafe-url' => [['Referrer-Policy' => 'unsafe-url'], "- The `Referrer-Policy` HTTP header is not set to `no-referrer`, `no-referrer-when-downgrade`, `strict-origin`, `strict-origin-when-cross-origin` or `same-origin`. This can leak referer information. See the {w3c-recommendation}.\n"], | |
| 142 | - 'hsts-missing' => [['Strict-Transport-Security' => ''], "- The `Strict-Transport-Security` HTTP header is not set (should be at least `15552000` seconds). For enhanced security, it is recommended to enable HSTS.\n"], | |
| 143 | - 'hsts-too-low' => [['Strict-Transport-Security' => 'max-age=15551999'], "- The `Strict-Transport-Security` HTTP header is not set to at least `15552000` seconds (current value: `15551999`). For enhanced security, it is recommended to use a long HSTS policy.\n"], | |
| 144 | - 'hsts-malformed' => [['Strict-Transport-Security' => 'iAmABogusHeader342'], "- The `Strict-Transport-Security` HTTP header is malformed: `iAmABogusHeader342`. For enhanced security, it is recommended to enable HSTS.\n"], | |
| 145 | - ]; | |
| 146 | - } | |
| 147 | - | |
| 148 | -	#[\PHPUnit\Framework\Attributes\DataProvider('dataFailure')] | |
| 149 | -	public function testFailure(array $headers, string $msg): void { | |
| 150 | - $headers = array_merge( | |
| 151 | - [ | |
| 152 | - 'X-Content-Type-Options' => 'nosniff', | |
| 153 | - 'X-Robots-Tag' => 'noindex, nofollow', | |
| 154 | - 'X-Frame-Options' => 'SAMEORIGIN', | |
| 155 | - 'Strict-Transport-Security' => 'max-age=15768000', | |
| 156 | - 'X-Permitted-Cross-Domain-Policies' => 'none', | |
| 157 | - 'Referrer-Policy' => 'no-referrer', | |
| 158 | - ], | |
| 159 | - $headers | |
| 160 | - ); | |
| 161 | - $this->setupResponse( | |
| 162 | - 200, | |
| 163 | - $headers | |
| 164 | - ); | |
| 165 | - | |
| 166 | - $result = $this->setupcheck->run(); | |
| 167 | - $this->assertEquals( | |
| 168 | - 'Some headers are not set correctly on your instance' . "\n$msg", | |
| 169 | - $result->getDescription() | |
| 170 | - ); | |
| 171 | - $this->assertEquals(SetupResult::WARNING, $result->getSeverity()); | |
| 172 | - } | |
| 173 | - | |
| 174 | -	protected function setupResponse(int $statuscode, array $headers): void { | |
| 175 | - $response = $this->createMock(IResponse::class); | |
| 176 | -		$response->expects($this->atLeastOnce())->method('getStatusCode')->willReturn($statuscode); | |
| 177 | -		$response->expects($this->any())->method('getHeader') | |
| 178 | - ->willReturnCallback( | |
| 179 | - fn (string $header): string => $headers[$header] ?? '' | |
| 180 | - ); | |
| 181 | - | |
| 182 | - $this->setupcheck | |
| 183 | - ->expects($this->atLeastOnce()) | |
| 184 | -			->method('runRequest') | |
| 185 | - ->willReturnOnConsecutiveCalls($this->generate([$response])); | |
| 186 | - } | |
| 187 | - | |
| 188 | - /** | |
| 189 | - * Helper function creates a nicer interface for mocking Generator behavior | |
| 190 | - */ | |
| 191 | -	protected function generate(array $yield_values) { | |
| 192 | -		return $this->returnCallback(function () use ($yield_values) { | |
| 193 | - yield from $yield_values; | |
| 194 | - }); | |
| 195 | - } | |
| 23 | + private IL10N&MockObject $l10n; | |
| 24 | + private IConfig&MockObject $config; | |
| 25 | + private IURLGenerator&MockObject $urlGenerator; | |
| 26 | + private IClientService&MockObject $clientService; | |
| 27 | + private LoggerInterface&MockObject $logger; | |
| 28 | + private SecurityHeaders&MockObject $setupcheck; | |
| 29 | + | |
| 30 | +    protected function setUp(): void { | |
| 31 | + parent::setUp(); | |
| 32 | + | |
| 33 | + $this->l10n = $this->createMock(IL10N::class); | |
| 34 | + $this->l10n->expects($this->any()) | |
| 35 | +            ->method('t') | |
| 36 | +            ->willReturnCallback(function ($message, array $replace) { | |
| 37 | + return vsprintf($message, $replace); | |
| 38 | + }); | |
| 39 | + | |
| 40 | + $this->config = $this->createMock(IConfig::class); | |
| 41 | + $this->urlGenerator = $this->createMock(IURLGenerator::class); | |
| 42 | + $this->clientService = $this->createMock(IClientService::class); | |
| 43 | + $this->logger = $this->createMock(LoggerInterface::class); | |
| 44 | + | |
| 45 | + $this->setupcheck = $this->getMockBuilder(SecurityHeaders::class) | |
| 46 | + ->onlyMethods(['runRequest']) | |
| 47 | + ->setConstructorArgs([ | |
| 48 | + $this->l10n, | |
| 49 | + $this->config, | |
| 50 | + $this->urlGenerator, | |
| 51 | + $this->clientService, | |
| 52 | + $this->logger, | |
| 53 | + ]) | |
| 54 | + ->getMock(); | |
| 55 | + } | |
| 56 | + | |
| 57 | +    public function testInvalidStatusCode(): void { | |
| 58 | + $this->setupResponse(500, []); | |
| 59 | + | |
| 60 | + $result = $this->setupcheck->run(); | |
| 61 | +        $this->assertMatchesRegularExpression('/^Could not check that your web server serves security headers correctly/', $result->getDescription()); | |
| 62 | + $this->assertEquals(SetupResult::WARNING, $result->getSeverity()); | |
| 63 | + } | |
| 64 | + | |
| 65 | +    public function testAllHeadersMissing(): void { | |
| 66 | + $this->setupResponse(200, []); | |
| 67 | + | |
| 68 | + $result = $this->setupcheck->run(); | |
| 69 | +        $this->assertMatchesRegularExpression('/^Some headers are not set correctly on your instance/', $result->getDescription()); | |
| 70 | + $this->assertEquals(SetupResult::WARNING, $result->getSeverity()); | |
| 71 | + } | |
| 72 | + | |
| 73 | +    public function testSomeHeadersMissing(): void { | |
| 74 | + $this->setupResponse( | |
| 75 | + 200, | |
| 76 | + [ | |
| 77 | + 'X-Robots-Tag' => 'noindex, nofollow', | |
| 78 | + 'X-Frame-Options' => 'SAMEORIGIN', | |
| 79 | + 'Strict-Transport-Security' => 'max-age=15768000;preload', | |
| 80 | + 'X-Permitted-Cross-Domain-Policies' => 'none', | |
| 81 | + 'Referrer-Policy' => 'no-referrer', | |
| 82 | + ] | |
| 83 | + ); | |
| 84 | + | |
| 85 | + $result = $this->setupcheck->run(); | |
| 86 | + $this->assertEquals( | |
| 87 | + "Some headers are not set correctly on your instance\n- The `X-Content-Type-Options` HTTP header is not set to `nosniff`. This is a potential security or privacy risk, as it is recommended to adjust this setting accordingly.\n", | |
| 88 | + $result->getDescription() | |
| 89 | + ); | |
| 90 | + $this->assertEquals(SetupResult::WARNING, $result->getSeverity()); | |
| 91 | + } | |
| 92 | + | |
| 93 | +    public static function dataSuccess(): array { | |
| 94 | + return [ | |
| 95 | + // description => modifiedHeaders | |
| 96 | + 'basic' => [[]], | |
| 97 | + 'no-space-in-x-robots' => [['X-Robots-Tag' => 'noindex,nofollow']], | |
| 98 | + 'strict-origin-when-cross-origin' => [['Referrer-Policy' => 'strict-origin-when-cross-origin']], | |
| 99 | + 'referrer-no-referrer-when-downgrade' => [['Referrer-Policy' => 'no-referrer-when-downgrade']], | |
| 100 | + 'referrer-strict-origin' => [['Referrer-Policy' => 'strict-origin']], | |
| 101 | + 'referrer-strict-origin-when-cross-origin' => [['Referrer-Policy' => 'strict-origin-when-cross-origin']], | |
| 102 | + 'referrer-same-origin' => [['Referrer-Policy' => 'same-origin']], | |
| 103 | + 'hsts-minimum' => [['Strict-Transport-Security' => 'max-age=15552000']], | |
| 104 | + 'hsts-include-subdomains' => [['Strict-Transport-Security' => 'max-age=99999999; includeSubDomains']], | |
| 105 | + 'hsts-include-subdomains-preload' => [['Strict-Transport-Security' => 'max-age=99999999; preload; includeSubDomains']], | |
| 106 | + ]; | |
| 107 | + } | |
| 108 | + | |
| 109 | +    #[\PHPUnit\Framework\Attributes\DataProvider('dataSuccess')] | |
| 110 | +    public function testSuccess(array $headers): void { | |
| 111 | + $headers = array_merge( | |
| 112 | + [ | |
| 113 | + 'X-Content-Type-Options' => 'nosniff', | |
| 114 | + 'X-Robots-Tag' => 'noindex, nofollow', | |
| 115 | + 'X-Frame-Options' => 'SAMEORIGIN', | |
| 116 | + 'Strict-Transport-Security' => 'max-age=15768000', | |
| 117 | + 'X-Permitted-Cross-Domain-Policies' => 'none', | |
| 118 | + 'Referrer-Policy' => 'no-referrer', | |
| 119 | + ], | |
| 120 | + $headers | |
| 121 | + ); | |
| 122 | + $this->setupResponse( | |
| 123 | + 200, | |
| 124 | + $headers | |
| 125 | + ); | |
| 126 | + | |
| 127 | + $result = $this->setupcheck->run(); | |
| 128 | + $this->assertEquals( | |
| 129 | + 'Your server is correctly configured to send security headers.', | |
| 130 | + $result->getDescription() | |
| 131 | + ); | |
| 132 | + $this->assertEquals(SetupResult::SUCCESS, $result->getSeverity()); | |
| 133 | + } | |
| 134 | + | |
| 135 | +    public static function dataFailure(): array { | |
| 136 | + return [ | |
| 137 | + // description => modifiedHeaders | |
| 138 | + 'x-robots-none' => [['X-Robots-Tag' => 'none'], "- The `X-Robots-Tag` HTTP header is not set to `noindex,nofollow`. This is a potential security or privacy risk, as it is recommended to adjust this setting accordingly.\n"], | |
| 139 | +            'referrer-origin' => [['Referrer-Policy' => 'origin'], "- The `Referrer-Policy` HTTP header is not set to `no-referrer`, `no-referrer-when-downgrade`, `strict-origin`, `strict-origin-when-cross-origin` or `same-origin`. This can leak referer information. See the {w3c-recommendation}.\n"], | |
| 140 | +            'referrer-origin-when-cross-origin' => [['Referrer-Policy' => 'origin-when-cross-origin'], "- The `Referrer-Policy` HTTP header is not set to `no-referrer`, `no-referrer-when-downgrade`, `strict-origin`, `strict-origin-when-cross-origin` or `same-origin`. This can leak referer information. See the {w3c-recommendation}.\n"], | |
| 141 | +            'referrer-unsafe-url' => [['Referrer-Policy' => 'unsafe-url'], "- The `Referrer-Policy` HTTP header is not set to `no-referrer`, `no-referrer-when-downgrade`, `strict-origin`, `strict-origin-when-cross-origin` or `same-origin`. This can leak referer information. See the {w3c-recommendation}.\n"], | |
| 142 | + 'hsts-missing' => [['Strict-Transport-Security' => ''], "- The `Strict-Transport-Security` HTTP header is not set (should be at least `15552000` seconds). For enhanced security, it is recommended to enable HSTS.\n"], | |
| 143 | + 'hsts-too-low' => [['Strict-Transport-Security' => 'max-age=15551999'], "- The `Strict-Transport-Security` HTTP header is not set to at least `15552000` seconds (current value: `15551999`). For enhanced security, it is recommended to use a long HSTS policy.\n"], | |
| 144 | + 'hsts-malformed' => [['Strict-Transport-Security' => 'iAmABogusHeader342'], "- The `Strict-Transport-Security` HTTP header is malformed: `iAmABogusHeader342`. For enhanced security, it is recommended to enable HSTS.\n"], | |
| 145 | + ]; | |
| 146 | + } | |
| 147 | + | |
| 148 | +    #[\PHPUnit\Framework\Attributes\DataProvider('dataFailure')] | |
| 149 | +    public function testFailure(array $headers, string $msg): void { | |
| 150 | + $headers = array_merge( | |
| 151 | + [ | |
| 152 | + 'X-Content-Type-Options' => 'nosniff', | |
| 153 | + 'X-Robots-Tag' => 'noindex, nofollow', | |
| 154 | + 'X-Frame-Options' => 'SAMEORIGIN', | |
| 155 | + 'Strict-Transport-Security' => 'max-age=15768000', | |
| 156 | + 'X-Permitted-Cross-Domain-Policies' => 'none', | |
| 157 | + 'Referrer-Policy' => 'no-referrer', | |
| 158 | + ], | |
| 159 | + $headers | |
| 160 | + ); | |
| 161 | + $this->setupResponse( | |
| 162 | + 200, | |
| 163 | + $headers | |
| 164 | + ); | |
| 165 | + | |
| 166 | + $result = $this->setupcheck->run(); | |
| 167 | + $this->assertEquals( | |
| 168 | + 'Some headers are not set correctly on your instance' . "\n$msg", | |
| 169 | + $result->getDescription() | |
| 170 | + ); | |
| 171 | + $this->assertEquals(SetupResult::WARNING, $result->getSeverity()); | |
| 172 | + } | |
| 173 | + | |
| 174 | +    protected function setupResponse(int $statuscode, array $headers): void { | |
| 175 | + $response = $this->createMock(IResponse::class); | |
| 176 | +        $response->expects($this->atLeastOnce())->method('getStatusCode')->willReturn($statuscode); | |
| 177 | +        $response->expects($this->any())->method('getHeader') | |
| 178 | + ->willReturnCallback( | |
| 179 | + fn (string $header): string => $headers[$header] ?? '' | |
| 180 | + ); | |
| 181 | + | |
| 182 | + $this->setupcheck | |
| 183 | + ->expects($this->atLeastOnce()) | |
| 184 | +            ->method('runRequest') | |
| 185 | + ->willReturnOnConsecutiveCalls($this->generate([$response])); | |
| 186 | + } | |
| 187 | + | |
| 188 | + /** | |
| 189 | + * Helper function creates a nicer interface for mocking Generator behavior | |
| 190 | + */ | |
| 191 | +    protected function generate(array $yield_values) { | |
| 192 | +        return $this->returnCallback(function () use ($yield_values) { | |
| 193 | + yield from $yield_values; | |
| 194 | + }); | |
| 195 | + } | |
| 196 | 196 | } | 
| @@ -20,196 +20,196 @@ | ||
| 20 | 20 | use Test\TestCase; | 
| 21 | 21 | |
| 22 | 22 |  class WellKnownUrlsTest extends TestCase { | 
| 23 | - private IL10N&MockObject $l10n; | |
| 24 | - private IConfig&MockObject $config; | |
| 25 | - private IURLGenerator&MockObject $urlGenerator; | |
| 26 | - private IClientService&MockObject $clientService; | |
| 27 | - private LoggerInterface&MockObject $logger; | |
| 28 | - private WellKnownUrls&MockObject $setupcheck; | |
| 29 | - | |
| 30 | -	protected function setUp(): void { | |
| 31 | - parent::setUp(); | |
| 32 | - | |
| 33 | - /** @var IL10N&MockObject */ | |
| 34 | - $this->l10n = $this->createMock(IL10N::class); | |
| 35 | - $this->l10n->expects($this->any()) | |
| 36 | -			->method('t') | |
| 37 | -			->willReturnCallback(function ($message, array $replace) { | |
| 38 | - return vsprintf($message, $replace); | |
| 39 | - }); | |
| 40 | - | |
| 41 | - $this->config = $this->createMock(IConfig::class); | |
| 42 | - $this->urlGenerator = $this->createMock(IURLGenerator::class); | |
| 43 | - $this->clientService = $this->createMock(IClientService::class); | |
| 44 | - $this->logger = $this->createMock(LoggerInterface::class); | |
| 45 | - | |
| 46 | - $this->setupcheck = $this->getMockBuilder(WellKnownUrls::class) | |
| 47 | - ->onlyMethods(['runRequest']) | |
| 48 | - ->setConstructorArgs([ | |
| 49 | - $this->l10n, | |
| 50 | - $this->config, | |
| 51 | - $this->urlGenerator, | |
| 52 | - $this->clientService, | |
| 53 | - $this->logger, | |
| 54 | - ]) | |
| 55 | - ->getMock(); | |
| 56 | - } | |
| 57 | - | |
| 58 | - /** | |
| 59 | - * Test that the SetupCheck is skipped if the system config is set | |
| 60 | - */ | |
| 61 | -	public function testDisabled(): void { | |
| 62 | - $this->config | |
| 63 | - ->expects($this->once()) | |
| 64 | -			->method('getSystemValueBool') | |
| 65 | -			->with('check_for_working_wellknown_setup') | |
| 66 | - ->willReturn(false); | |
| 67 | - | |
| 68 | - $this->setupcheck | |
| 69 | - ->expects($this->never()) | |
| 70 | -			->method('runRequest'); | |
| 71 | - | |
| 72 | - $result = $this->setupcheck->run(); | |
| 73 | - $this->assertEquals(SetupResult::INFO, $result->getSeverity()); | |
| 74 | -		$this->assertMatchesRegularExpression('/check was skipped/', $result->getDescription()); | |
| 75 | - } | |
| 76 | - | |
| 77 | - /** | |
| 78 | - * Test what happens if the local server could not be reached (no response from the requests) | |
| 79 | - */ | |
| 80 | -	public function testNoResponse(): void { | |
| 81 | - $this->config | |
| 82 | - ->expects($this->once()) | |
| 83 | -			->method('getSystemValueBool') | |
| 84 | -			->with('check_for_working_wellknown_setup') | |
| 85 | - ->willReturn(true); | |
| 86 | - | |
| 87 | - $this->setupcheck | |
| 88 | - ->expects($this->once()) | |
| 89 | -			->method('runRequest') | |
| 90 | - ->will($this->generate([])); | |
| 91 | - | |
| 92 | - $result = $this->setupcheck->run(); | |
| 93 | - $this->assertEquals(SetupResult::INFO, $result->getSeverity()); | |
| 94 | -		$this->assertMatchesRegularExpression('/^Could not check/', $result->getDescription()); | |
| 95 | - } | |
| 96 | - | |
| 97 | - /** | |
| 98 | - * Test responses | |
| 99 | - */ | |
| 100 | -	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestResponses')] | |
| 101 | -	public function testResponses($responses, string $expectedSeverity): void { | |
| 102 | - $this->config | |
| 103 | - ->expects($this->once()) | |
| 104 | -			->method('getSystemValueBool') | |
| 105 | -			->with('check_for_working_wellknown_setup') | |
| 106 | - ->willReturn(true); | |
| 107 | - | |
| 108 | - $this->setupcheck | |
| 109 | - ->expects($this->atLeastOnce()) | |
| 110 | -			->method('runRequest') | |
| 111 | - ->willReturnOnConsecutiveCalls(...$responses); | |
| 112 | - | |
| 113 | - $result = $this->setupcheck->run(); | |
| 114 | - $this->assertEquals($expectedSeverity, $result->getSeverity()); | |
| 115 | - } | |
| 116 | - | |
| 117 | -	public function dataTestResponses(): array { | |
| 118 | -		$createResponse = function (int $statuscode, array $header = []): IResponse&MockObject { | |
| 119 | - $response = $this->createMock(IResponse::class); | |
| 120 | - $response->expects($this->any()) | |
| 121 | -				->method('getStatusCode') | |
| 122 | - ->willReturn($statuscode); | |
| 123 | - $response->expects($this->any()) | |
| 124 | -				->method('getHeader') | |
| 125 | - ->willReturnCallback(fn ($name) => $header[$name] ?? ''); | |
| 126 | - return $response; | |
| 127 | - }; | |
| 128 | - | |
| 129 | - $wellKnownHeader = ['X-NEXTCLOUD-WELL-KNOWN' => 'yes']; | |
| 130 | - | |
| 131 | - return [ | |
| 132 | - 'expected codes' => [ | |
| 133 | - [ | |
| 134 | - $this->generate([$createResponse(200, $wellKnownHeader)]), | |
| 135 | - $this->generate([$createResponse(200, $wellKnownHeader)]), | |
| 136 | - $this->generate([$createResponse(207)]), | |
| 137 | - $this->generate([$createResponse(207)]), | |
| 138 | - ], | |
| 139 | - SetupResult::SUCCESS, | |
| 140 | - ], | |
| 141 | - 'late response with expected codes' => [ | |
| 142 | - [ | |
| 143 | - $this->generate([$createResponse(404), $createResponse(200, $wellKnownHeader)]), | |
| 144 | - $this->generate([$createResponse(404), $createResponse(200, $wellKnownHeader)]), | |
| 145 | - $this->generate([$createResponse(404), $createResponse(207)]), | |
| 146 | - $this->generate([$createResponse(404), $createResponse(207)]), | |
| 147 | - ], | |
| 148 | - SetupResult::SUCCESS, | |
| 149 | - ], | |
| 150 | - 'working but disabled webfinger' => [ | |
| 151 | - [ | |
| 152 | - $this->generate([$createResponse(404, $wellKnownHeader)]), | |
| 153 | - $this->generate([$createResponse(404, $wellKnownHeader)]), | |
| 154 | - $this->generate([$createResponse(207)]), | |
| 155 | - $this->generate([$createResponse(207)]), | |
| 156 | - ], | |
| 157 | - SetupResult::SUCCESS, | |
| 158 | - ], | |
| 159 | - 'unauthorized webdav but with correct configured redirect' => [ | |
| 160 | - [ | |
| 161 | - $this->generate([$createResponse(404, $wellKnownHeader)]), | |
| 162 | - $this->generate([$createResponse(404, $wellKnownHeader)]), | |
| 163 | - $this->generate([$createResponse(401, ['X-Guzzle-Redirect-History' => 'https://example.com,https://example.com/remote.php/dav/'])]), | |
| 164 | - $this->generate([$createResponse(401, ['X-Guzzle-Redirect-History' => 'https://example.com/remote.php/dav/'])]), | |
| 165 | - ], | |
| 166 | - SetupResult::SUCCESS, | |
| 167 | - ], | |
| 168 | - 'not configured path' => [ | |
| 169 | - [ | |
| 170 | - $this->generate([$createResponse(404)]), | |
| 171 | - $this->generate([$createResponse(404)]), | |
| 172 | - $this->generate([$createResponse(404)]), | |
| 173 | - $this->generate([$createResponse(404)]), | |
| 174 | - ], | |
| 175 | - SetupResult::WARNING, | |
| 176 | - ], | |
| 177 | - 'Invalid webfinger' => [ | |
| 178 | - [ | |
| 179 | - $this->generate([$createResponse(404)]), | |
| 180 | - $this->generate([$createResponse(404, $wellKnownHeader)]), | |
| 181 | - $this->generate([$createResponse(207)]), | |
| 182 | - $this->generate([$createResponse(207)]), | |
| 183 | - ], | |
| 184 | - SetupResult::WARNING, | |
| 185 | - ], | |
| 186 | - 'Invalid nodeinfo' => [ | |
| 187 | - [ | |
| 188 | - $this->generate([$createResponse(404, $wellKnownHeader)]), | |
| 189 | - $this->generate([$createResponse(404)]), | |
| 190 | - $this->generate([$createResponse(207)]), | |
| 191 | - $this->generate([$createResponse(207)]), | |
| 192 | - ], | |
| 193 | - SetupResult::WARNING, | |
| 194 | - ], | |
| 195 | - 'Invalid caldav' => [ | |
| 196 | - [ | |
| 197 | - $this->generate([$createResponse(404, $wellKnownHeader)]), | |
| 198 | - $this->generate([$createResponse(404, $wellKnownHeader)]), | |
| 199 | - $this->generate([$createResponse(404)]), | |
| 200 | - $this->generate([$createResponse(207)]), | |
| 201 | - ], | |
| 202 | - SetupResult::WARNING, | |
| 203 | - ], | |
| 204 | - ]; | |
| 205 | - } | |
| 206 | - | |
| 207 | - /** | |
| 208 | - * Helper function creates a nicer interface for mocking Generator behavior | |
| 209 | - */ | |
| 210 | -	protected function generate(array $yield_values) { | |
| 211 | -		return $this->returnCallback(function () use ($yield_values) { | |
| 212 | - yield from $yield_values; | |
| 213 | - }); | |
| 214 | - } | |
| 23 | + private IL10N&MockObject $l10n; | |
| 24 | + private IConfig&MockObject $config; | |
| 25 | + private IURLGenerator&MockObject $urlGenerator; | |
| 26 | + private IClientService&MockObject $clientService; | |
| 27 | + private LoggerInterface&MockObject $logger; | |
| 28 | + private WellKnownUrls&MockObject $setupcheck; | |
| 29 | + | |
| 30 | +    protected function setUp(): void { | |
| 31 | + parent::setUp(); | |
| 32 | + | |
| 33 | + /** @var IL10N&MockObject */ | |
| 34 | + $this->l10n = $this->createMock(IL10N::class); | |
| 35 | + $this->l10n->expects($this->any()) | |
| 36 | +            ->method('t') | |
| 37 | +            ->willReturnCallback(function ($message, array $replace) { | |
| 38 | + return vsprintf($message, $replace); | |
| 39 | + }); | |
| 40 | + | |
| 41 | + $this->config = $this->createMock(IConfig::class); | |
| 42 | + $this->urlGenerator = $this->createMock(IURLGenerator::class); | |
| 43 | + $this->clientService = $this->createMock(IClientService::class); | |
| 44 | + $this->logger = $this->createMock(LoggerInterface::class); | |
| 45 | + | |
| 46 | + $this->setupcheck = $this->getMockBuilder(WellKnownUrls::class) | |
| 47 | + ->onlyMethods(['runRequest']) | |
| 48 | + ->setConstructorArgs([ | |
| 49 | + $this->l10n, | |
| 50 | + $this->config, | |
| 51 | + $this->urlGenerator, | |
| 52 | + $this->clientService, | |
| 53 | + $this->logger, | |
| 54 | + ]) | |
| 55 | + ->getMock(); | |
| 56 | + } | |
| 57 | + | |
| 58 | + /** | |
| 59 | + * Test that the SetupCheck is skipped if the system config is set | |
| 60 | + */ | |
| 61 | +    public function testDisabled(): void { | |
| 62 | + $this->config | |
| 63 | + ->expects($this->once()) | |
| 64 | +            ->method('getSystemValueBool') | |
| 65 | +            ->with('check_for_working_wellknown_setup') | |
| 66 | + ->willReturn(false); | |
| 67 | + | |
| 68 | + $this->setupcheck | |
| 69 | + ->expects($this->never()) | |
| 70 | +            ->method('runRequest'); | |
| 71 | + | |
| 72 | + $result = $this->setupcheck->run(); | |
| 73 | + $this->assertEquals(SetupResult::INFO, $result->getSeverity()); | |
| 74 | +        $this->assertMatchesRegularExpression('/check was skipped/', $result->getDescription()); | |
| 75 | + } | |
| 76 | + | |
| 77 | + /** | |
| 78 | + * Test what happens if the local server could not be reached (no response from the requests) | |
| 79 | + */ | |
| 80 | +    public function testNoResponse(): void { | |
| 81 | + $this->config | |
| 82 | + ->expects($this->once()) | |
| 83 | +            ->method('getSystemValueBool') | |
| 84 | +            ->with('check_for_working_wellknown_setup') | |
| 85 | + ->willReturn(true); | |
| 86 | + | |
| 87 | + $this->setupcheck | |
| 88 | + ->expects($this->once()) | |
| 89 | +            ->method('runRequest') | |
| 90 | + ->will($this->generate([])); | |
| 91 | + | |
| 92 | + $result = $this->setupcheck->run(); | |
| 93 | + $this->assertEquals(SetupResult::INFO, $result->getSeverity()); | |
| 94 | +        $this->assertMatchesRegularExpression('/^Could not check/', $result->getDescription()); | |
| 95 | + } | |
| 96 | + | |
| 97 | + /** | |
| 98 | + * Test responses | |
| 99 | + */ | |
| 100 | +    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestResponses')] | |
| 101 | +    public function testResponses($responses, string $expectedSeverity): void { | |
| 102 | + $this->config | |
| 103 | + ->expects($this->once()) | |
| 104 | +            ->method('getSystemValueBool') | |
| 105 | +            ->with('check_for_working_wellknown_setup') | |
| 106 | + ->willReturn(true); | |
| 107 | + | |
| 108 | + $this->setupcheck | |
| 109 | + ->expects($this->atLeastOnce()) | |
| 110 | +            ->method('runRequest') | |
| 111 | + ->willReturnOnConsecutiveCalls(...$responses); | |
| 112 | + | |
| 113 | + $result = $this->setupcheck->run(); | |
| 114 | + $this->assertEquals($expectedSeverity, $result->getSeverity()); | |
| 115 | + } | |
| 116 | + | |
| 117 | +    public function dataTestResponses(): array { | |
| 118 | +        $createResponse = function (int $statuscode, array $header = []): IResponse&MockObject { | |
| 119 | + $response = $this->createMock(IResponse::class); | |
| 120 | + $response->expects($this->any()) | |
| 121 | +                ->method('getStatusCode') | |
| 122 | + ->willReturn($statuscode); | |
| 123 | + $response->expects($this->any()) | |
| 124 | +                ->method('getHeader') | |
| 125 | + ->willReturnCallback(fn ($name) => $header[$name] ?? ''); | |
| 126 | + return $response; | |
| 127 | + }; | |
| 128 | + | |
| 129 | + $wellKnownHeader = ['X-NEXTCLOUD-WELL-KNOWN' => 'yes']; | |
| 130 | + | |
| 131 | + return [ | |
| 132 | + 'expected codes' => [ | |
| 133 | + [ | |
| 134 | + $this->generate([$createResponse(200, $wellKnownHeader)]), | |
| 135 | + $this->generate([$createResponse(200, $wellKnownHeader)]), | |
| 136 | + $this->generate([$createResponse(207)]), | |
| 137 | + $this->generate([$createResponse(207)]), | |
| 138 | + ], | |
| 139 | + SetupResult::SUCCESS, | |
| 140 | + ], | |
| 141 | + 'late response with expected codes' => [ | |
| 142 | + [ | |
| 143 | + $this->generate([$createResponse(404), $createResponse(200, $wellKnownHeader)]), | |
| 144 | + $this->generate([$createResponse(404), $createResponse(200, $wellKnownHeader)]), | |
| 145 | + $this->generate([$createResponse(404), $createResponse(207)]), | |
| 146 | + $this->generate([$createResponse(404), $createResponse(207)]), | |
| 147 | + ], | |
| 148 | + SetupResult::SUCCESS, | |
| 149 | + ], | |
| 150 | + 'working but disabled webfinger' => [ | |
| 151 | + [ | |
| 152 | + $this->generate([$createResponse(404, $wellKnownHeader)]), | |
| 153 | + $this->generate([$createResponse(404, $wellKnownHeader)]), | |
| 154 | + $this->generate([$createResponse(207)]), | |
| 155 | + $this->generate([$createResponse(207)]), | |
| 156 | + ], | |
| 157 | + SetupResult::SUCCESS, | |
| 158 | + ], | |
| 159 | + 'unauthorized webdav but with correct configured redirect' => [ | |
| 160 | + [ | |
| 161 | + $this->generate([$createResponse(404, $wellKnownHeader)]), | |
| 162 | + $this->generate([$createResponse(404, $wellKnownHeader)]), | |
| 163 | + $this->generate([$createResponse(401, ['X-Guzzle-Redirect-History' => 'https://example.com,https://example.com/remote.php/dav/'])]), | |
| 164 | + $this->generate([$createResponse(401, ['X-Guzzle-Redirect-History' => 'https://example.com/remote.php/dav/'])]), | |
| 165 | + ], | |
| 166 | + SetupResult::SUCCESS, | |
| 167 | + ], | |
| 168 | + 'not configured path' => [ | |
| 169 | + [ | |
| 170 | + $this->generate([$createResponse(404)]), | |
| 171 | + $this->generate([$createResponse(404)]), | |
| 172 | + $this->generate([$createResponse(404)]), | |
| 173 | + $this->generate([$createResponse(404)]), | |
| 174 | + ], | |
| 175 | + SetupResult::WARNING, | |
| 176 | + ], | |
| 177 | + 'Invalid webfinger' => [ | |
| 178 | + [ | |
| 179 | + $this->generate([$createResponse(404)]), | |
| 180 | + $this->generate([$createResponse(404, $wellKnownHeader)]), | |
| 181 | + $this->generate([$createResponse(207)]), | |
| 182 | + $this->generate([$createResponse(207)]), | |
| 183 | + ], | |
| 184 | + SetupResult::WARNING, | |
| 185 | + ], | |
| 186 | + 'Invalid nodeinfo' => [ | |
| 187 | + [ | |
| 188 | + $this->generate([$createResponse(404, $wellKnownHeader)]), | |
| 189 | + $this->generate([$createResponse(404)]), | |
| 190 | + $this->generate([$createResponse(207)]), | |
| 191 | + $this->generate([$createResponse(207)]), | |
| 192 | + ], | |
| 193 | + SetupResult::WARNING, | |
| 194 | + ], | |
| 195 | + 'Invalid caldav' => [ | |
| 196 | + [ | |
| 197 | + $this->generate([$createResponse(404, $wellKnownHeader)]), | |
| 198 | + $this->generate([$createResponse(404, $wellKnownHeader)]), | |
| 199 | + $this->generate([$createResponse(404)]), | |
| 200 | + $this->generate([$createResponse(207)]), | |
| 201 | + ], | |
| 202 | + SetupResult::WARNING, | |
| 203 | + ], | |
| 204 | + ]; | |
| 205 | + } | |
| 206 | + | |
| 207 | + /** | |
| 208 | + * Helper function creates a nicer interface for mocking Generator behavior | |
| 209 | + */ | |
| 210 | +    protected function generate(array $yield_values) { | |
| 211 | +        return $this->returnCallback(function () use ($yield_values) { | |
| 212 | + yield from $yield_values; | |
| 213 | + }); | |
| 214 | + } | |
| 215 | 215 | } |