Adds autodiscovery support to server-to-server sharing as specified in the specification. If no discovery data is found it is using the fallback ownCloud endpoints for legacy support.tags/v9.0.0RC1
@@ -0,0 +1,134 @@ | |||
<?php | |||
/** | |||
* @author Lukas Reschke <lukas@owncloud.com> | |||
* | |||
* @copyright Copyright (c) 2016, ownCloud, Inc. | |||
* @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 ownCloud 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/'); | |||
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) { | |||
} catch (ConnectException $e) { | |||
} | |||
// 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']; | |||
} | |||
} |
@@ -1,6 +1,7 @@ | |||
<?php | |||
/** | |||
* @author Björn Schießle <schiessle@owncloud.com> | |||
* @author Lukas Reschke <lukas@owncloud.com> | |||
* | |||
* @copyright Copyright (c) 2016, ownCloud, Inc. | |||
* @license AGPL-3.0 | |||
@@ -22,32 +23,31 @@ | |||
namespace OCA\FederatedFileSharing; | |||
use OCP\Http\Client\IClientService; | |||
class Notifications { | |||
const BASE_PATH_TO_SHARE_API = '/ocs/v1.php/cloud/shares'; | |||
const RESPONSE_FORMAT = 'json'; // default response format for ocs calls | |||
/** @var AddressHandler */ | |||
private $addressHandler; | |||
/** @var IClientService */ | |||
private $httpClientService; | |||
/** @var DiscoveryManager */ | |||
private $discoveryManager; | |||
/** | |||
* Notifications constructor. | |||
* | |||
* @param AddressHandler $addressHandler | |||
* @param IClientService $httpClientService | |||
* @param DiscoveryManager $discoveryManager | |||
*/ | |||
public function __construct( | |||
AddressHandler $addressHandler, | |||
IClientService $httpClientService | |||
IClientService $httpClientService, | |||
DiscoveryManager $discoveryManager | |||
) { | |||
$this->addressHandler = $addressHandler; | |||
$this->httpClientService = $httpClientService; | |||
$this->discoveryManager = $discoveryManager; | |||
} | |||
/** | |||
@@ -65,7 +65,7 @@ class Notifications { | |||
list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith); | |||
if ($user && $remote) { | |||
$url = $remote . self::BASE_PATH_TO_SHARE_API . '?format=' . self::RESPONSE_FORMAT; | |||
$url = $remote; | |||
$local = $this->addressHandler->generateRemoteURL(); | |||
$fields = array( | |||
@@ -78,10 +78,10 @@ class Notifications { | |||
); | |||
$url = $this->addressHandler->removeProtocolFromUrl($url); | |||
$result = $this->tryHttpPost($url, $fields); | |||
$result = $this->tryHttpPostToShareEndpoint($url, '', $fields); | |||
$status = json_decode($result['result'], true); | |||
if ($result['success'] && $status['ocs']['meta']['statuscode'] === 100) { | |||
if ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200)) { | |||
\OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $remote]); | |||
return true; | |||
} | |||
@@ -100,23 +100,24 @@ class Notifications { | |||
* @return bool | |||
*/ | |||
public function sendRemoteUnShare($remote, $id, $token) { | |||
$url = rtrim($remote, '/') . self::BASE_PATH_TO_SHARE_API . '/' . $id . '/unshare?format=' . self::RESPONSE_FORMAT; | |||
$url = rtrim($remote, '/'); | |||
$fields = array('token' => $token, 'format' => 'json'); | |||
$url = $this->addressHandler->removeProtocolFromUrl($url); | |||
$result = $this->tryHttpPost($url, $fields); | |||
$result = $this->tryHttpPostToShareEndpoint($url, '/'.$id.'/unshare', $fields); | |||
$status = json_decode($result['result'], true); | |||
return ($result['success'] && $status['ocs']['meta']['statuscode'] === 100); | |||
return ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200)); | |||
} | |||
/** | |||
* try http post first with https and then with http as a fallback | |||
* | |||
* @param string $url | |||
* @param string $remoteDomain | |||
* @param string $urlSuffix | |||
* @param array $fields post parameters | |||
* @return array | |||
*/ | |||
private function tryHttpPost($url, array $fields) { | |||
private function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) { | |||
$client = $this->httpClientService->newClient(); | |||
$protocol = 'https://'; | |||
$result = [ | |||
@@ -124,9 +125,11 @@ class Notifications { | |||
'result' => '', | |||
]; | |||
$try = 0; | |||
while ($result['success'] === false && $try < 2) { | |||
$endpoint = $this->discoveryManager->getShareEndpoint($protocol . $remoteDomain); | |||
try { | |||
$response = $client->post($protocol . $url, [ | |||
$response = $client->post($protocol . $remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT, [ | |||
'body' => $fields | |||
]); | |||
$result['result'] = $response->getBody(); | |||
@@ -140,5 +143,4 @@ class Notifications { | |||
return $result; | |||
} | |||
} |
@@ -0,0 +1,194 @@ | |||
<?php | |||
/** | |||
* @author Lukas Reschke <lukas@owncloud.com> | |||
* | |||
* @copyright Copyright (c) 2016, ownCloud, Inc. | |||
* @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; | |||
use Test\TestCase; | |||
class DiscoveryManagerTest extends TestCase { | |||
/** @var ICache */ | |||
private $cache; | |||
/** @var IClient */ | |||
private $client; | |||
/** @var DiscoveryManager */ | |||
private $discoveryManager; | |||
public function setUp() { | |||
parent::setUp(); | |||
$this->cache = $this->getMock('\OCP\ICache'); | |||
/** @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->getMock('\OCP\Http\Client\IResponse'); | |||
$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/', []) | |||
->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->getMock('\OCP\Http\Client\IResponse'); | |||
$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/', []) | |||
->willReturn($response); | |||
$expectedResult = '/public.php/MyCustomEndpoint/'; | |||
$this->assertSame($expectedResult, $this->discoveryManager->getWebDavEndpoint('https://myhost.com')); | |||
} | |||
public function testGetWebDavEndpointWithValidFormattedEndpointWithoutDataAndNotCached() { | |||
$response = $this->getMock('\OCP\Http\Client\IResponse'); | |||
$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/', []) | |||
->willReturn($response); | |||
$expectedResult = '/public.php/webdav'; | |||
$this->assertSame($expectedResult, $this->discoveryManager->getWebDavEndpoint('https://myhost.com')); | |||
} | |||
public function testGetShareEndpointWithValidFormattedEndpointAndNotCached() { | |||
$response = $this->getMock('\OCP\Http\Client\IResponse'); | |||
$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/', []) | |||
->willReturn($response); | |||
$expectedResult = '/ocs/v2.php/cloud/MyCustomShareEndpoint'; | |||
$this->assertSame($expectedResult, $this->discoveryManager->getShareEndpoint('https://myhost.com')); | |||
} | |||
public function testWithMaliciousEndpointCached() { | |||
$response = $this->getMock('\OCP\Http\Client\IResponse'); | |||
$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/', []) | |||
->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')); | |||
} | |||
} |
@@ -57,7 +57,10 @@ if (\OC\Share\Helper::isSameUserOnSameServer($owner, $remote, $currentUser, $cur | |||
exit(); | |||
} | |||
$discoveryManager = new \OCA\FederatedFileSharing\DiscoveryManager( | |||
\OC::$server->getMemCacheFactory(), | |||
\OC::$server->getHTTPClientService() | |||
); | |||
$externalManager = new \OCA\Files_Sharing\External\Manager( | |||
\OC::$server->getDatabaseConnection(), | |||
\OC\Files\Filesystem::getMountManager(), |
@@ -24,6 +24,7 @@ | |||
namespace OCA\Files_Sharing\API; | |||
use OC\Files\Filesystem; | |||
use OCA\FederatedFileSharing\DiscoveryManager; | |||
use OCA\Files_Sharing\External\Manager; | |||
class Remote { | |||
@@ -35,12 +36,17 @@ class Remote { | |||
* @return \OC_OCS_Result | |||
*/ | |||
public static function getOpenShares($params) { | |||
$discoveryManager = new DiscoveryManager( | |||
\OC::$server->getMemCacheFactory(), | |||
\OC::$server->getHTTPClientService() | |||
); | |||
$externalManager = new Manager( | |||
\OC::$server->getDatabaseConnection(), | |||
Filesystem::getMountManager(), | |||
Filesystem::getLoader(), | |||
\OC::$server->getHTTPHelper(), | |||
\OC::$server->getNotificationManager(), | |||
$discoveryManager, | |||
\OC_User::getUser() | |||
); | |||
@@ -54,12 +60,17 @@ class Remote { | |||
* @return \OC_OCS_Result | |||
*/ | |||
public static function acceptShare($params) { | |||
$discoveryManager = new DiscoveryManager( | |||
\OC::$server->getMemCacheFactory(), | |||
\OC::$server->getHTTPClientService() | |||
); | |||
$externalManager = new Manager( | |||
\OC::$server->getDatabaseConnection(), | |||
Filesystem::getMountManager(), | |||
Filesystem::getLoader(), | |||
\OC::$server->getHTTPHelper(), | |||
\OC::$server->getNotificationManager(), | |||
$discoveryManager, | |||
\OC_User::getUser() | |||
); | |||
@@ -80,12 +91,17 @@ class Remote { | |||
* @return \OC_OCS_Result | |||
*/ | |||
public static function declineShare($params) { | |||
$discoveryManager = new DiscoveryManager( | |||
\OC::$server->getMemCacheFactory(), | |||
\OC::$server->getHTTPClientService() | |||
); | |||
$externalManager = new Manager( | |||
\OC::$server->getDatabaseConnection(), | |||
Filesystem::getMountManager(), | |||
Filesystem::getLoader(), | |||
\OC::$server->getHTTPHelper(), | |||
\OC::$server->getNotificationManager(), | |||
$discoveryManager, | |||
\OC_User::getUser() | |||
); | |||
@@ -123,12 +139,17 @@ class Remote { | |||
* @return \OC_OCS_Result | |||
*/ | |||
public static function getShares($params) { | |||
$discoveryManager = new DiscoveryManager( | |||
\OC::$server->getMemCacheFactory(), | |||
\OC::$server->getHTTPClientService() | |||
); | |||
$externalManager = new Manager( | |||
\OC::$server->getDatabaseConnection(), | |||
Filesystem::getMountManager(), | |||
Filesystem::getLoader(), | |||
\OC::$server->getHTTPHelper(), | |||
\OC::$server->getNotificationManager(), | |||
$discoveryManager, | |||
\OC_User::getUser() | |||
); | |||
@@ -146,12 +167,17 @@ class Remote { | |||
* @return \OC_OCS_Result | |||
*/ | |||
public static function getShare($params) { | |||
$discoveryManager = new DiscoveryManager( | |||
\OC::$server->getMemCacheFactory(), | |||
\OC::$server->getHTTPClientService() | |||
); | |||
$externalManager = new Manager( | |||
\OC::$server->getDatabaseConnection(), | |||
Filesystem::getMountManager(), | |||
Filesystem::getLoader(), | |||
\OC::$server->getHTTPHelper(), | |||
\OC::$server->getNotificationManager(), | |||
$discoveryManager, | |||
\OC_User::getUser() | |||
); | |||
@@ -172,12 +198,17 @@ class Remote { | |||
* @return \OC_OCS_Result | |||
*/ | |||
public static function unshare($params) { | |||
$discoveryManager = new DiscoveryManager( | |||
\OC::$server->getMemCacheFactory(), | |||
\OC::$server->getHTTPClientService() | |||
); | |||
$externalManager = new Manager( | |||
\OC::$server->getDatabaseConnection(), | |||
Filesystem::getMountManager(), | |||
Filesystem::getLoader(), | |||
\OC::$server->getHTTPHelper(), | |||
\OC::$server->getNotificationManager(), | |||
$discoveryManager, | |||
\OC_User::getUser() | |||
); | |||
@@ -25,6 +25,7 @@ | |||
namespace OCA\Files_Sharing\API; | |||
use OCA\FederatedFileSharing\DiscoveryManager; | |||
use OCA\Files_Sharing\Activity; | |||
use OCP\Files\NotFoundException; | |||
@@ -70,12 +71,17 @@ class Server2Server { | |||
\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->getHTTPHelper(), | |||
\OC::$server->getNotificationManager(), | |||
$discoveryManager, | |||
$shareWith | |||
); | |||
@@ -24,6 +24,7 @@ | |||
namespace OCA\Files_Sharing\AppInfo; | |||
use OCA\FederatedFileSharing\DiscoveryManager; | |||
use OCA\Files_Sharing\MountProvider; | |||
use OCP\AppFramework\App; | |||
use OC\AppFramework\Utility\SimpleContainer; | |||
@@ -76,12 +77,17 @@ 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->getHTTPHelper(), | |||
$server->getNotificationManager(), | |||
$discoveryManager, | |||
$uid | |||
); | |||
}); |
@@ -27,6 +27,7 @@ | |||
namespace OCA\Files_Sharing\External; | |||
use OC\Files\Filesystem; | |||
use OCA\FederatedFileSharing\DiscoveryManager; | |||
use OCP\Files; | |||
use OCP\Notification\IManager; | |||
@@ -62,6 +63,8 @@ class Manager { | |||
* @var IManager | |||
*/ | |||
private $notificationManager; | |||
/** @var DiscoveryManager */ | |||
private $discoveryManager; | |||
/** | |||
* @param \OCP\IDBConnection $connection | |||
@@ -69,16 +72,23 @@ class Manager { | |||
* @param \OCP\Files\Storage\IStorageFactory $storageLoader | |||
* @param \OC\HTTPHelper $httpHelper | |||
* @param IManager $notificationManager | |||
* @param DiscoveryManager $discoveryManager | |||
* @param string $uid | |||
*/ | |||
public function __construct(\OCP\IDBConnection $connection, \OC\Files\Mount\Manager $mountManager, | |||
\OCP\Files\Storage\IStorageFactory $storageLoader, \OC\HTTPHelper $httpHelper, IManager $notificationManager, $uid) { | |||
public function __construct(\OCP\IDBConnection $connection, | |||
\OC\Files\Mount\Manager $mountManager, | |||
\OCP\Files\Storage\IStorageFactory $storageLoader, | |||
\OC\HTTPHelper $httpHelper, | |||
IManager $notificationManager, | |||
DiscoveryManager $discoveryManager, | |||
$uid) { | |||
$this->connection = $connection; | |||
$this->mountManager = $mountManager; | |||
$this->storageLoader = $storageLoader; | |||
$this->httpHelper = $httpHelper; | |||
$this->uid = $uid; | |||
$this->notificationManager = $notificationManager; | |||
$this->discoveryManager = $discoveryManager; | |||
} | |||
/** | |||
@@ -246,13 +256,13 @@ class Manager { | |||
*/ | |||
private function sendFeedbackToRemote($remote, $token, $remoteId, $feedback) { | |||
$url = rtrim($remote, '/') . \OCP\Share::BASE_PATH_TO_SHARE_API . '/' . $remoteId . '/' . $feedback . '?format=' . \OCP\Share::RESPONSE_FORMAT; | |||
$url = rtrim($remote, '/') . $this->discoveryManager->getShareEndpoint($remote) . '/' . $remoteId . '/' . $feedback . '?format=' . \OCP\Share::RESPONSE_FORMAT; | |||
$fields = array('token' => $token); | |||
$result = $this->httpHelper->post($url, $fields); | |||
$status = json_decode($result['result'], true); | |||
return ($result['success'] && $status['ocs']['meta']['statuscode'] === 100); | |||
return ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200)); | |||
} | |||
/** |
@@ -27,6 +27,7 @@ namespace OCA\Files_Sharing\External; | |||
use OC\Files\Storage\DAV; | |||
use OC\ForbiddenException; | |||
use OCA\FederatedFileSharing\DiscoveryManager; | |||
use OCA\Files_Sharing\ISharedStorage; | |||
use OCP\Files\NotFoundException; | |||
use OCP\Files\StorageInvalidException; | |||
@@ -66,6 +67,11 @@ class Storage extends DAV implements ISharedStorage { | |||
private $manager; | |||
public function __construct($options) { | |||
$discoveryManager = new DiscoveryManager( | |||
\OC::$server->getMemCacheFactory(), | |||
\OC::$server->getHTTPClientService() | |||
); | |||
$this->manager = $options['manager']; | |||
$this->certificateManager = $options['certificateManager']; | |||
$this->remote = $options['remote']; | |||
@@ -78,7 +84,7 @@ class Storage extends DAV implements ISharedStorage { | |||
$root = ''; | |||
} | |||
$secure = $protocol === 'https'; | |||
$root = rtrim($root, '/') . '/public.php/webdav'; | |||
$root = rtrim($root, '/') . $discoveryManager->getWebDavEndpoint($this->remote); | |||
$this->mountPoint = $options['mountpoint']; | |||
$this->token = $options['token']; | |||
parent::__construct(array( |
@@ -25,16 +25,22 @@ | |||
namespace OCA\Files_Sharing; | |||
use OC\Files\Filesystem; | |||
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->getHTTPHelper(), | |||
\OC::$server->getNotificationManager(), | |||
$discoveryManager, | |||
$params['uid']); | |||
$manager->removeUserShares($params['uid']); |
@@ -24,6 +24,7 @@ | |||
namespace OCA\Files_Sharing\Tests\External; | |||
use OC\Files\Storage\StorageFactory; | |||
use OCA\FederatedFileSharing\DiscoveryManager; | |||
use OCA\Files_Sharing\External\Manager; | |||
use OCA\Files_Sharing\External\MountProvider; | |||
use OCA\Files_Sharing\Tests\TestCase; | |||
@@ -64,6 +65,10 @@ class ManagerTest extends TestCase { | |||
$this->user = \OC::$server->getUserManager()->get($this->uid); | |||
$this->mountManager = new \OC\Files\Mount\Manager(); | |||
$this->httpHelper = $httpHelper = $this->getMockBuilder('\OC\HTTPHelper')->disableOriginalConstructor()->getMock(); | |||
$discoveryManager = new DiscoveryManager( | |||
\OC::$server->getMemCacheFactory(), | |||
\OC::$server->getHTTPClientService() | |||
); | |||
/** @var \OC\HTTPHelper $httpHelper */ | |||
$this->manager = new Manager( | |||
\OC::$server->getDatabaseConnection(), | |||
@@ -71,6 +76,7 @@ class ManagerTest extends TestCase { | |||
new StorageFactory(), | |||
$httpHelper, | |||
\OC::$server->getNotificationManager(), | |||
$discoveryManager, | |||
$this->uid | |||
); | |||
$this->mountProvider = new MountProvider(\OC::$server->getDatabaseConnection(), function() { |
@@ -153,14 +153,19 @@ class Test_Files_Sharing_S2S_OCS_API extends TestCase { | |||
function testDeleteUser($toDelete, $expected, $remainingUsers) { | |||
$this->createDummyS2SShares(); | |||
$discoveryManager = new \OCA\FederatedFileSharing\DiscoveryManager( | |||
\OC::$server->getMemCacheFactory(), | |||
\OC::$server->getHTTPClientService() | |||
); | |||
$manager = new OCA\Files_Sharing\External\Manager( | |||
\OC::$server->getDatabaseConnection(), | |||
\OC\Files\Filesystem::getMountManager(), | |||
\OC\Files\Filesystem::getLoader(), | |||
\OC::$server->getHTTPHelper(), | |||
\OC::$server->getNotificationManager(), | |||
$discoveryManager, | |||
$toDelete | |||
); | |||
); | |||
$manager->removeUserShares($toDelete); | |||
@@ -40,8 +40,6 @@ class Constants { | |||
const TOKEN_LENGTH = 15; // old (oc7) length is 32, keep token length in db at least that for compatibility | |||
const BASE_PATH_TO_SHARE_API = '/ocs/v1.php/cloud/shares'; | |||
protected static $shareTypeUserAndGroups = -1; | |||
protected static $shareTypeGroupUserUnique = 2; | |||
protected static $backends = array(); |
@@ -38,6 +38,7 @@ | |||
namespace OC\Share; | |||
use OC\Files\Filesystem; | |||
use OCA\FederatedFileSharing\DiscoveryManager; | |||
use OCP\DB\QueryBuilder\IQueryBuilder; | |||
use OCP\IUserSession; | |||
use OCP\IDBConnection; | |||
@@ -2620,19 +2621,25 @@ class Share extends Constants { | |||
/** | |||
* try http post first with https and then with http as a fallback | |||
* | |||
* @param string $url | |||
* @param string $remoteDomain | |||
* @param string $urlSuffix | |||
* @param array $fields post parameters | |||
* @return array | |||
*/ | |||
private static function tryHttpPost($url, $fields) { | |||
private static function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) { | |||
$protocol = 'https://'; | |||
$result = [ | |||
'success' => false, | |||
'result' => '', | |||
]; | |||
$try = 0; | |||
$discoveryManager = new DiscoveryManager( | |||
\OC::$server->getMemCacheFactory(), | |||
\OC::$server->getHTTPClientService() | |||
); | |||
while ($result['success'] === false && $try < 2) { | |||
$result = \OC::$server->getHTTPHelper()->post($protocol . $url, $fields); | |||
$endpoint = $discoveryManager->getShareEndpoint($protocol . $remoteDomain); | |||
$result = \OC::$server->getHTTPHelper()->post($protocol . $remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT, $fields); | |||
$try++; | |||
$protocol = 'http://'; | |||
} | |||
@@ -2655,7 +2662,7 @@ class Share extends Constants { | |||
list($user, $remote) = Helper::splitUserRemote($shareWith); | |||
if ($user && $remote) { | |||
$url = $remote . self::BASE_PATH_TO_SHARE_API . '?format=' . self::RESPONSE_FORMAT; | |||
$url = $remote; | |||
$local = \OC::$server->getURLGenerator()->getAbsoluteURL('/'); | |||
@@ -2669,10 +2676,10 @@ class Share extends Constants { | |||
); | |||
$url = self::removeProtocolFromUrl($url); | |||
$result = self::tryHttpPost($url, $fields); | |||
$result = self::tryHttpPostToShareEndpoint($url, '', $fields); | |||
$status = json_decode($result['result'], true); | |||
if ($result['success'] && $status['ocs']['meta']['statuscode'] === 100) { | |||
if ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200)) { | |||
\OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $remote]); | |||
return true; | |||
} | |||
@@ -2691,13 +2698,13 @@ class Share extends Constants { | |||
* @return bool | |||
*/ | |||
private static function sendRemoteUnshare($remote, $id, $token) { | |||
$url = rtrim($remote, '/') . self::BASE_PATH_TO_SHARE_API . '/' . $id . '/unshare?format=' . self::RESPONSE_FORMAT; | |||
$url = rtrim($remote, '/'); | |||
$fields = array('token' => $token, 'format' => 'json'); | |||
$url = self::removeProtocolFromUrl($url); | |||
$result = self::tryHttpPost($url, $fields); | |||
$result = self::tryHttpPostToShareEndpoint($url, '/'.$id.'/unshare', $fields); | |||
$status = json_decode($result['result'], true); | |||
return ($result['success'] && $status['ocs']['meta']['statuscode'] === 100); | |||
return ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200)); | |||
} | |||
/** |
@@ -21,6 +21,7 @@ | |||
namespace OC\Share20; | |||
use OCA\FederatedFileSharing\AddressHandler; | |||
use OCA\FederatedFileSharing\DiscoveryManager; | |||
use OCA\FederatedFileSharing\FederatedShareProvider; | |||
use OCA\FederatedFileSharing\Notifications; | |||
use OCA\FederatedFileSharing\TokenHandler; | |||
@@ -91,9 +92,14 @@ class ProviderFactory implements IProviderFactory { | |||
$this->serverContainer->getURLGenerator(), | |||
$l | |||
); | |||
$discoveryManager = new DiscoveryManager( | |||
$this->serverContainer->getMemCacheFactory(), | |||
$this->serverContainer->getHTTPClientService() | |||
); | |||
$notifications = new Notifications( | |||
$addressHandler, | |||
$this->serverContainer->getHTTPClientService() | |||
$this->serverContainer->getHTTPClientService(), | |||
$discoveryManager | |||
); | |||
$tokenHandler = new TokenHandler( | |||
$this->serverContainer->getSecureRandom() |