From 7d38ec5d522869282b000dc965debdfefa0e272a Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Fri, 15 May 2020 10:56:16 +0200 Subject: [PATCH] Update minimum version for supported clients Signed-off-by: Georg Ehrke --- lib/UserAgentManager.php | 45 +++++------ tests/Unit/UserAgentManagerTest.php | 121 +++++++++++++++------------- 2 files changed, 87 insertions(+), 79 deletions(-) diff --git a/lib/UserAgentManager.php b/lib/UserAgentManager.php index ecb9413f..96f2fdd8 100644 --- a/lib/UserAgentManager.php +++ b/lib/UserAgentManager.php @@ -38,9 +38,9 @@ class UserAgentManager { public function __construct() { $this->supportedUserAgents = [ - '/^Mozilla\/5\.0 \(Android\) Nextcloud\-android.*$/' => '', - Request::USER_AGENT_CLIENT_DESKTOP => '', - '/^Mozilla\/5\.0 \(iOS\) Nextcloud\-iOS.*$/' => '2.20.0', + '/^Mozilla\/5\.0 \(Android\) Nextcloud\-android\/(?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)).*$/' => '3.13.0', + '/^Mozilla\/5\.0 \([A-Za-z ]+\) (mirall|csyncoC)\/(?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)).*$/' => '2.7.0', + '/^Mozilla\/5\.0 \(iOS\) Nextcloud\-iOS\/(?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)).*$/' => '3.0.0', ]; } @@ -51,34 +51,31 @@ public function __construct() { * @return bool */ public function supportsEndToEndEncryption(string $client): bool { - foreach ($this->supportedUserAgents as $regex => $minVersion) { - if (preg_match($regex, $client)) { - return $this->checkVersion($client, $minVersion); + $supportedUAs = $this->getSupportedUserAgents(); + + foreach ($supportedUAs as $regex => $minVersion) { + $doesMatch = preg_match($regex, $client, $matches); + if ($doesMatch === 0) { + continue; + } + + if (empty($minVersion)) { + return true; + } + if (!isset($matches['version'])) { + return false; } + + return (version_compare($matches['version'], $minVersion) > -1); } return false; } /** - * check the client version - * - * @param string $client - * @param string $minVersion - * @return bool returns true if clientVersion >= minVersion or if no min Version is specified + * @return array|string[] */ - protected function checkVersion(string $client, string $minVersion): bool { - - // no minVersion given, all client versions are compatible - if (empty($minVersion)) { - return true; - } - - $version = substr(strrchr($client, '/'), 1); - if (!empty($version) && version_compare($version, $minVersion) > -1) { - return true; - } - - return false; + protected function getSupportedUserAgents(): array { + return $this->supportedUserAgents; } } diff --git a/tests/Unit/UserAgentManagerTest.php b/tests/Unit/UserAgentManagerTest.php index 7c4ef1dc..b157b757 100644 --- a/tests/Unit/UserAgentManagerTest.php +++ b/tests/Unit/UserAgentManagerTest.php @@ -25,84 +25,95 @@ namespace OCA\EndToEndEncryption\Tests\Unit; use OCA\EndToEndEncryption\UserAgentManager; -use PHPUnit_Framework_MockObject_MockObject; use Test\TestCase; class UserAgentManagerTest extends TestCase { /** - * create userAgentManager instance + * @param string $client + * @param bool $expected * - * @param array $mockedMethods - * @return UserAgentManager|PHPUnit_Framework_MockObject_MockObject + * @dataProvider supportsEndToEndEncryptionDataProvider */ - private function getUserAgentManager($mockedMethods = []) { - if (empty($mockedMethods)) { - return new UserAgentManager(); - } + public function testSupportsEndToEndEncryption(string $client, + bool $expected): void { + $supportedUAs = $this->getSupportedUserAgents(); + $userAgentManager = $this->getUserAgentManager(['getSupportedUserAgents']); + $userAgentManager->expects($this->once()) + ->method('getSupportedUserAgents') + ->willReturn($supportedUAs); - $userAgentManager = $this->getMockBuilder(UserAgentManager::class) - ->setMethods($mockedMethods)->getMock(); - return $userAgentManager; + $actual = $userAgentManager->supportsEndToEndEncryption($client); + $this->assertEquals($expected, $actual); } /** - * @dataProvider dataTestCheckVersion - * - * @param string $client - * @param string $minVersion - * @param bool $expected + * @return array */ - public function testCheckVersion($client, $minVersion, $expected): void { - $userAgentManager = $this->getUserAgentManager(); - $result = $this->invokePrivate($userAgentManager, 'checkVersion', [$client, $minVersion]); - $this->assertSame($expected, $result); - } - - public function dataTestCheckVersion(): array { + public function supportsEndToEndEncryptionDataProvider(): array { return [ // Android - ['Mozilla/5.0 (Android) Nextcloud-android/2.1.3', '', true], - ['Mozilla/5.0 (Android) Nextcloud-android/2.1.3', '1.9.3', true], - ['Mozilla/5.0 (Android) Nextcloud-android/2.1.3', '2.1.3', true], - ['Mozilla/5.0 (Android) Nextcloud-android/2.1.3', '2.1.4', false], + ['Mozilla/5.0 (Android) Nextcloud-android/1.9.9', false], + ['Mozilla/5.0 (Android) Nextcloud-android/2.1.3', false], + ['Mozilla/5.0 (Android) Nextcloud-android/2.3.3', false], + ['Mozilla/5.0 (Android) Nextcloud-android/2.3.4', true], + ['Mozilla/5.0 (Android) Nextcloud-android/2.4.9', true], + ['Mozilla/5.0 (Android) Nextcloud-android/3.0.0', true], + // Android without version + ['Mozilla/5.0 (Android) Nextcloud-android/beta', false], + ['Mozilla/5.0 (Android) Nextcloud-android/', false], + ['Mozilla/5.0 (Android) Nextcloud-android', false], // iOS - ['Mozilla/5.0 (iOS) Nextcloud-iOS/2.1.3', '', true], - ['Mozilla/5.0 (iOS) Nextcloud-iOS/2.1.3', '1.9.3', true], - ['Mozilla/5.0 (iOS) Nextcloud-iOS/2.1.3', '2.1.3', true], - ['Mozilla/5.0 (iOS) Nextcloud-iOS/2.1.3', '2.1.4', false], - // no valid version should result in false - ['Mozilla/5.0 (Android) Nextcloud-android/', '2.1.4', false], - ['Mozilla/5.0 (Android) Nextcloud-android/zzz', '2.1.4', false], + ['Mozilla/5.0 (iOS) Nextcloud-iOS/1.9.9', false], + ['Mozilla/5.0 (iOS) Nextcloud-iOS/2.1.3', false], + ['Mozilla/5.0 (iOS) Nextcloud-iOS/2.3.3', false], + ['Mozilla/5.0 (iOS) Nextcloud-iOS/2.3.4', true], + ['Mozilla/5.0 (iOS) Nextcloud-iOS/2.4.9', true], + ['Mozilla/5.0 (iOS) Nextcloud-iOS/3.0.0', true], + // iOS without version + ['Mozilla/5.0 (iOS) Nextcloud-iOS/beta', false], + ['Mozilla/5.0 (iOS) Nextcloud-iOS/', false], + ['Mozilla/5.0 (iOS) Nextcloud-iOS', false], + // Desktop + ['Mozilla/5.0 (Macintosh) mirall/1.9.9stable (build 20200303) (Nextcloud)', false], + ['Mozilla/5.0 (Macintosh) mirall/2.1.3rc (build 20200303)', false], + ['Mozilla/5.0 (Macintosh) mirall/2.3.3', false], + ['Mozilla/5.0 (Linux) mirall/2.3.4', true], + ['Mozilla/5.0 (Macintosh) csyncoC/2.4.9RC (build 20200303) (Nextcloud)', true], + ['Mozilla/5.0 (Macintosh) mirall/3.0.0 (build 20200303)', true], + // Desktop without version + ['Mozilla/5.0 (Macintosh) mirall/ (build 20200303)', false], + ['Mozilla/5.0 (Macintosh) mirall/', false], + ['Mozilla/5.0 (Macintosh) mirall', false], ]; } + private function getUserAgentManager(array $mockedMethods = []) { + if (empty($mockedMethods)) { + return new UserAgentManager(); + } + + return $this + ->getMockBuilder(UserAgentManager::class) + ->setMethods($mockedMethods) + ->getMock(); + } + /** - * @dataProvider dataTestSupportsEndToEndEncryption + * This function returns the user agents to test against + * It keeps the original regex, but replaces the exact version + * so this test suite doesn't break on a simple version bump * - * @param string $client - * @param bool $expected + * @return array */ - public function testSupportsEndToEndEncryption($client, $expected): void { - $userAgentManager = $this->getUserAgentManager(['checkVersion']); + private function getSupportedUserAgents(): array { + $userAgentManager = new UserAgentManager(); + $originalRules = self::invokePrivate($userAgentManager, 'getSupportedUserAgents'); - if ($expected === true) { - $userAgentManager->expects($this->once())->method('checkVersion') - ->willReturn($expected); - } else { - $userAgentManager->expects($this->never())->method('checkVersion'); + foreach ($originalRules as $regex => $version) { + $originalRules[$regex] = '2.3.4'; } - $result = $userAgentManager->supportsEndToEndEncryption($client); - $this->assertSame($expected, $result); - } - - public function dataTestSupportsEndToEndEncryption(): array { - return [ - ['Mozilla/5.0 (Android) ownCloud-android/2.1.3', false], - ['Mozilla/5.0 (iOS) ownCloud-iOS/2.20.1', false], - ['Mozilla/5.0 (iOS) Nextcloud-iOS/2.20.1', true], - ['Mozilla/5.0 (Android) Nextcloud-android/2.1.3', true], - ]; + return $originalRules; } }