diff options
author | Ferdinand Thiessen <opensource@fthiessen.de> | 2024-09-07 16:24:27 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-07 16:24:27 +0200 |
commit | 46472d3f4c4607d30efc295564cf95d780ff4f3f (patch) | |
tree | f1121ac2959d41ed9ac9fa2b67c09ffd7fcd8337 /apps | |
parent | 80f459d82a864fc8aa593dd06abb2a9c2956960d (diff) | |
parent | 5fc715a9e2d2284751b46a928ab402ec28c7ca08 (diff) | |
download | nextcloud-server-46472d3f4c4607d30efc295564cf95d780ff4f3f.tar.gz nextcloud-server-46472d3f4c4607d30efc295564cf95d780ff4f3f.zip |
Merge pull request #43281 from nextcloud/feature/minSupportDesktopVerMsg
enh: update desktop client unsupported version (403) error message
Diffstat (limited to 'apps')
5 files changed, 79 insertions, 18 deletions
diff --git a/apps/dav/lib/CalDAV/InvitationResponse/InvitationResponseServer.php b/apps/dav/lib/CalDAV/InvitationResponse/InvitationResponseServer.php index e076b2cd1e2..6fa94eebc91 100644 --- a/apps/dav/lib/CalDAV/InvitationResponse/InvitationResponseServer.php +++ b/apps/dav/lib/CalDAV/InvitationResponse/InvitationResponseServer.php @@ -15,7 +15,9 @@ use OCA\DAV\Connector\Sabre\CachingTree; use OCA\DAV\Connector\Sabre\DavAclPlugin; use OCA\DAV\Events\SabrePluginAuthInitEvent; use OCA\DAV\RootCollection; +use OCA\Theming\ThemingDefaults; use OCP\EventDispatcher\IEventDispatcher; +use OCP\IConfig; use Psr\Log\LoggerInterface; use Sabre\VObject\ITip\Message; @@ -28,9 +30,8 @@ class InvitationResponseServer { */ public function __construct(bool $public = true) { $baseUri = \OC::$WEBROOT . '/remote.php/dav/'; - $logger = \OC::$server->get(LoggerInterface::class); - /** @var IEventDispatcher $dispatcher */ - $dispatcher = \OC::$server->query(IEventDispatcher::class); + $logger = \OCP\Server::get(LoggerInterface::class); + $dispatcher = \OCP\Server::get(IEventDispatcher::class); $root = new RootCollection(); $this->server = new \OCA\DAV\Connector\Sabre\Server(new CachingTree($root)); @@ -42,7 +43,10 @@ class InvitationResponseServer { $this->server->httpRequest->setUrl($baseUri); $this->server->setBaseUri($baseUri); - $this->server->addPlugin(new BlockLegacyClientPlugin(\OC::$server->getConfig())); + $this->server->addPlugin(new BlockLegacyClientPlugin( + \OCP\Server::get(IConfig::class), + \OCP\Server::get(ThemingDefaults::class), + )); $this->server->addPlugin(new AnonymousOptionsPlugin()); // allow custom principal uri option diff --git a/apps/dav/lib/Connector/Sabre/BlockLegacyClientPlugin.php b/apps/dav/lib/Connector/Sabre/BlockLegacyClientPlugin.php index c4e579bef0b..cff60b9e0f8 100644 --- a/apps/dav/lib/Connector/Sabre/BlockLegacyClientPlugin.php +++ b/apps/dav/lib/Connector/Sabre/BlockLegacyClientPlugin.php @@ -7,6 +7,7 @@ */ namespace OCA\DAV\Connector\Sabre; +use OCA\Theming\ThemingDefaults; use OCP\IConfig; use OCP\IRequest; use Sabre\DAV\Server; @@ -21,10 +22,11 @@ use Sabre\HTTP\RequestInterface; */ class BlockLegacyClientPlugin extends ServerPlugin { protected ?Server $server = null; - protected IConfig $config; - public function __construct(IConfig $config) { - $this->config = $config; + public function __construct( + private IConfig $config, + private ThemingDefaults $themingDefaults, + ) { } /** @@ -51,7 +53,10 @@ class BlockLegacyClientPlugin extends ServerPlugin { preg_match(IRequest::USER_AGENT_CLIENT_DESKTOP, $userAgent, $versionMatches); if (isset($versionMatches[1]) && version_compare($versionMatches[1], $minimumSupportedDesktopVersion) === -1) { - throw new \Sabre\DAV\Exception\Forbidden('Unsupported client version.'); + $customClientDesktopLink = htmlspecialchars($this->themingDefaults->getSyncClientUrl()); + $minimumSupportedDesktopVersion = htmlspecialchars($minimumSupportedDesktopVersion); + + throw new \Sabre\DAV\Exception\Forbidden("This version of the client is unsupported. Upgrade to <a href=\"$customClientDesktopLink\">version $minimumSupportedDesktopVersion or later</a>."); } } } diff --git a/apps/dav/lib/Connector/Sabre/ServerFactory.php b/apps/dav/lib/Connector/Sabre/ServerFactory.php index 2d804aad842..42d3ce1818a 100644 --- a/apps/dav/lib/Connector/Sabre/ServerFactory.php +++ b/apps/dav/lib/Connector/Sabre/ServerFactory.php @@ -11,6 +11,7 @@ use OCA\DAV\AppInfo\PluginManager; use OCA\DAV\CalDAV\DefaultCalendarValidator; use OCA\DAV\DAV\ViewOnlyPlugin; use OCA\DAV\Files\ErrorPagePlugin; +use OCA\Theming\ThemingDefaults; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Folder; use OCP\Files\IFilenameValidator; @@ -78,7 +79,10 @@ class ServerFactory { // Load plugins $server->addPlugin(new \OCA\DAV\Connector\Sabre\MaintenancePlugin($this->config, $this->l10n)); - $server->addPlugin(new \OCA\DAV\Connector\Sabre\BlockLegacyClientPlugin($this->config)); + $server->addPlugin(new BlockLegacyClientPlugin( + \OCP\Server::get(IConfig::class), + \OCP\Server::get(ThemingDefaults::class), + )); $server->addPlugin(new \OCA\DAV\Connector\Sabre\AnonymousOptionsPlugin()); $server->addPlugin($authPlugin); // FIXME: The following line is a workaround for legacy components relying on being able to send a GET to / diff --git a/apps/dav/lib/Server.php b/apps/dav/lib/Server.php index 55c8a5afec1..2784e99b5f7 100644 --- a/apps/dav/lib/Server.php +++ b/apps/dav/lib/Server.php @@ -50,6 +50,7 @@ use OCA\DAV\Provisioning\Apple\AppleProvisioningPlugin; use OCA\DAV\SystemTag\SystemTagPlugin; use OCA\DAV\Upload\ChunkingPlugin; use OCA\DAV\Upload\ChunkingV2Plugin; +use OCA\Theming\ThemingDefaults; use OCP\AppFramework\Http\Response; use OCP\Diagnostics\IEventLogger; use OCP\EventDispatcher\IEventDispatcher; @@ -110,7 +111,10 @@ class Server { $this->server->setBaseUri($this->baseUri); $this->server->addPlugin(new ProfilerPlugin($this->request)); - $this->server->addPlugin(new BlockLegacyClientPlugin(\OC::$server->getConfig())); + $this->server->addPlugin(new BlockLegacyClientPlugin( + \OCP\Server::get(IConfig::class), + \OCP\Server::get(ThemingDefaults::class), + )); $this->server->addPlugin(new AnonymousOptionsPlugin()); $authPlugin = new Plugin(); $authPlugin->addBackend(new PublicAuth()); diff --git a/apps/dav/tests/unit/Connector/Sabre/BlockLegacyClientPluginTest.php b/apps/dav/tests/unit/Connector/Sabre/BlockLegacyClientPluginTest.php index 607ad71b11d..c44f52ec713 100644 --- a/apps/dav/tests/unit/Connector/Sabre/BlockLegacyClientPluginTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/BlockLegacyClientPluginTest.php @@ -10,6 +10,7 @@ declare(strict_types=1); namespace OCA\DAV\Tests\unit\Connector\Sabre; use OCA\DAV\Connector\Sabre\BlockLegacyClientPlugin; +use OCA\Theming\ThemingDefaults; use OCP\IConfig; use PHPUnit\Framework\MockObject\MockObject; use Sabre\HTTP\RequestInterface; @@ -21,19 +22,23 @@ use Test\TestCase; * @package OCA\DAV\Tests\unit\Connector\Sabre */ class BlockLegacyClientPluginTest extends TestCase { - /** @var IConfig|MockObject */ - private $config; - /** @var BlockLegacyClientPlugin */ - private $blockLegacyClientVersionPlugin; + + private IConfig&MockObject $config; + private ThemingDefaults&MockObject $themingDefaults; + private BlockLegacyClientPlugin $blockLegacyClientVersionPlugin; protected function setUp(): void { parent::setUp(); $this->config = $this->createMock(IConfig::class); - $this->blockLegacyClientVersionPlugin = new BlockLegacyClientPlugin($this->config); + $this->themingDefaults = $this->createMock(ThemingDefaults::class); + $this->blockLegacyClientVersionPlugin = new BlockLegacyClientPlugin( + $this->config, + $this->themingDefaults, + ); } - public function oldDesktopClientProvider(): array { + public static function oldDesktopClientProvider(): array { return [ ['Mozilla/5.0 (Windows) mirall/1.5.0'], ['Mozilla/5.0 (Bogus Text) mirall/1.6.9'], @@ -45,7 +50,19 @@ class BlockLegacyClientPluginTest extends TestCase { */ public function testBeforeHandlerException(string $userAgent): void { $this->expectException(\Sabre\DAV\Exception\Forbidden::class); - $this->expectExceptionMessage('Unsupported client version.'); + + $this->themingDefaults + ->expects($this->once()) + ->method('getSyncClientUrl') + ->willReturn('https://nextcloud.com/install/#install-clients'); + + $this->config + ->expects($this->once()) + ->method('getSystemValue') + ->with('minimum.supported.desktop.version', '2.3.0') + ->willReturn('1.7.0'); + + $this->expectExceptionMessage('This version of the client is unsupported. Upgrade to <a href="https://nextcloud.com/install/#install-clients">version 1.7.0 or later</a>.'); /** @var RequestInterface|MockObject $request */ $request = $this->createMock('\Sabre\HTTP\RequestInterface'); @@ -55,11 +72,38 @@ class BlockLegacyClientPluginTest extends TestCase { ->with('User-Agent') ->willReturn($userAgent); + + $this->blockLegacyClientVersionPlugin->beforeHandler($request); + } + + /** + * Ensure that there is no room for XSS attack through configured URL / version + * @dataProvider oldDesktopClientProvider + */ + public function testBeforeHandlerExceptionPreventXSSAttack(string $userAgent): void { + $this->expectException(\Sabre\DAV\Exception\Forbidden::class); + + $this->themingDefaults + ->expects($this->once()) + ->method('getSyncClientUrl') + ->willReturn('https://example.com"><script>alter("hacked");</script>'); + $this->config ->expects($this->once()) ->method('getSystemValue') ->with('minimum.supported.desktop.version', '2.3.0') - ->willReturn('1.7.0'); + ->willReturn('1.7.0 <script>alert("unsafe")</script>'); + + $this->expectExceptionMessage('This version of the client is unsupported. Upgrade to <a href="https://example.com"><script>alter("hacked");</script>">version 1.7.0 <script>alert("unsafe")</script> or later</a>.'); + + /** @var RequestInterface|MockObject $request */ + $request = $this->createMock('\Sabre\HTTP\RequestInterface'); + $request + ->expects($this->once()) + ->method('getHeader') + ->with('User-Agent') + ->willReturn($userAgent); + $this->blockLegacyClientVersionPlugin->beforeHandler($request); } |