mirror of
https://github.com/nextcloud/server.git
synced 2026-05-28 04:32:30 -04:00
feat(config): add maximum.supported.desktop.version
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
This commit is contained in:
parent
21666e0bc0
commit
8c0f8db6ca
3 changed files with 80 additions and 28 deletions
|
|
@ -49,14 +49,26 @@ class BlockLegacyClientPlugin extends ServerPlugin {
|
|||
return;
|
||||
}
|
||||
|
||||
$minimumSupportedDesktopVersion = $this->config->getSystemValue('minimum.supported.desktop.version', '2.3.0');
|
||||
$minimumSupportedDesktopVersion = $this->config->getSystemValueString('minimum.supported.desktop.version', '2.3.0');
|
||||
$maximumSupportedDesktopVersion = $this->config->getSystemValueString('maximum.supported.desktop.version', '99.99.99');
|
||||
|
||||
// Check if the client is a desktop client
|
||||
preg_match(IRequest::USER_AGENT_CLIENT_DESKTOP, $userAgent, $versionMatches);
|
||||
if (isset($versionMatches[1]) &&
|
||||
version_compare($versionMatches[1], $minimumSupportedDesktopVersion) === -1) {
|
||||
|
||||
// If the client is a desktop client and the version is too old, block it
|
||||
if (isset($versionMatches[1]) && version_compare($versionMatches[1], $minimumSupportedDesktopVersion) === -1) {
|
||||
$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>.");
|
||||
}
|
||||
|
||||
// If the client is a desktop client and the version is too new, block it
|
||||
if (isset($versionMatches[1]) && version_compare($versionMatches[1], $maximumSupportedDesktopVersion) === 1) {
|
||||
$customClientDesktopLink = htmlspecialchars($this->themingDefaults->getSyncClientUrl());
|
||||
$maximumSupportedDesktopVersion = htmlspecialchars($maximumSupportedDesktopVersion);
|
||||
|
||||
throw new \Sabre\DAV\Exception\Forbidden("This version of the client is unsupported. Downgrade to <a href=\"$customClientDesktopLink\">version $maximumSupportedDesktopVersion or earlier</a>.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,12 @@ use PHPUnit\Framework\MockObject\MockObject;
|
|||
use Sabre\HTTP\RequestInterface;
|
||||
use Test\TestCase;
|
||||
|
||||
enum ERROR_TYPE {
|
||||
case MIN_ERROR;
|
||||
case MAX_ERROR;
|
||||
case NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class BlockLegacyClientPluginTest
|
||||
*
|
||||
|
|
@ -40,29 +46,41 @@ class BlockLegacyClientPluginTest extends TestCase {
|
|||
|
||||
public static function oldDesktopClientProvider(): array {
|
||||
return [
|
||||
['Mozilla/5.0 (Windows) mirall/1.5.0'],
|
||||
['Mozilla/5.0 (Bogus Text) mirall/1.6.9'],
|
||||
['Mozilla/5.0 (Windows) mirall/1.5.0', ERROR_TYPE::MIN_ERROR],
|
||||
['Mozilla/5.0 (Bogus Text) mirall/1.6.9', ERROR_TYPE::MIN_ERROR],
|
||||
['Mozilla/5.0 (Windows) mirall/2.5.0', ERROR_TYPE::MAX_ERROR],
|
||||
['Mozilla/5.0 (Bogus Text) mirall/2.0.1', ERROR_TYPE::MAX_ERROR],
|
||||
['Mozilla/5.0 (Windows) mirall/2.0.0', ERROR_TYPE::NONE],
|
||||
['Mozilla/5.0 (Bogus Text) mirall/2.0.0', ERROR_TYPE::NONE],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider oldDesktopClientProvider
|
||||
*/
|
||||
public function testBeforeHandlerException(string $userAgent): void {
|
||||
$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
|
||||
|
||||
public function testBeforeHandlerException(string $userAgent, ERROR_TYPE $errorType): void {
|
||||
$this->themingDefaults
|
||||
->expects($this->once())
|
||||
->expects($this->atMost(1))
|
||||
->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');
|
||||
->expects($this->exactly(2))
|
||||
->method('getSystemValueString')
|
||||
->willReturnCallback(function (string $key) {
|
||||
if ($key === 'minimum.supported.desktop.version') {
|
||||
return '1.7.0';
|
||||
}
|
||||
return '2.0.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>.');
|
||||
if ($errorType !== ERROR_TYPE::NONE) {
|
||||
$errorString = $errorType === ERROR_TYPE::MIN_ERROR
|
||||
? 'This version of the client is unsupported. Upgrade to <a href="https://nextcloud.com/install/#install-clients">version 1.7.0 or later</a>.'
|
||||
: 'This version of the client is unsupported. Downgrade to <a href="https://nextcloud.com/install/#install-clients">version 2.0.0 or earlier</a>.';
|
||||
$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
|
||||
$this->expectExceptionMessage($errorString);
|
||||
}
|
||||
|
||||
/** @var RequestInterface|MockObject $request */
|
||||
$request = $this->createMock('\Sabre\HTTP\RequestInterface');
|
||||
|
|
@ -72,7 +90,6 @@ class BlockLegacyClientPluginTest extends TestCase {
|
|||
->with('User-Agent')
|
||||
->willReturn($userAgent);
|
||||
|
||||
|
||||
$this->blockLegacyClientVersionPlugin->beforeHandler($request);
|
||||
}
|
||||
|
||||
|
|
@ -80,21 +97,28 @@ class BlockLegacyClientPluginTest extends TestCase {
|
|||
* Ensure that there is no room for XSS attack through configured URL / version
|
||||
* @dataProvider oldDesktopClientProvider
|
||||
*/
|
||||
public function testBeforeHandlerExceptionPreventXSSAttack(string $userAgent): void {
|
||||
public function testBeforeHandlerExceptionPreventXSSAttack(string $userAgent, ERROR_TYPE $errorType): void {
|
||||
$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
|
||||
|
||||
$this->themingDefaults
|
||||
->expects($this->once())
|
||||
->expects($this->atMost(1))
|
||||
->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 <script>alert("unsafe")</script>');
|
||||
->expects($this->exactly(2))
|
||||
->method('getSystemValueString')
|
||||
->willReturnCallback(function (string $key) {
|
||||
if ($key === 'minimum.supported.desktop.version') {
|
||||
return '1.7.0 <script>alert("unsafe")</script>';
|
||||
}
|
||||
return '2.0.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>.');
|
||||
$errorString = $errorType === ERROR_TYPE::MIN_ERROR
|
||||
? '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>.'
|
||||
: 'This version of the client is unsupported. Downgrade to <a href="https://example.com"><script>alter("hacked");</script>">version 2.0.0 <script>alert("unsafe")</script> or earlier</a>.';
|
||||
$this->expectExceptionMessage($errorString);
|
||||
|
||||
/** @var RequestInterface|MockObject $request */
|
||||
$request = $this->createMock('\Sabre\HTTP\RequestInterface');
|
||||
|
|
@ -104,15 +128,17 @@ class BlockLegacyClientPluginTest extends TestCase {
|
|||
->with('User-Agent')
|
||||
->willReturn($userAgent);
|
||||
|
||||
|
||||
$this->blockLegacyClientVersionPlugin->beforeHandler($request);
|
||||
}
|
||||
|
||||
public function newAndAlternateDesktopClientProvider(): array {
|
||||
public static function newAndAlternateDesktopClientProvider(): array {
|
||||
return [
|
||||
['Mozilla/5.0 (Windows) mirall/1.7.0'],
|
||||
['Mozilla/5.0 (Bogus Text) mirall/1.9.3'],
|
||||
['Mozilla/5.0 (Not Our Client But Old Version) LegacySync/1.1.0'],
|
||||
['Mozilla/5.0 (Windows) mirall/4.7.0'],
|
||||
['Mozilla/5.0 (Bogus Text) mirall/3.9.3'],
|
||||
['Mozilla/5.0 (Not Our Client But Old Version) LegacySync/45.0.0'],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -129,10 +155,14 @@ class BlockLegacyClientPluginTest extends TestCase {
|
|||
->willReturn($userAgent);
|
||||
|
||||
$this->config
|
||||
->expects($this->once())
|
||||
->method('getSystemValue')
|
||||
->with('minimum.supported.desktop.version', '2.3.0')
|
||||
->willReturn('1.7.0');
|
||||
->expects($this->exactly(2))
|
||||
->method('getSystemValueString')
|
||||
->willReturnCallback(function (string $key) {
|
||||
if ($key === 'minimum.supported.desktop.version') {
|
||||
return '1.7.0';
|
||||
}
|
||||
return '10.0.0';
|
||||
});
|
||||
|
||||
$this->blockLegacyClientVersionPlugin->beforeHandler($request);
|
||||
}
|
||||
|
|
@ -145,6 +175,7 @@ class BlockLegacyClientPluginTest extends TestCase {
|
|||
->method('getHeader')
|
||||
->with('User-Agent')
|
||||
->willReturn(null);
|
||||
|
||||
$this->blockLegacyClientVersionPlugin->beforeHandler($request);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2136,6 +2136,15 @@ $CONFIG = [
|
|||
*/
|
||||
'minimum.supported.desktop.version' => '2.3.0',
|
||||
|
||||
/**
|
||||
* The maximum Nextcloud desktop client version that will be allowed to sync with
|
||||
* this server instance. All connections made from later clients will be denied
|
||||
* by the server.
|
||||
*
|
||||
* Defaults to 99.99.99
|
||||
*/
|
||||
'maximum.supported.desktop.version' => '99.99.99',
|
||||
|
||||
/**
|
||||
* Option to allow local storage to contain symlinks.
|
||||
* WARNING: Not recommended. This would make it possible for Nextcloud to access
|
||||
|
|
|
|||
Loading…
Reference in a new issue