diff options
34 files changed, 502 insertions, 509 deletions
diff --git a/apps/dav/lib/CardDAV/SyncService.php b/apps/dav/lib/CardDAV/SyncService.php index 477e912a797..b6f57753431 100644 --- a/apps/dav/lib/CardDAV/SyncService.php +++ b/apps/dav/lib/CardDAV/SyncService.php @@ -75,6 +75,7 @@ class SyncService { /** * @param string $url * @param string $userName + * @param string $addressBookUrl * @param string $sharedSecret * @param string $syncToken * @param int $targetBookId @@ -83,14 +84,14 @@ class SyncService { * @return string * @throws \Exception */ - public function syncRemoteAddressBook($url, $userName, $sharedSecret, $syncToken, $targetBookId, $targetPrincipal, $targetProperties) { + public function syncRemoteAddressBook($url, $userName, $addressBookUrl, $sharedSecret, $syncToken, $targetBookId, $targetPrincipal, $targetProperties) { // 1. create addressbook $book = $this->ensureSystemAddressBookExists($targetPrincipal, $targetBookId, $targetProperties); $addressBookId = $book['id']; // 2. query changes try { - $response = $this->requestSyncReport($url, $userName, $sharedSecret, $syncToken); + $response = $this->requestSyncReport($url, $userName, $addressBookUrl, $sharedSecret, $syncToken); } catch (ClientHttpException $ex) { if ($ex->getCode() === Http::STATUS_UNAUTHORIZED) { // remote server revoked access to the address book, remove it @@ -105,7 +106,7 @@ class SyncService { foreach ($response['response'] as $resource => $status) { $cardUri = basename($resource); if (isset($status[200])) { - $vCard = $this->download($url, $sharedSecret, $resource); + $vCard = $this->download($url, $userName, $sharedSecret, $resource); $existingCard = $this->backend->getCard($addressBookId, $cardUri); if ($existingCard === false) { $this->backend->createCard($addressBookId, $cardUri, $vCard['body']); @@ -162,6 +163,7 @@ class SyncService { /** * @param string $url * @param string $userName + * @param string $addressBookUrl * @param string $sharedSecret * @return Client */ @@ -185,31 +187,32 @@ class SyncService { /** * @param string $url * @param string $userName + * @param string $addressBookUrl * @param string $sharedSecret * @param string $syncToken * @return array */ - protected function requestSyncReport($url, $userName, $sharedSecret, $syncToken) { - $client = $this->getClient($url, $userName, $sharedSecret); + protected function requestSyncReport($url, $userName, $addressBookUrl, $sharedSecret, $syncToken) { + $client = $this->getClient($url, $userName, $sharedSecret); - $addressBookUrl = "remote.php/dav/addressbooks/system/system/system"; - $body = $this->buildSyncCollectionRequestBody($syncToken); + $body = $this->buildSyncCollectionRequestBody($syncToken); - $response = $client->request('REPORT', $addressBookUrl, $body, [ - 'Content-Type' => 'application/xml' - ]); + $response = $client->request('REPORT', $addressBookUrl, $body, [ + 'Content-Type' => 'application/xml' + ]); - return $this->parseMultiStatus($response['body']); - } + return $this->parseMultiStatus($response['body']); + } /** * @param string $url + * @param string $userName * @param string $sharedSecret * @param string $resourcePath * @return array */ - protected function download($url, $sharedSecret, $resourcePath) { - $client = $this->getClient($url, 'system', $sharedSecret); + protected function download($url, $userName, $sharedSecret, $resourcePath) { + $client = $this->getClient($url, $userName, $sharedSecret); return $client->request('GET', $resourcePath); } diff --git a/apps/dav/tests/unit/CardDAV/SyncServiceTest.php b/apps/dav/tests/unit/CardDAV/SyncServiceTest.php index c06e4857743..32f8a2424b1 100644 --- a/apps/dav/tests/unit/CardDAV/SyncServiceTest.php +++ b/apps/dav/tests/unit/CardDAV/SyncServiceTest.php @@ -37,7 +37,7 @@ class SyncServiceTest extends TestCase { $backend = $this->getBackendMock(0, 0, 0); $ss = $this->getSyncServiceMock($backend, []); - $return = $ss->syncRemoteAddressBook('', 'system', '1234567890', null, '1', 'principals/system/system', []); + $return = $ss->syncRemoteAddressBook('', 'system', 'system', '1234567890', null, '1', 'principals/system/system', []); $this->assertEquals('sync-token-1', $return); } @@ -46,7 +46,7 @@ class SyncServiceTest extends TestCase { $backend->method('getCard')->willReturn(false); $ss = $this->getSyncServiceMock($backend, ['0' => [200 => '']]); - $return = $ss->syncRemoteAddressBook('', 'system', '1234567890', null, '1', 'principals/system/system', []); + $return = $ss->syncRemoteAddressBook('', 'system', 'system', '1234567890', null, '1', 'principals/system/system', []); $this->assertEquals('sync-token-1', $return); } @@ -55,7 +55,7 @@ class SyncServiceTest extends TestCase { $backend->method('getCard')->willReturn(true); $ss = $this->getSyncServiceMock($backend, ['0' => [200 => '']]); - $return = $ss->syncRemoteAddressBook('', 'system', '1234567890', null, '1', 'principals/system/system', []); + $return = $ss->syncRemoteAddressBook('', 'system', 'system', '1234567890', null, '1', 'principals/system/system', []); $this->assertEquals('sync-token-1', $return); } @@ -63,7 +63,7 @@ class SyncServiceTest extends TestCase { $backend = $this->getBackendMock(0, 0, 1); $ss = $this->getSyncServiceMock($backend, ['0' => [404 => '']]); - $return = $ss->syncRemoteAddressBook('', 'system', '1234567890', null, '1', 'principals/system/system', []); + $return = $ss->syncRemoteAddressBook('', 'system', 'system', '1234567890', null, '1', 'principals/system/system', []); $this->assertEquals('sync-token-1', $return); } diff --git a/apps/federatedfilesharing/lib/AppInfo/Application.php b/apps/federatedfilesharing/lib/AppInfo/Application.php index 3e97edeada0..9d8464e37d5 100644 --- a/apps/federatedfilesharing/lib/AppInfo/Application.php +++ b/apps/federatedfilesharing/lib/AppInfo/Application.php @@ -51,10 +51,7 @@ class Application extends App { $notification = new Notifications( $addressHandler, $server->getHTTPClientService(), - new \OCA\FederatedFileSharing\DiscoveryManager( - $server->getMemCacheFactory(), - $server->getHTTPClientService() - ), + $server->query(\OCP\OCS\IDiscoveryService::class), \OC::$server->getJobList() ); return new RequestHandlerController( @@ -99,14 +96,10 @@ class Application extends App { \OC::$server->getL10N('federatedfilesharing'), \OC::$server->getCloudIdManager() ); - $discoveryManager = new \OCA\FederatedFileSharing\DiscoveryManager( - \OC::$server->getMemCacheFactory(), - \OC::$server->getHTTPClientService() - ); $notifications = new \OCA\FederatedFileSharing\Notifications( $addressHandler, \OC::$server->getHTTPClientService(), - $discoveryManager, + \OC::$server->query(\OCP\OCS\IDiscoveryService::class), \OC::$server->getJobList() ); $tokenHandler = new \OCA\FederatedFileSharing\TokenHandler( diff --git a/apps/federatedfilesharing/lib/BackgroundJob/RetryJob.php b/apps/federatedfilesharing/lib/BackgroundJob/RetryJob.php index 2356c569d87..821647e5e39 100644 --- a/apps/federatedfilesharing/lib/BackgroundJob/RetryJob.php +++ b/apps/federatedfilesharing/lib/BackgroundJob/RetryJob.php @@ -27,7 +27,6 @@ namespace OCA\FederatedFileSharing\BackgroundJob; use OC\BackgroundJob\Job; use OC\BackgroundJob\JobList; use OCA\FederatedFileSharing\AddressHandler; -use OCA\FederatedFileSharing\DiscoveryManager; use OCA\FederatedFileSharing\Notifications; use OCP\BackgroundJob\IJobList; use OCP\ILogger; @@ -68,14 +67,10 @@ class RetryJob extends Job { \OC::$server->getL10N('federatedfilesharing'), \OC::$server->getCloudIdManager() ); - $discoveryManager = new DiscoveryManager( - \OC::$server->getMemCacheFactory(), - \OC::$server->getHTTPClientService() - ); $this->notifications = new Notifications( $addressHandler, \OC::$server->getHTTPClientService(), - $discoveryManager, + \OC::$server->query(\OCP\OCS\IDiscoveryService::class), \OC::$server->getJobList() ); } @@ -108,7 +103,7 @@ class RetryJob extends Job { $try = (int)$argument['try'] + 1; $result = $this->notifications->sendUpdateToRemote($remote, $remoteId, $token, $action, $data, $try); - + if ($result === true || $try > $this->maxTry) { $this->retainJob = false; } diff --git a/apps/federatedfilesharing/lib/Controller/MountPublicLinkController.php b/apps/federatedfilesharing/lib/Controller/MountPublicLinkController.php index dd2e88d2dae..d7e466d1a64 100644 --- a/apps/federatedfilesharing/lib/Controller/MountPublicLinkController.php +++ b/apps/federatedfilesharing/lib/Controller/MountPublicLinkController.php @@ -248,17 +248,13 @@ class MountPublicLinkController extends Controller { if (Helper::isSameUserOnSameServer($owner, $remote, $currentUser, $currentServer)) { return new JSONResponse(['message' => $this->l->t('Not allowed to create a federated share with the owner.')], Http::STATUS_BAD_REQUEST); } - $discoveryManager = new DiscoveryManager( - \OC::$server->getMemCacheFactory(), - \OC::$server->getHTTPClientService() - ); $externalManager = new Manager( \OC::$server->getDatabaseConnection(), Filesystem::getMountManager(), Filesystem::getLoader(), \OC::$server->getHTTPClientService(), \OC::$server->getNotificationManager(), - $discoveryManager, + \OC::$server->query(\OCP\OCS\IDiscoveryService::class), \OC::$server->getUserSession()->getUser()->getUID() ); diff --git a/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php b/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php index a41481afd2a..2b643810fb4 100644 --- a/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php +++ b/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php @@ -152,19 +152,15 @@ class RequestHandlerController extends OCSController { \OC_Util::setupFS($shareWith); - $discoveryManager = new DiscoveryManager( - \OC::$server->getMemCacheFactory(), - \OC::$server->getHTTPClientService() - ); $externalManager = new \OCA\Files_Sharing\External\Manager( - \OC::$server->getDatabaseConnection(), - \OC\Files\Filesystem::getMountManager(), - \OC\Files\Filesystem::getLoader(), - \OC::$server->getHTTPClientService(), - \OC::$server->getNotificationManager(), - $discoveryManager, - $shareWith - ); + \OC::$server->getDatabaseConnection(), + \OC\Files\Filesystem::getMountManager(), + \OC\Files\Filesystem::getLoader(), + \OC::$server->getHTTPClientService(), + \OC::$server->getNotificationManager(), + \OC::$server->query(\OCP\OCS\IDiscoveryService::class), + $shareWith + ); try { $externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId); diff --git a/apps/federatedfilesharing/lib/DiscoveryManager.php b/apps/federatedfilesharing/lib/DiscoveryManager.php deleted file mode 100644 index 8c8c72dbd66..00000000000 --- a/apps/federatedfilesharing/lib/DiscoveryManager.php +++ /dev/null @@ -1,143 +0,0 @@ -<?php -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bjoern Schiessle <bjoern@schiessle.org> - * @author Joas Schilling <coding@schilljs.com> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OCA\FederatedFileSharing; - -use GuzzleHttp\Exception\ClientException; -use GuzzleHttp\Exception\ConnectException; -use OCP\Http\Client\IClient; -use OCP\Http\Client\IClientService; -use OCP\ICache; -use OCP\ICacheFactory; - -/** - * Class DiscoveryManager handles the discovery of endpoints used by Federated - * Cloud Sharing. - * - * @package OCA\FederatedFileSharing - */ -class DiscoveryManager { - /** @var ICache */ - private $cache; - /** @var IClient */ - private $client; - - /** - * @param ICacheFactory $cacheFactory - * @param IClientService $clientService - */ - public function __construct(ICacheFactory $cacheFactory, - IClientService $clientService) { - $this->cache = $cacheFactory->create('ocs-discovery'); - $this->client = $clientService->newClient(); - } - - /** - * Returns whether the specified URL includes only safe characters, if not - * returns false - * - * @param string $url - * @return bool - */ - private function isSafeUrl($url) { - return (bool)preg_match('/^[\/\.A-Za-z0-9]+$/', $url); - } - - /** - * Discover the actual data and do some naive caching to ensure that the data - * is not requested multiple times. - * - * If no valid discovery data is found the Nextcloud defaults are returned. - * - * @param string $remote - * @return array - */ - private function discover($remote) { - // Check if something is in the cache - if($cacheData = $this->cache->get($remote)) { - return json_decode($cacheData, true); - } - - // Default response body - $discoveredServices = [ - 'webdav' => '/public.php/webdav', - 'share' => '/ocs/v1.php/cloud/shares', - ]; - - // Read the data from the response body - try { - $response = $this->client->get($remote . '/ocs-provider/', [ - 'timeout' => 10, - 'connect_timeout' => 10, - ]); - if($response->getStatusCode() === 200) { - $decodedService = json_decode($response->getBody(), true); - if(is_array($decodedService)) { - $endpoints = [ - 'webdav', - 'share', - ]; - - foreach($endpoints as $endpoint) { - if(isset($decodedService['services']['FEDERATED_SHARING']['endpoints'][$endpoint])) { - $endpointUrl = (string)$decodedService['services']['FEDERATED_SHARING']['endpoints'][$endpoint]; - if($this->isSafeUrl($endpointUrl)) { - $discoveredServices[$endpoint] = $endpointUrl; - } - } - } - } - } - } catch (ClientException $e) { - // Don't throw any exception since exceptions are handled before - } catch (ConnectException $e) { - // Don't throw any exception since exceptions are handled before - } - - // Write into cache - $this->cache->set($remote, json_encode($discoveredServices)); - return $discoveredServices; - } - - /** - * Return the public WebDAV endpoint used by the specified remote - * - * @param string $host - * @return string - */ - public function getWebDavEndpoint($host) { - return $this->discover($host)['webdav']; - } - - /** - * Return the sharing endpoint used by the specified remote - * - * @param string $host - * @return string - */ - public function getShareEndpoint($host) { - return $this->discover($host)['share']; - } -} diff --git a/apps/federatedfilesharing/lib/Notifications.php b/apps/federatedfilesharing/lib/Notifications.php index 8110b4915da..5abac711985 100644 --- a/apps/federatedfilesharing/lib/Notifications.php +++ b/apps/federatedfilesharing/lib/Notifications.php @@ -30,6 +30,7 @@ namespace OCA\FederatedFileSharing; use OCP\AppFramework\Http; use OCP\BackgroundJob\IJobList; use OCP\Http\Client\IClientService; +use OCP\OCS\IDiscoveryService; class Notifications { const RESPONSE_FORMAT = 'json'; // default response format for ocs calls @@ -40,8 +41,8 @@ class Notifications { /** @var IClientService */ private $httpClientService; - /** @var DiscoveryManager */ - private $discoveryManager; + /** @var IDiscoveryService */ + private $discoveryService; /** @var IJobList */ private $jobList; @@ -49,18 +50,18 @@ class Notifications { /** * @param AddressHandler $addressHandler * @param IClientService $httpClientService - * @param DiscoveryManager $discoveryManager + * @param IDiscoveryService $discoveryService * @param IJobList $jobList */ public function __construct( AddressHandler $addressHandler, IClientService $httpClientService, - DiscoveryManager $discoveryManager, + IDiscoveryService $discoveryService, IJobList $jobList ) { $this->addressHandler = $addressHandler; $this->httpClientService = $httpClientService; - $this->discoveryManager = $discoveryManager; + $this->discoveryService = $discoveryService; $this->jobList = $jobList; } @@ -287,7 +288,8 @@ class Notifications { 'result' => '', ]; - $endpoint = $this->discoveryManager->getShareEndpoint($remoteDomain); + $federationEndpoints = $this->discoveryService->discover($remoteDomain, 'FEDERATED_SHARING'); + $endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares'; try { $response = $client->post($remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT, [ 'body' => $fields, diff --git a/apps/federatedfilesharing/tests/Controller/RequestHandlerControllerTest.php b/apps/federatedfilesharing/tests/Controller/RequestHandlerControllerTest.php index 233395dec9f..512000181c1 100644 --- a/apps/federatedfilesharing/tests/Controller/RequestHandlerControllerTest.php +++ b/apps/federatedfilesharing/tests/Controller/RequestHandlerControllerTest.php @@ -270,17 +270,13 @@ class RequestHandlerControllerTest extends TestCase { ->method('newClient') ->willReturn($client); - $discoveryManager = new DiscoveryManager( - \OC::$server->getMemCacheFactory(), - $httpClientService - ); $manager = new \OCA\Files_Sharing\External\Manager( \OC::$server->getDatabaseConnection(), Filesystem::getMountManager(), Filesystem::getLoader(), $httpClientService, \OC::$server->getNotificationManager(), - $discoveryManager, + \OC::$server->query(\OCP\OCS\IDiscoveryService::class), $toDelete ); diff --git a/apps/federatedfilesharing/tests/DiscoveryManagerTest.php b/apps/federatedfilesharing/tests/DiscoveryManagerTest.php deleted file mode 100644 index 77e24aad54b..00000000000 --- a/apps/federatedfilesharing/tests/DiscoveryManagerTest.php +++ /dev/null @@ -1,217 +0,0 @@ -<?php -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Björn Schießle <bjoern@schiessle.org> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OCA\FederatedFileSharing\Tests; - -use OCA\FederatedFileSharing\DiscoveryManager; -use OCP\Http\Client\IClient; -use OCP\Http\Client\IClientService; -use OCP\ICache; -use OCP\ICacheFactory; - -class DiscoveryManagerTest extends \Test\TestCase { - /** @var ICache */ - private $cache; - /** @var IClient */ - private $client; - /** @var DiscoveryManager */ - private $discoveryManager; - - public function setUp() { - parent::setUp(); - $this->cache = $this->getMockBuilder('\OCP\ICache') - ->getMock(); - /** @var ICacheFactory $cacheFactory */ - $cacheFactory = $this->getMockBuilder('\OCP\ICacheFactory') - ->disableOriginalConstructor()->getMock(); - $cacheFactory - ->expects($this->once()) - ->method('create') - ->with('ocs-discovery') - ->willReturn($this->cache); - - $this->client = $this->getMockBuilder('\OCP\Http\Client\IClient') - ->disableOriginalConstructor()->getMock(); - /** @var IClientService $clientService */ - $clientService = $this->getMockBuilder('\OCP\Http\Client\IClientService') - ->disableOriginalConstructor()->getMock(); - $clientService - ->expects($this->once()) - ->method('newClient') - ->willReturn($this->client); - - $this->discoveryManager = new DiscoveryManager( - $cacheFactory, - $clientService - ); - } - - public function testWithMalformedFormattedEndpointCached() { - $response = $this->getMockBuilder('\OCP\Http\Client\IResponse') - ->getMock(); - $response - ->expects($this->once()) - ->method('getStatusCode') - ->willReturn(200); - $response - ->expects($this->once()) - ->method('getBody') - ->willReturn('CertainlyNotJson'); - $this->client - ->expects($this->once()) - ->method('get') - ->with('https://myhost.com/ocs-provider/', [ - 'timeout' => 10, - 'connect_timeout' => 10, - ]) - ->willReturn($response); - $this->cache - ->expects($this->at(0)) - ->method('get') - ->with('https://myhost.com') - ->willReturn(null); - $this->cache - ->expects($this->at(1)) - ->method('set') - ->with('https://myhost.com', '{"webdav":"\/public.php\/webdav","share":"\/ocs\/v1.php\/cloud\/shares"}'); - $this->cache - ->expects($this->at(2)) - ->method('get') - ->with('https://myhost.com') - ->willReturn('{"webdav":"\/public.php\/webdav","share":"\/ocs\/v1.php\/cloud\/shares"}'); - - $this->assertSame('/public.php/webdav', $this->discoveryManager->getWebDavEndpoint('https://myhost.com')); - $this->assertSame('/ocs/v1.php/cloud/shares', $this->discoveryManager->getShareEndpoint('https://myhost.com')); - } - - public function testGetWebDavEndpointWithValidFormattedEndpointAndNotCached() { - $response = $this->getMockBuilder('\OCP\Http\Client\IResponse') - ->getMock(); - $response - ->expects($this->once()) - ->method('getStatusCode') - ->willReturn(200); - $response - ->expects($this->once()) - ->method('getBody') - ->willReturn('{"version":2,"services":{"PRIVATE_DATA":{"version":1,"endpoints":{"store":"\/ocs\/v2.php\/privatedata\/setattribute","read":"\/ocs\/v2.php\/privatedata\/getattribute","delete":"\/ocs\/v2.php\/privatedata\/deleteattribute"}},"SHARING":{"version":1,"endpoints":{"share":"\/ocs\/v2.php\/apps\/files_sharing\/api\/v1\/shares"}},"FEDERATED_SHARING":{"version":1,"endpoints":{"share":"\/ocs\/v2.php\/cloud\/shares","webdav":"\/public.php\/MyCustomEndpoint\/"}},"ACTIVITY":{"version":1,"endpoints":{"list":"\/ocs\/v2.php\/cloud\/activity"}},"PROVISIONING":{"version":1,"endpoints":{"user":"\/ocs\/v2.php\/cloud\/users","groups":"\/ocs\/v2.php\/cloud\/groups","apps":"\/ocs\/v2.php\/cloud\/apps"}}}}'); - $this->client - ->expects($this->once()) - ->method('get') - ->with('https://myhost.com/ocs-provider/', [ - 'timeout' => 10, - 'connect_timeout' => 10, - ]) - ->willReturn($response); - - $expectedResult = '/public.php/MyCustomEndpoint/'; - $this->assertSame($expectedResult, $this->discoveryManager->getWebDavEndpoint('https://myhost.com')); - } - - public function testGetWebDavEndpointWithValidFormattedEndpointWithoutDataAndNotCached() { - $response = $this->getMockBuilder('\OCP\Http\Client\IResponse') - ->getMock(); - $response - ->expects($this->once()) - ->method('getStatusCode') - ->willReturn(200); - $response - ->expects($this->once()) - ->method('getBody') - ->willReturn('{"version":2,"PRIVATE_DATA":{"version":1,"endpoints":{"store":"\/ocs\/v2.php\/privatedata\/setattribute","read":"\/ocs\/v2.php\/privatedata\/getattribute","delete":"\/ocs\/v2.php\/privatedata\/deleteattribute"}},"SHARING":{"version":1,"endpoints":{"share":"\/ocs\/v2.php\/apps\/files_sharing\/api\/v1\/shares"}},"FEDERATED_SHARING":{"version":1,"endpoints":{"share":"\/ocs\/v2.php\/cloud\/shares","webdav":"\/public.php\/MyCustomEndpoint\/"}},"ACTIVITY":{"version":1,"endpoints":{"list":"\/ocs\/v2.php\/cloud\/activity"}},"PROVISIONING":{"version":1,"endpoints":{"user":"\/ocs\/v2.php\/cloud\/users","groups":"\/ocs\/v2.php\/cloud\/groups","apps":"\/ocs\/v2.php\/cloud\/apps"}}}'); - $this->client - ->expects($this->once()) - ->method('get') - ->with('https://myhost.com/ocs-provider/', [ - 'timeout' => 10, - 'connect_timeout' => 10, - ]) - ->willReturn($response); - - $expectedResult = '/public.php/webdav'; - $this->assertSame($expectedResult, $this->discoveryManager->getWebDavEndpoint('https://myhost.com')); - } - - public function testGetShareEndpointWithValidFormattedEndpointAndNotCached() { - $response = $this->getMockBuilder('\OCP\Http\Client\IResponse') - ->getMock(); - $response - ->expects($this->once()) - ->method('getStatusCode') - ->willReturn(200); - $response - ->expects($this->once()) - ->method('getBody') - ->willReturn('{"version":2,"services":{"PRIVATE_DATA":{"version":1,"endpoints":{"store":"\/ocs\/v2.php\/privatedata\/setattribute","read":"\/ocs\/v2.php\/privatedata\/getattribute","delete":"\/ocs\/v2.php\/privatedata\/deleteattribute"}},"SHARING":{"version":1,"endpoints":{"share":"\/ocs\/v2.php\/apps\/files_sharing\/api\/v1\/shares"}},"FEDERATED_SHARING":{"version":1,"endpoints":{"share":"\/ocs\/v2.php\/cloud\/MyCustomShareEndpoint","webdav":"\/public.php\/MyCustomEndpoint\/"}},"ACTIVITY":{"version":1,"endpoints":{"list":"\/ocs\/v2.php\/cloud\/activity"}},"PROVISIONING":{"version":1,"endpoints":{"user":"\/ocs\/v2.php\/cloud\/users","groups":"\/ocs\/v2.php\/cloud\/groups","apps":"\/ocs\/v2.php\/cloud\/apps"}}}}'); - $this->client - ->expects($this->once()) - ->method('get') - ->with('https://myhost.com/ocs-provider/', [ - 'timeout' => 10, - 'connect_timeout' => 10, - ]) - ->willReturn($response); - - $expectedResult = '/ocs/v2.php/cloud/MyCustomShareEndpoint'; - $this->assertSame($expectedResult, $this->discoveryManager->getShareEndpoint('https://myhost.com')); - } - - public function testWithMaliciousEndpointCached() { - $response = $this->getMockBuilder('\OCP\Http\Client\IResponse') - ->getMock(); - $response - ->expects($this->once()) - ->method('getStatusCode') - ->willReturn(200); - $response - ->expects($this->once()) - ->method('getBody') - ->willReturn('{"version":2,"services":{"PRIVATE_DATA":{"version":1,"endpoints":{"store":"\/ocs\/v2.php\/privatedata\/setattribute","read":"\/ocs\/v2.php\/privatedata\/getattribute","delete":"\/ocs\/v2.php\/privatedata\/deleteattribute"}},"SHARING":{"version":1,"endpoints":{"share":"\/ocs\/v2.php\/apps\/files_sharing\/api\/v1\/shares"}},"FEDERATED_SHARING":{"version":1,"endpoints":{"share":"\/ocs\/v2.php\/cl@oud\/MyCustomShareEndpoint","webdav":"\/public.php\/MyC:ustomEndpoint\/"}},"ACTIVITY":{"version":1,"endpoints":{"list":"\/ocs\/v2.php\/cloud\/activity"}},"PROVISIONING":{"version":1,"endpoints":{"user":"\/ocs\/v2.php\/cloud\/users","groups":"\/ocs\/v2.php\/cloud\/groups","apps":"\/ocs\/v2.php\/cloud\/apps"}}}}'); - $this->client - ->expects($this->once()) - ->method('get') - ->with('https://myhost.com/ocs-provider/', [ - 'timeout' => 10, - 'connect_timeout' => 10, - ]) - ->willReturn($response); - $this->cache - ->expects($this->at(0)) - ->method('get') - ->with('https://myhost.com') - ->willReturn(null); - $this->cache - ->expects($this->at(1)) - ->method('set') - ->with('https://myhost.com', '{"webdav":"\/public.php\/webdav","share":"\/ocs\/v1.php\/cloud\/shares"}'); - $this->cache - ->expects($this->at(2)) - ->method('get') - ->with('https://myhost.com') - ->willReturn('{"webdav":"\/public.php\/webdav","share":"\/ocs\/v1.php\/cloud\/shares"}'); - - $this->assertSame('/public.php/webdav', $this->discoveryManager->getWebDavEndpoint('https://myhost.com')); - $this->assertSame('/ocs/v1.php/cloud/shares', $this->discoveryManager->getShareEndpoint('https://myhost.com')); - } -} diff --git a/apps/federatedfilesharing/tests/NotificationsTest.php b/apps/federatedfilesharing/tests/NotificationsTest.php index a5f5c6bc078..4f70d5f3950 100644 --- a/apps/federatedfilesharing/tests/NotificationsTest.php +++ b/apps/federatedfilesharing/tests/NotificationsTest.php @@ -25,10 +25,10 @@ namespace OCA\FederatedFileSharing\Tests; use OCA\FederatedFileSharing\AddressHandler; -use OCA\FederatedFileSharing\DiscoveryManager; use OCA\FederatedFileSharing\Notifications; use OCP\BackgroundJob\IJobList; use OCP\Http\Client\IClientService; +use OCP\OCS\IDiscoveryService; class NotificationsTest extends \Test\TestCase { @@ -38,8 +38,8 @@ class NotificationsTest extends \Test\TestCase { /** @var IClientService | \PHPUnit_Framework_MockObject_MockObject*/ private $httpClientService; - /** @var DiscoveryManager | \PHPUnit_Framework_MockObject_MockObject */ - private $discoveryManager; + /** @var IDiscoveryService | \PHPUnit_Framework_MockObject_MockObject */ + private $discoveryService; /** @var IJobList | \PHPUnit_Framework_MockObject_MockObject */ private $jobList; @@ -48,8 +48,7 @@ class NotificationsTest extends \Test\TestCase { parent::setUp(); $this->jobList = $this->getMockBuilder('OCP\BackgroundJob\IJobList')->getMock(); - $this->discoveryManager = $this->getMockBuilder('OCA\FederatedFileSharing\DiscoveryManager') - ->disableOriginalConstructor()->getMock(); + $this->discoveryService = $this->getMockBuilder(IDiscoveryService::class)->getMock(); $this->httpClientService = $this->getMockBuilder('OCP\Http\Client\IClientService')->getMock(); $this->addressHandler = $this->getMockBuilder('OCA\FederatedFileSharing\AddressHandler') ->disableOriginalConstructor()->getMock(); @@ -67,7 +66,7 @@ class NotificationsTest extends \Test\TestCase { $instance = new Notifications( $this->addressHandler, $this->httpClientService, - $this->discoveryManager, + $this->discoveryService, $this->jobList ); } else { @@ -76,7 +75,7 @@ class NotificationsTest extends \Test\TestCase { [ $this->addressHandler, $this->httpClientService, - $this->discoveryManager, + $this->discoveryService, $this->jobList ] )->setMethods($mockedMethods)->getMock(); diff --git a/apps/federation/appinfo/routes.php b/apps/federation/appinfo/routes.php index 4c742dd705c..01c37eab584 100644 --- a/apps/federation/appinfo/routes.php +++ b/apps/federation/appinfo/routes.php @@ -45,12 +45,12 @@ $application->registerRoutes( 'ocs' => [ // old endpoints, only used by Nextcloud and ownCloud [ - 'name' => 'OCSAuthAPI#getSharedSecret', + 'name' => 'OCSAuthAPI#getSharedSecretLegacy', 'url' => '/api/v1/shared-secret', 'verb' => 'GET', ], [ - 'name' => 'OCSAuthAPI#requestSharedSecret', + 'name' => 'OCSAuthAPI#requestSharedSecretLegacy', 'url' => '/api/v1/request-shared-secret', 'verb' => 'POST', ], diff --git a/apps/federation/lib/AppInfo/Application.php b/apps/federation/lib/AppInfo/Application.php index e5acab52857..3166316b108 100644 --- a/apps/federation/lib/AppInfo/Application.php +++ b/apps/federation/lib/AppInfo/Application.php @@ -135,7 +135,8 @@ class Application extends \OCP\AppFramework\App { public function getSyncService() { $syncService = \OC::$server->query('CardDAVSyncService'); $dbHandler = $this->getContainer()->query('DbHandler'); - return new SyncFederationAddressBooks($dbHandler, $syncService); + $discoveryService = \OC::$server->query(\OCP\OCS\IDiscoveryService::class); + return new SyncFederationAddressBooks($dbHandler, $syncService, $discoveryService); } } diff --git a/apps/federation/lib/BackgroundJob/GetSharedSecret.php b/apps/federation/lib/BackgroundJob/GetSharedSecret.php index c0a4b43db64..4a6e720ae2c 100644 --- a/apps/federation/lib/BackgroundJob/GetSharedSecret.php +++ b/apps/federation/lib/BackgroundJob/GetSharedSecret.php @@ -37,6 +37,7 @@ use OCP\Http\Client\IClient; use OCP\Http\Client\IResponse; use OCP\ILogger; use OCP\IURLGenerator; +use OCP\OCS\IDiscoveryService; /** * Class GetSharedSecret @@ -62,13 +63,18 @@ class GetSharedSecret extends Job{ /** @var DbHandler */ private $dbHandler; + /** @var IDiscoveryService */ + private $ocsDiscoveryService; + /** @var ILogger */ private $logger; /** @var bool */ protected $retainJob = false; - private $endPoint = '/ocs/v2.php/apps/federation/api/v1/shared-secret?format=json'; + private $format = '?format=json'; + + private $defaultEndPoint = '/ocs/v2.php/apps/federation/api/v1/shared-secret'; /** * RequestSharedSecret constructor. @@ -79,6 +85,7 @@ class GetSharedSecret extends Job{ * @param TrustedServers $trustedServers * @param ILogger $logger * @param DbHandler $dbHandler + * @param IDiscoveryService $ocsDiscoveryService */ public function __construct( IClient $httpClient = null, @@ -86,13 +93,15 @@ class GetSharedSecret extends Job{ IJobList $jobList = null, TrustedServers $trustedServers = null, ILogger $logger = null, - DbHandler $dbHandler = null + DbHandler $dbHandler = null, + IDiscoveryService $ocsDiscoveryService = null ) { $this->logger = $logger ? $logger : \OC::$server->getLogger(); $this->httpClient = $httpClient ? $httpClient : \OC::$server->getHTTPClientService()->newClient(); $this->jobList = $jobList ? $jobList : \OC::$server->getJobList(); $this->urlGenerator = $urlGenerator ? $urlGenerator : \OC::$server->getURLGenerator(); $this->dbHandler = $dbHandler ? $dbHandler : new DbHandler(\OC::$server->getDatabaseConnection(), \OC::$server->getL10N('federation')); + $this->ocsDiscoveryService = $ocsDiscoveryService ? $ocsDiscoveryService : \OC::$server->query(\OCP\OCS\IDiscoveryService::class); if ($trustedServers) { $this->trustedServers = $trustedServers; } else { @@ -142,10 +151,16 @@ class GetSharedSecret extends Job{ $source = rtrim($source, '/'); $token = $argument['token']; + $endPoints = $this->ocsDiscoveryService->discover($target, 'FEDERATED_SHARING'); + $endPoint = isset($endPoints['shared-secret']) ? $endPoints['shared-secret'] : $this->defaultEndPoint; + + // make sure that we have a well formated url + $url = rtrim($target, '/') . '/' . trim($endPoint, '/') . $this->format; + $result = null; try { $result = $this->httpClient->get( - $target . $this->endPoint, + $url, [ 'query' => [ diff --git a/apps/federation/lib/BackgroundJob/RequestSharedSecret.php b/apps/federation/lib/BackgroundJob/RequestSharedSecret.php index 352995572c9..60b22cd6283 100644 --- a/apps/federation/lib/BackgroundJob/RequestSharedSecret.php +++ b/apps/federation/lib/BackgroundJob/RequestSharedSecret.php @@ -37,6 +37,7 @@ use OCP\BackgroundJob\IJobList; use OCP\Http\Client\IClient; use OCP\ILogger; use OCP\IURLGenerator; +use OCP\OCS\IDiscoveryService; /** * Class RequestSharedSecret @@ -62,7 +63,8 @@ class RequestSharedSecret extends Job { /** @var TrustedServers */ private $trustedServers; - private $endPoint = '/ocs/v2.php/apps/federation/api/v1/request-shared-secret?format=json'; + /** @var IDiscoveryService */ + private $ocsDiscoveryService; /** @var ILogger */ private $logger; @@ -70,6 +72,10 @@ class RequestSharedSecret extends Job { /** @var bool */ protected $retainJob = false; + private $format = '?format=json'; + + private $defaultEndPoint = '/ocs/v2.php/apps/federation/api/v1/request-shared-secret'; + /** * RequestSharedSecret constructor. * @@ -78,19 +84,22 @@ class RequestSharedSecret extends Job { * @param IJobList $jobList * @param TrustedServers $trustedServers * @param DbHandler $dbHandler + * @param IDiscoveryService $ocsDiscoveryService */ public function __construct( IClient $httpClient = null, IURLGenerator $urlGenerator = null, IJobList $jobList = null, TrustedServers $trustedServers = null, - DbHandler $dbHandler = null + DbHandler $dbHandler = null, + IDiscoveryService $ocsDiscoveryService = null ) { $this->httpClient = $httpClient ? $httpClient : \OC::$server->getHTTPClientService()->newClient(); $this->jobList = $jobList ? $jobList : \OC::$server->getJobList(); $this->urlGenerator = $urlGenerator ? $urlGenerator : \OC::$server->getURLGenerator(); $this->dbHandler = $dbHandler ? $dbHandler : new DbHandler(\OC::$server->getDatabaseConnection(), \OC::$server->getL10N('federation')); $this->logger = \OC::$server->getLogger(); + $this->ocsDiscoveryService = $ocsDiscoveryService ? $ocsDiscoveryService : \OC::$server->query(\OCP\OCS\IDiscoveryService::class); if ($trustedServers) { $this->trustedServers = $trustedServers; } else { @@ -142,9 +151,15 @@ class RequestSharedSecret extends Job { $source = rtrim($source, '/'); $token = $argument['token']; + $endPoints = $this->ocsDiscoveryService->discover($target, 'FEDERATED_SHARING'); + $endPoint = isset($endPoints['shared-secret']) ? $endPoints['shared-secret'] : $this->defaultEndPoint; + + // make sure that we have a well formated url + $url = rtrim($target, '/') . '/' . trim($endPoint, '/') . $this->format; + try { $result = $this->httpClient->post( - $target . $this->endPoint, + $url, [ 'body' => [ 'url' => $source, diff --git a/apps/federation/lib/Controller/OCSAuthAPIController.php b/apps/federation/lib/Controller/OCSAuthAPIController.php index fdca601da63..594299a2d02 100644 --- a/apps/federation/lib/Controller/OCSAuthAPIController.php +++ b/apps/federation/lib/Controller/OCSAuthAPIController.php @@ -94,6 +94,37 @@ class OCSAuthAPIController extends OCSController{ * @NoCSRFRequired * @PublicPage * + * request received to ask remote server for a shared secret, for legacy end-points + * + * @param string $url + * @param string $token + * @return Http\DataResponse + * @throws OCSForbiddenException + */ + public function requestSharedSecretLegacy($url, $token) { + return $this->requestSharedSecret($url, $token); + } + + + /** + * @NoCSRFRequired + * @PublicPage + * + * create shared secret and return it, for legacy end-points + * + * @param string $url + * @param string $token + * @return Http\DataResponse + * @throws OCSForbiddenException + */ + public function getSharedSecretLegacy($url, $token) { + return $this->getSharedSecret($url, $token); + } + + /** + * @NoCSRFRequired + * @PublicPage + * * request received to ask remote server for a shared secret * * @param string $url diff --git a/apps/federation/lib/SyncFederationAddressBooks.php b/apps/federation/lib/SyncFederationAddressBooks.php index 759b59183aa..87419a5ba54 100644 --- a/apps/federation/lib/SyncFederationAddressBooks.php +++ b/apps/federation/lib/SyncFederationAddressBooks.php @@ -23,12 +23,10 @@ */ namespace OCA\Federation; +use OC\OCS\DiscoveryService; use OCA\DAV\CardDAV\SyncService; use OCP\AppFramework\Http; -use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Helper\ProgressBar; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; +use OCP\OCS\IDiscoveryService; class SyncFederationAddressBooks { @@ -38,13 +36,21 @@ class SyncFederationAddressBooks { /** @var SyncService */ private $syncService; + /** @var DiscoveryService */ + private $ocsDiscoveryService; + /** * @param DbHandler $dbHandler * @param SyncService $syncService + * @param IDiscoveryService $ocsDiscoveryService */ - function __construct(DbHandler $dbHandler, SyncService $syncService) { + public function __construct(DbHandler $dbHandler, + SyncService $syncService, + IDiscoveryService $ocsDiscoveryService + ) { $this->syncService = $syncService; $this->dbHandler = $dbHandler; + $this->ocsDiscoveryService = $ocsDiscoveryService; } /** @@ -59,6 +65,10 @@ class SyncFederationAddressBooks { $sharedSecret = $trustedServer['shared_secret']; $syncToken = $trustedServer['sync_token']; + $endPoints = $this->ocsDiscoveryService->discover($url, 'FEDERATED_SHARING'); + $cardDavUser = isset($endPoints['carddav-user']) ? $endPoints['carddav-user'] : 'system'; + $addressBookUrl = isset($endPoints['system-address-book']) ? trim($endPoints['system-address-book'], '/') : 'remote.php/dav/addressbooks/system/system/system'; + if (is_null($sharedSecret)) { continue; } @@ -68,7 +78,7 @@ class SyncFederationAddressBooks { '{DAV:}displayname' => $url ]; try { - $newToken = $this->syncService->syncRemoteAddressBook($url, 'system', $sharedSecret, $syncToken, $targetBookId, $targetPrincipal, $targetBookProperties); + $newToken = $this->syncService->syncRemoteAddressBook($url, $cardDavUser, $addressBookUrl, $sharedSecret, $syncToken, $targetBookId, $targetPrincipal, $targetBookProperties); if ($newToken !== $syncToken) { $this->dbHandler->setServerStatus($url, TrustedServers::STATUS_OK, $newToken); } diff --git a/apps/federation/tests/BackgroundJob/GetSharedSecretTest.php b/apps/federation/tests/BackgroundJob/GetSharedSecretTest.php index fe7cc5cc337..6364ddaedff 100644 --- a/apps/federation/tests/BackgroundJob/GetSharedSecretTest.php +++ b/apps/federation/tests/BackgroundJob/GetSharedSecretTest.php @@ -36,6 +36,7 @@ use OCP\Http\Client\IClient; use OCP\Http\Client\IResponse; use OCP\ILogger; use OCP\IURLGenerator; +use OCP\OCS\IDiscoveryService; /** * Class GetSharedSecretTest @@ -67,6 +68,9 @@ class GetSharedSecretTest extends TestCase { /** @var \PHPUnit_Framework_MockObject_MockObject | IResponse */ private $response; + /** @var \PHPUnit_Framework_MockObject_MockObject | IDiscoveryService */ + private $discoverService; + /** @var GetSharedSecret */ private $getSharedSecret; @@ -82,6 +86,9 @@ class GetSharedSecretTest extends TestCase { ->disableOriginalConstructor()->getMock(); $this->logger = $this->getMockBuilder(ILogger::class)->getMock(); $this->response = $this->getMockBuilder(IResponse::class)->getMock(); + $this->discoverService = $this->getMockBuilder(IDiscoveryService::class)->getMock(); + + $this->discoverService->expects($this->any())->method('discover')->willReturn([]); $this->getSharedSecret = new GetSharedSecret( $this->httpClient, @@ -89,7 +96,8 @@ class GetSharedSecretTest extends TestCase { $this->jobList, $this->trustedServers, $this->logger, - $this->dbHandler + $this->dbHandler, + $this->discoverService ); } @@ -109,7 +117,8 @@ class GetSharedSecretTest extends TestCase { $this->jobList, $this->trustedServers, $this->logger, - $this->dbHandler + $this->dbHandler, + $this->discoverService ] )->setMethods(['parentExecute'])->getMock(); $this->invokePrivate($getSharedSecret, 'argument', [['url' => 'url']]); diff --git a/apps/federation/tests/BackgroundJob/RequestSharedSecretTest.php b/apps/federation/tests/BackgroundJob/RequestSharedSecretTest.php index 3fa2ca2973e..06da29d17fc 100644 --- a/apps/federation/tests/BackgroundJob/RequestSharedSecretTest.php +++ b/apps/federation/tests/BackgroundJob/RequestSharedSecretTest.php @@ -33,6 +33,7 @@ use OCP\BackgroundJob\IJobList; use OCP\Http\Client\IClient; use OCP\Http\Client\IResponse; use OCP\IURLGenerator; +use OCP\OCS\IDiscoveryService; use Test\TestCase; class RequestSharedSecretTest extends TestCase { @@ -55,6 +56,9 @@ class RequestSharedSecretTest extends TestCase { /** @var \PHPUnit_Framework_MockObject_MockObject | IResponse */ private $response; + /** @var \PHPUnit_Framework_MockObject_MockObject | IDiscoveryService */ + private $discoveryService; + /** @var RequestSharedSecret */ private $requestSharedSecret; @@ -69,13 +73,17 @@ class RequestSharedSecretTest extends TestCase { $this->dbHandler = $this->getMockBuilder(DbHandler::class) ->disableOriginalConstructor()->getMock(); $this->response = $this->getMockBuilder(IResponse::class)->getMock(); + $this->discoveryService = $this->getMockBuilder(IDiscoveryService::class)->getMock(); + + $this->discoveryService->expects($this->any())->method('discover')->willReturn([]); $this->requestSharedSecret = new RequestSharedSecret( $this->httpClient, $this->urlGenerator, $this->jobList, $this->trustedServers, - $this->dbHandler + $this->dbHandler, + $this->discoveryService ); } @@ -94,7 +102,8 @@ class RequestSharedSecretTest extends TestCase { $this->urlGenerator, $this->jobList, $this->trustedServers, - $this->dbHandler + $this->dbHandler, + $this->discoveryService ] )->setMethods(['parentExecute'])->getMock(); $this->invokePrivate($requestSharedSecret, 'argument', [['url' => 'url']]); diff --git a/apps/federation/tests/SyncFederationAddressbooksTest.php b/apps/federation/tests/SyncFederationAddressbooksTest.php index 1a2dbf1bcae..9ce5efeb457 100644 --- a/apps/federation/tests/SyncFederationAddressbooksTest.php +++ b/apps/federation/tests/SyncFederationAddressbooksTest.php @@ -24,6 +24,7 @@ */ namespace OCA\Federation\Tests; +use OC\OCS\DiscoveryService; use OCA\Federation\DbHandler; use OCA\Federation\SyncFederationAddressBooks; @@ -32,7 +33,18 @@ class SyncFederationAddressbooksTest extends \Test\TestCase { /** @var array */ private $callBacks = []; - function testSync() { + /** @var \PHPUnit_Framework_MockObject_MockObject | DiscoveryService */ + private $discoveryService; + + public function setUp() { + parent::setUp(); + + $this->discoveryService = $this->getMockBuilder(DiscoveryService::class) + ->disableOriginalConstructor()->getMock(); + $this->discoveryService->expects($this->any())->method('discover')->willReturn([]); + } + + public function testSync() { /** @var DbHandler | \PHPUnit_Framework_MockObject_MockObject $dbHandler */ $dbHandler = $this->getMockBuilder('OCA\Federation\DbHandler')-> disableOriginalConstructor()-> @@ -55,14 +67,14 @@ class SyncFederationAddressbooksTest extends \Test\TestCase { ->willReturn(1); /** @var \OCA\DAV\CardDAV\SyncService $syncService */ - $s = new SyncFederationAddressBooks($dbHandler, $syncService); + $s = new SyncFederationAddressBooks($dbHandler, $syncService, $this->discoveryService); $s->syncThemAll(function($url, $ex) { $this->callBacks[] = [$url, $ex]; }); $this->assertEquals(1, count($this->callBacks)); } - function testException() { + public function testException() { /** @var DbHandler | \PHPUnit_Framework_MockObject_MockObject $dbHandler */ $dbHandler = $this->getMockBuilder('OCA\Federation\DbHandler')-> disableOriginalConstructor()-> @@ -83,7 +95,7 @@ class SyncFederationAddressbooksTest extends \Test\TestCase { ->willThrowException(new \Exception('something did not work out')); /** @var \OCA\DAV\CardDAV\SyncService $syncService */ - $s = new SyncFederationAddressBooks($dbHandler, $syncService); + $s = new SyncFederationAddressBooks($dbHandler, $syncService, $this->discoveryService); $s->syncThemAll(function($url, $ex) { $this->callBacks[] = [$url, $ex]; }); diff --git a/apps/files_sharing/lib/AppInfo/Application.php b/apps/files_sharing/lib/AppInfo/Application.php index f9540df3ff2..f502d905fe8 100644 --- a/apps/files_sharing/lib/AppInfo/Application.php +++ b/apps/files_sharing/lib/AppInfo/Application.php @@ -92,17 +92,13 @@ class Application extends App { $container->registerService('ExternalManager', function (SimpleContainer $c) use ($server) { $user = $server->getUserSession()->getUser(); $uid = $user ? $user->getUID() : null; - $discoveryManager = new DiscoveryManager( - \OC::$server->getMemCacheFactory(), - \OC::$server->getHTTPClientService() - ); return new \OCA\Files_Sharing\External\Manager( $server->getDatabaseConnection(), \OC\Files\Filesystem::getMountManager(), \OC\Files\Filesystem::getLoader(), $server->getHTTPClientService(), $server->getNotificationManager(), - $discoveryManager, + $server->query(\OCP\OCS\IDiscoveryService::class), $uid ); }); diff --git a/apps/files_sharing/lib/External/Manager.php b/apps/files_sharing/lib/External/Manager.php index 0a57324c32f..2c348907384 100644 --- a/apps/files_sharing/lib/External/Manager.php +++ b/apps/files_sharing/lib/External/Manager.php @@ -32,8 +32,11 @@ namespace OCA\Files_Sharing\External; use OC\Files\Filesystem; use OCA\FederatedFileSharing\DiscoveryManager; use OCP\Files; +use OCP\Files\Storage\IStorageFactory; use OCP\Http\Client\IClientService; +use OCP\IDBConnection; use OCP\Notification\IManager; +use OCP\OCS\IDiscoveryService; class Manager { const STORAGE = '\OCA\Files_Sharing\External\Storage'; @@ -44,7 +47,7 @@ class Manager { private $uid; /** - * @var \OCP\IDBConnection + * @var IDBConnection */ private $connection; @@ -54,7 +57,7 @@ class Manager { private $mountManager; /** - * @var \OCP\Files\Storage\IStorageFactory + * @var IStorageFactory */ private $storageLoader; @@ -67,24 +70,27 @@ class Manager { * @var IManager */ private $notificationManager; - /** @var DiscoveryManager */ - private $discoveryManager; /** - * @param \OCP\IDBConnection $connection + * @var IDiscoveryService + */ + private $discoveryService; + + /** + * @param IDBConnection $connection * @param \OC\Files\Mount\Manager $mountManager - * @param \OCP\Files\Storage\IStorageFactory $storageLoader + * @param IStorageFactory $storageLoader * @param IClientService $clientService * @param IManager $notificationManager - * @param DiscoveryManager $discoveryManager + * @param IDiscoveryService $discoveryService * @param string $uid */ - public function __construct(\OCP\IDBConnection $connection, + public function __construct(IDBConnection $connection, \OC\Files\Mount\Manager $mountManager, - \OCP\Files\Storage\IStorageFactory $storageLoader, + IStorageFactory $storageLoader, IClientService $clientService, IManager $notificationManager, - DiscoveryManager $discoveryManager, + IDiscoveryService $discoveryService, $uid) { $this->connection = $connection; $this->mountManager = $mountManager; @@ -92,7 +98,7 @@ class Manager { $this->clientService = $clientService; $this->uid = $uid; $this->notificationManager = $notificationManager; - $this->discoveryManager = $discoveryManager; + $this->discoveryService = $discoveryService; } /** @@ -260,7 +266,10 @@ class Manager { */ private function sendFeedbackToRemote($remote, $token, $remoteId, $feedback) { - $url = rtrim($remote, '/') . $this->discoveryManager->getShareEndpoint($remote) . '/' . $remoteId . '/' . $feedback . '?format=' . \OCP\Share::RESPONSE_FORMAT; + $federationEndpoints = $this->discoveryService->discover($remote, 'FEDERATED_SHARING'); + $endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares'; + + $url = rtrim($remote, '/') . $endpoint . '/' . $remoteId . '/' . $feedback . '?format=' . \OCP\Share::RESPONSE_FORMAT; $fields = array('token' => $token); $client = $this->clientService->newClient(); @@ -376,7 +385,7 @@ class Manager { /** * remove re-shares from share table and mapping in the federated_reshares table - * + * * @param $mountPointId */ protected function removeReShares($mountPointId) { diff --git a/apps/files_sharing/lib/External/Storage.php b/apps/files_sharing/lib/External/Storage.php index 319735dcaf5..b84ba5d96ab 100644 --- a/apps/files_sharing/lib/External/Storage.php +++ b/apps/files_sharing/lib/External/Storage.php @@ -51,8 +51,6 @@ class Storage extends DAV implements ISharedStorage { private $memcacheFactory; /** @var \OCP\Http\Client\IClientService */ private $httpClient; - /** @var \OCP\ICertificateManager */ - private $certificateManager; /** @var bool */ private $updateChecked = false; @@ -64,14 +62,11 @@ class Storage extends DAV implements ISharedStorage { public function __construct($options) { $this->memcacheFactory = \OC::$server->getMemCacheFactory(); $this->httpClient = $options['HttpClientService']; - $discoveryManager = new DiscoveryManager( - $this->memcacheFactory, - $this->httpClient - ); $this->manager = $options['manager']; - $this->certificateManager = $options['certificateManager']; $this->cloudId = $options['cloudId']; + $discoveryService = \OC::$server->query(\OCP\OCS\IDiscoveryService::class); + list($protocol, $remote) = explode('://', $this->cloudId->getRemote()); if (strpos($remote, '/')) { list($host, $root) = explode('/', $remote, 2); @@ -80,9 +75,12 @@ class Storage extends DAV implements ISharedStorage { $root = ''; } $secure = $protocol === 'https'; - $root = rtrim($root, '/') . $discoveryManager->getWebDavEndpoint($this->cloudId->getRemote()); + $federatedSharingEndpoints = $discoveryService->discover($this->cloudId->getRemote(), 'FEDERATED_SHARING'); + $webDavEndpoint = isset($federatedSharingEndpoints['webdav']) ? $federatedSharingEndpoints['webdav'] : '/public.php/webdav'; + $root = rtrim($root, '/') . $webDavEndpoint; $this->mountPoint = $options['mountpoint']; $this->token = $options['token']; + parent::__construct(array( 'secure' => $secure, 'host' => $host, @@ -350,7 +348,7 @@ class Storage extends DAV implements ISharedStorage { } return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_SHARE); } - + public function getPermissions($path) { $response = $this->propfind($path); if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) { diff --git a/apps/files_sharing/lib/Hooks.php b/apps/files_sharing/lib/Hooks.php index 2029e97d08b..821c3046595 100644 --- a/apps/files_sharing/lib/Hooks.php +++ b/apps/files_sharing/lib/Hooks.php @@ -32,17 +32,13 @@ use OCA\FederatedFileSharing\DiscoveryManager; class Hooks { public static function deleteUser($params) { - $discoveryManager = new DiscoveryManager( - \OC::$server->getMemCacheFactory(), - \OC::$server->getHTTPClientService() - ); $manager = new External\Manager( \OC::$server->getDatabaseConnection(), \OC\Files\Filesystem::getMountManager(), \OC\Files\Filesystem::getLoader(), \OC::$server->getHTTPClientService(), \OC::$server->getNotificationManager(), - $discoveryManager, + \OC::$server->query(\OCP\OCS\IDiscoveryService::class), $params['uid']); $manager->removeUserShares($params['uid']); diff --git a/apps/files_sharing/tests/External/ManagerTest.php b/apps/files_sharing/tests/External/ManagerTest.php index f2a55babcc7..9f60261c203 100644 --- a/apps/files_sharing/tests/External/ManagerTest.php +++ b/apps/files_sharing/tests/External/ManagerTest.php @@ -70,17 +70,14 @@ class ManagerTest extends TestCase { $this->mountManager = new \OC\Files\Mount\Manager(); $this->clientService = $this->getMockBuilder('\OCP\Http\Client\IClientService') ->disableOriginalConstructor()->getMock(); - $discoveryManager = new DiscoveryManager( - \OC::$server->getMemCacheFactory(), - \OC::$server->getHTTPClientService() - ); + $this->manager = new Manager( \OC::$server->getDatabaseConnection(), $this->mountManager, new StorageFactory(), $this->clientService, \OC::$server->getNotificationManager(), - $discoveryManager, + \OC::$server->query(\OCP\OCS\IDiscoveryService::class), $this->uid ); $this->testMountProvider = new MountProvider(\OC::$server->getDatabaseConnection(), function() { @@ -143,7 +140,7 @@ class ManagerTest extends TestCase { ->disableOriginalConstructor()->getMock(); $client->expects($this->once()) ->method('post') - ->with($this->stringStartsWith('http://localhost/ocs/v1.php/cloud/shares/' . $openShares[0]['remote_id']), $this->anything()) + ->with($this->stringStartsWith('http://localhost/ocs/v2.php/cloud/shares/' . $openShares[0]['remote_id']), $this->anything()) ->willReturn($response); // Accept the first share @@ -186,7 +183,7 @@ class ManagerTest extends TestCase { ->disableOriginalConstructor()->getMock(); $client->expects($this->once()) ->method('post') - ->with($this->stringStartsWith('http://localhost/ocs/v1.php/cloud/shares/' . $openShares[1]['remote_id'] . '/decline'), $this->anything()) + ->with($this->stringStartsWith('http://localhost/ocs/v2.php/cloud/shares/' . $openShares[1]['remote_id'] . '/decline'), $this->anything()) ->willReturn($response); // Decline the third share @@ -226,11 +223,11 @@ class ManagerTest extends TestCase { ->disableOriginalConstructor()->getMock(); $client1->expects($this->once()) ->method('post') - ->with($this->stringStartsWith('http://localhost/ocs/v1.php/cloud/shares/' . $openShares[0]['remote_id'] . '/decline'), $this->anything()) + ->with($this->stringStartsWith('http://localhost/ocs/v2.php/cloud/shares/' . $openShares[0]['remote_id'] . '/decline'), $this->anything()) ->willReturn($response); $client2->expects($this->once()) ->method('post') - ->with($this->stringStartsWith('http://localhost/ocs/v1.php/cloud/shares/' . $acceptedShares[0]['remote_id'] . '/decline'), $this->anything()) + ->with($this->stringStartsWith('http://localhost/ocs/v2.php/cloud/shares/' . $acceptedShares[0]['remote_id'] . '/decline'), $this->anything()) ->willReturn($response); $this->manager->removeUserShares($this->uid); diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index c80881262d7..ab6a3781147 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -220,6 +220,7 @@ return array( 'OCP\\Notification\\IManager' => $baseDir . '/lib/public/Notification/IManager.php', 'OCP\\Notification\\INotification' => $baseDir . '/lib/public/Notification/INotification.php', 'OCP\\Notification\\INotifier' => $baseDir . '/lib/public/Notification/INotifier.php', + 'OCP\\OCS\\IDiscoveryService' => $baseDir . '/lib/public/OCS/IDiscoveryService.php', 'OCP\\PreConditionNotMetException' => $baseDir . '/lib/public/PreConditionNotMetException.php', 'OCP\\Preview\\IProvider' => $baseDir . '/lib/public/Preview/IProvider.php', 'OCP\\Response' => $baseDir . '/lib/public/Response.php', @@ -662,6 +663,7 @@ return array( 'OC\\Notification\\Manager' => $baseDir . '/lib/private/Notification/Manager.php', 'OC\\Notification\\Notification' => $baseDir . '/lib/private/Notification/Notification.php', 'OC\\OCS\\CoreCapabilities' => $baseDir . '/lib/private/OCS/CoreCapabilities.php', + 'OC\\OCS\\DiscoveryService' => $baseDir . '/lib/private/OCS/DiscoveryService.php', 'OC\\OCS\\Exception' => $baseDir . '/lib/private/OCS/Exception.php', 'OC\\OCS\\PrivateData' => $baseDir . '/lib/private/OCS/PrivateData.php', 'OC\\OCS\\Provider' => $baseDir . '/lib/private/OCS/Provider.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 8955d2de6ce..1b2c9f84df8 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -250,6 +250,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OCP\\Notification\\IManager' => __DIR__ . '/../../..' . '/lib/public/Notification/IManager.php', 'OCP\\Notification\\INotification' => __DIR__ . '/../../..' . '/lib/public/Notification/INotification.php', 'OCP\\Notification\\INotifier' => __DIR__ . '/../../..' . '/lib/public/Notification/INotifier.php', + 'OCP\\OCS\\IDiscoveryService' => __DIR__ . '/../../..' . '/lib/public/OCS/IDiscoveryService.php', 'OCP\\PreConditionNotMetException' => __DIR__ . '/../../..' . '/lib/public/PreConditionNotMetException.php', 'OCP\\Preview\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Preview/IProvider.php', 'OCP\\Response' => __DIR__ . '/../../..' . '/lib/public/Response.php', @@ -692,6 +693,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Notification\\Manager' => __DIR__ . '/../../..' . '/lib/private/Notification/Manager.php', 'OC\\Notification\\Notification' => __DIR__ . '/../../..' . '/lib/private/Notification/Notification.php', 'OC\\OCS\\CoreCapabilities' => __DIR__ . '/../../..' . '/lib/private/OCS/CoreCapabilities.php', + 'OC\\OCS\\DiscoveryService' => __DIR__ . '/../../..' . '/lib/private/OCS/DiscoveryService.php', 'OC\\OCS\\Exception' => __DIR__ . '/../../..' . '/lib/private/OCS/Exception.php', 'OC\\OCS\\PrivateData' => __DIR__ . '/../../..' . '/lib/private/OCS/PrivateData.php', 'OC\\OCS\\Provider' => __DIR__ . '/../../..' . '/lib/private/OCS/Provider.php', diff --git a/lib/private/OCS/DiscoveryService.php b/lib/private/OCS/DiscoveryService.php new file mode 100644 index 00000000000..5534fb24ef5 --- /dev/null +++ b/lib/private/OCS/DiscoveryService.php @@ -0,0 +1,125 @@ +<?php +/** + * @copyright Copyright (c) 2017 Bjoern Schiessle <bjoern@schiessle.org> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + + +namespace OC\OCS; + +use OCP\AppFramework\Http; +use OCP\Http\Client\IClient; +use OCP\Http\Client\IClientService; +use OCP\ICache; +use OCP\ICacheFactory; +use OCP\OCS\IDiscoveryService; + +class DiscoveryService implements IDiscoveryService { + + /** @var ICache */ + private $cache; + + /** @var IClient */ + private $client; + + /** + * @param ICacheFactory $cacheFactory + * @param IClientService $clientService + */ + public function __construct(ICacheFactory $cacheFactory, + IClientService $clientService + ) { + $this->cache = $cacheFactory->create('ocs-discovery'); + $this->client = $clientService->newClient(); + } + + + /** + * Discover OCS end-points + * + * If no valid discovery data is found the defaults are returned + * + * @param string $remote + * @param string $service the service you want to discover + * @return array + */ + public function discover($remote, $service) { + // Check the cache first + $cacheData = $this->cache->get($remote . '#' . $service); + if($cacheData) { + return json_decode($cacheData, true); + } + + $discoveredServices = []; + + // query the remote server for available services + try { + $response = $this->client->get($remote . '/ocs-provider/', [ + 'timeout' => 10, + 'connect_timeout' => 10, + ]); + if($response->getStatusCode() === Http::STATUS_OK) { + $decodedServices = json_decode($response->getBody(), true); + $discoveredServices = $this->getEndpoints($decodedServices, $service); + } + } catch (\Exception $e) { + // if we couldn't discover the service or any end-points we return a empty array + return []; + } + + // Write into cache + $this->cache->set($remote . '#' . $service, json_encode($discoveredServices)); + return $discoveredServices; + } + + /** + * get requested end-points from the requested service + * + * @param $decodedServices + * @param $service + * @return array + */ + protected function getEndpoints($decodedServices, $service) { + + $discoveredServices = []; + + if(is_array($decodedServices) && + isset($decodedServices['services'][$service]['endpoints']) + ) { + foreach ($decodedServices['services'][$service]['endpoints'] as $endpoint => $url) { + if($this->isSafeUrl($url)) { + $discoveredServices[$endpoint] = $url; + } + } + } + + return $discoveredServices; + } + + /** + * Returns whether the specified URL includes only safe characters, if not + * returns false + * + * @param string $url + * @return bool + */ + protected function isSafeUrl($url) { + return (bool)preg_match('/^[\/\.\-A-Za-z0-9]+$/', $url); + } + +} diff --git a/lib/private/Server.php b/lib/private/Server.php index 011263cd2d8..00698a04f89 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -77,6 +77,7 @@ use OC\Mail\Mailer; use OC\Memcache\ArrayCache; use OC\Memcache\Factory; use OC\Notification\Manager; +use OC\OCS\DiscoveryService; use OC\Repair\NC11\CleanPreviewsBackgroundJob; use OC\RichObjectStrings\Validator; use OC\Security\Bruteforce\Throttler; @@ -938,6 +939,10 @@ class Server extends ServerContainer implements IServerContainer { }); }); + $this->registerService(\OCP\OCS\IDiscoveryService::class, function (Server $c) { + return new DiscoveryService($c->getMemCacheFactory(), $c->getHTTPClientService()); + }); + $this->registerService(ICloudIdManager::class, function (Server $c) { return new CloudIdManager(); }); diff --git a/lib/private/Share/Share.php b/lib/private/Share/Share.php index 924e2f68396..b3e4cb2d4aa 100644 --- a/lib/private/Share/Share.php +++ b/lib/private/Share/Share.php @@ -2742,12 +2742,10 @@ class Share extends Constants { 'result' => '', ]; $try = 0; - $discoveryManager = new DiscoveryManager( - \OC::$server->getMemCacheFactory(), - \OC::$server->getHTTPClientService() - ); + $discoveryService = \OC::$server->query(\OCP\OCS\IDiscoveryService::class); while ($result['success'] === false && $try < 2) { - $endpoint = $discoveryManager->getShareEndpoint($protocol . $remoteDomain); + $federationEndpoints = $discoveryService->discover($protocol . $remoteDomain, 'FEDERATED_SHARING'); + $endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares'; $result = \OC::$server->getHTTPHelper()->post($protocol . $remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT, $fields); $try++; $protocol = 'http://'; diff --git a/lib/private/Share20/ProviderFactory.php b/lib/private/Share20/ProviderFactory.php index b411f42b262..ba6699ae7ad 100644 --- a/lib/private/Share20/ProviderFactory.php +++ b/lib/private/Share20/ProviderFactory.php @@ -104,14 +104,10 @@ class ProviderFactory implements IProviderFactory { $l, $this->serverContainer->getCloudIdManager() ); - $discoveryManager = new DiscoveryManager( - $this->serverContainer->getMemCacheFactory(), - $this->serverContainer->getHTTPClientService() - ); $notifications = new Notifications( $addressHandler, $this->serverContainer->getHTTPClientService(), - $discoveryManager, + $this->serverContainer->query(\OCP\OCS\IDiscoveryService::class), $this->serverContainer->getJobList() ); $tokenHandler = new TokenHandler( diff --git a/lib/public/OCS/IDiscoveryService.php b/lib/public/OCS/IDiscoveryService.php new file mode 100644 index 00000000000..eee5bf97f93 --- /dev/null +++ b/lib/public/OCS/IDiscoveryService.php @@ -0,0 +1,48 @@ +<?php +/** + * @copyright Copyright (c) 2017 Bjoern Schiessle <bjoern@schiessle.org> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + + +namespace OCP\OCS; + +/** + * Interface IDiscoveryService + * + * Allows you to discover OCS end-points on a remote server + * + * @package OCP\OCS + * @since 12.0.0 + */ +interface IDiscoveryService { + + /** + * Discover OCS end-points + * + * If no valid discovery data is found the defaults are returned + * + * @since 12.0.0 + * + * @param string $remote + * @param string $service the service you want to discover + * @return array + */ + public function discover($remote, $service); + +} diff --git a/tests/lib/OCS/DiscoveryServiceTest.php b/tests/lib/OCS/DiscoveryServiceTest.php new file mode 100644 index 00000000000..fdcdddb0813 --- /dev/null +++ b/tests/lib/OCS/DiscoveryServiceTest.php @@ -0,0 +1,99 @@ +<?php +/** + * @copyright Copyright (c) 2017 Bjoern Schiessle <bjoern@schiessle.org> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + + +namespace Test\OCS; + + +use OC\OCS\DiscoveryService; +use OCP\Http\Client\IClientService; +use OCP\ICacheFactory; +use OCP\OCS\IDiscoveryService; +use Test\TestCase; + +class DiscoveryServiceTest extends TestCase { + + /** @var \PHPUnit_Framework_MockObject_MockObject | ICacheFactory */ + private $cacheFactory; + + /** @var \PHPUnit_Framework_MockObject_MockObject | IClientService */ + private $clientService; + + /** @var IDiscoveryService */ + private $discoveryService; + + public function setUp() { + parent::setUp(); + + $this->cacheFactory = $this->getMockBuilder(ICacheFactory::class)->getMock(); + $this->clientService = $this->getMockBuilder(IClientService::class)->getMock(); + + $this->discoveryService = new DiscoveryService( + $this->cacheFactory, + $this->clientService + ); + } + + /** + * @dataProvider dataTestIsSafeUrl + * + * @param string $url + * @param bool $expected + */ + public function testIsSafeUrl($url, $expected) { + $result = $this->invokePrivate($this->discoveryService, 'isSafeUrl', [$url]); + $this->assertSame($expected, $result); + } + + public function dataTestIsSafeUrl() { + return [ + ['api/ocs/v1.php/foo', true], + ['/api/ocs/v1.php/foo', true], + ['api/ocs/v1.php/foo/', true], + ['api/ocs/v1.php/foo-bar/', true], + ['api/ocs/v1:php/foo', false], + ['api/ocs/<v1.php/foo', false], + ['api/ocs/v1.php>/foo', false], + ]; + } + + /** + * @dataProvider dataTestGetEndpoints + * + * @param array $decodedServices + * @param string $service + * @param array $expected + */ + public function testGetEndpoints($decodedServices, $service, $expected) { + $result = $this->invokePrivate($this->discoveryService, 'getEndpoints', [$decodedServices, $service]); + $this->assertSame($expected, $result); + } + + public function dataTestGetEndpoints() { + return [ + [['services' => ['myService' => ['endpoints' => []]]], 'myService', []], + [['services' => ['myService' => ['endpoints' => ['foo' => '/bar']]]], 'myService', ['foo' => '/bar']], + [['services' => ['myService' => ['endpoints' => ['foo' => '/bar']]]], 'anotherService', []], + [['services' => ['myService' => ['endpoints' => ['foo' => '/bar</foo']]]], 'myService', []], + ]; + } + +} diff --git a/tests/lib/Share/ShareTest.php b/tests/lib/Share/ShareTest.php index 6b0ebd76ed7..40e88d597a4 100644 --- a/tests/lib/Share/ShareTest.php +++ b/tests/lib/Share/ShareTest.php @@ -1064,11 +1064,11 @@ class ShareTest extends \Test\TestCase { $httpHelperMock->expects($this->at(0)) ->method('post') - ->with($this->stringStartsWith('https://' . $urlHost . '/ocs/v1.php/cloud/shares'), $this->anything()) + ->with($this->stringStartsWith('https://' . $urlHost . '/ocs/v2.php/cloud/shares'), $this->anything()) ->willReturn(['success' => false, 'result' => 'Exception']); $httpHelperMock->expects($this->at(1)) ->method('post') - ->with($this->stringStartsWith('http://' . $urlHost . '/ocs/v1.php/cloud/shares'), $this->anything()) + ->with($this->stringStartsWith('http://' . $urlHost . '/ocs/v2.php/cloud/shares'), $this->anything()) ->willReturn(['success' => true, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 100]]])]); \OCP\Share::shareItem('test', 'test.txt', \OCP\Share::SHARE_TYPE_REMOTE, $shareWith, \OCP\Constants::PERMISSION_READ); @@ -1077,11 +1077,11 @@ class ShareTest extends \Test\TestCase { $httpHelperMock->expects($this->at(0)) ->method('post') - ->with($this->stringStartsWith('https://' . $urlHost . '/ocs/v1.php/cloud/shares/' . $share['id'] . '/unshare'), $this->anything()) + ->with($this->stringStartsWith('https://' . $urlHost . '/ocs/v2.php/cloud/shares/' . $share['id'] . '/unshare'), $this->anything()) ->willReturn(['success' => false, 'result' => 'Exception']); $httpHelperMock->expects($this->at(1)) ->method('post') - ->with($this->stringStartsWith('http://' . $urlHost . '/ocs/v1.php/cloud/shares/' . $share['id'] . '/unshare'), $this->anything()) + ->with($this->stringStartsWith('http://' . $urlHost . '/ocs/v2.php/cloud/shares/' . $share['id'] . '/unshare'), $this->anything()) ->willReturn(['success' => true, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 100]]])]); \OCP\Share::unshare('test', 'test.txt', \OCP\Share::SHARE_TYPE_REMOTE, $shareWith); @@ -1490,7 +1490,7 @@ class ShareTest extends \Test\TestCase { $httpHelperMock->expects($this->at(0)) ->method('post') - ->with($this->stringStartsWith('https://localhost/ocs/v1.php/cloud/shares'), $this->anything()) + ->with($this->stringStartsWith('https://localhost/ocs/v2.php/cloud/shares'), $this->anything()) ->willReturn(['success' => true, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 100]]])]); \OCP\Share::shareItem('test', 'test.txt', \OCP\Share::SHARE_TYPE_REMOTE, 'foo@localhost', \OCP\Constants::PERMISSION_READ); @@ -1507,7 +1507,7 @@ class ShareTest extends \Test\TestCase { $httpHelperMock->expects($this->at(0)) ->method('post') - ->with($this->stringStartsWith('https://localhost/ocs/v1.php/cloud/shares/' . $share['id'] . '/unshare'), $this->anything()) + ->with($this->stringStartsWith('https://localhost/ocs/v2.php/cloud/shares/' . $share['id'] . '/unshare'), $this->anything()) ->willReturn(['success' => true, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 100]]])]); \OCP\Share::unshare('test', 'test.txt', \OCP\Share::SHARE_TYPE_REMOTE, 'foo@localhost'); |