Merge pull request #3297 from nextcloud/cloud-id-resolve

Add a single public api for resolving a cloud id to a user and remote and back
This commit is contained in:
Robin Appelman 2017-02-09 14:54:32 +01:00 committed by GitHub
commit bf88060a98
35 changed files with 707 additions and 231 deletions

View File

@ -22,6 +22,7 @@
namespace OCA\FederatedFileSharing;
use OC\HintException;
use OCP\Federation\ICloudIdManager;
use OCP\IL10N;
use OCP\IURLGenerator;
@ -38,18 +39,24 @@ class AddressHandler {
/** @var IURLGenerator */
private $urlGenerator;
/** @var ICloudIdManager */
private $cloudIdManager;
/**
* AddressHandler constructor.
*
* @param IURLGenerator $urlGenerator
* @param IL10N $il10n
* @param ICloudIdManager $cloudIdManager
*/
public function __construct(
IURLGenerator $urlGenerator,
IL10N $il10n
IL10N $il10n,
ICloudIdManager $cloudIdManager
) {
$this->l = $il10n;
$this->urlGenerator = $urlGenerator;
$this->cloudIdManager = $cloudIdManager;
}
/**
@ -60,44 +67,13 @@ class AddressHandler {
* @throws HintException
*/
public function splitUserRemote($address) {
if (strpos($address, '@') === false) {
try {
$cloudId = $this->cloudIdManager->resolveCloudId($address);
return [$cloudId->getUser(), $cloudId->getRemote()];
} catch (\InvalidArgumentException $e) {
$hint = $this->l->t('Invalid Federated Cloud ID');
throw new HintException('Invalid Federated Cloud ID', $hint);
throw new HintException('Invalid Federated Cloud ID', $hint, 0, $e);
}
// Find the first character that is not allowed in user names
$id = str_replace('\\', '/', $address);
$posSlash = strpos($id, '/');
$posColon = strpos($id, ':');
if ($posSlash === false && $posColon === false) {
$invalidPos = strlen($id);
} else if ($posSlash === false) {
$invalidPos = $posColon;
} else if ($posColon === false) {
$invalidPos = $posSlash;
} else {
$invalidPos = min($posSlash, $posColon);
}
// Find the last @ before $invalidPos
$pos = $lastAtPos = 0;
while ($lastAtPos !== false && $lastAtPos <= $invalidPos) {
$pos = $lastAtPos;
$lastAtPos = strpos($id, '@', $pos + 1);
}
if ($pos !== false) {
$user = substr($id, 0, $pos);
$remote = substr($id, $pos + 1);
$remote = $this->fixRemoteURL($remote);
if (!empty($user) && !empty($remote)) {
return array($user, $remote);
}
}
$hint = $this->l->t('Invalid Federated Cloud ID');
throw new HintException('Invalid Federated Cloud ID', $hint);
}
/**
@ -175,27 +151,4 @@ class AddressHandler {
return false;
}
/**
* Strips away a potential file names and trailing slashes:
* - http://localhost
* - http://localhost/
* - http://localhost/index.php
* - http://localhost/index.php/s/{shareToken}
*
* all return: http://localhost
*
* @param string $remote
* @return string
*/
protected function fixRemoteURL($remote) {
$remote = str_replace('\\', '/', $remote);
if ($fileNamePosition = strpos($remote, '/index.php')) {
$remote = substr($remote, 0, $fileNamePosition);
}
$remote = rtrim($remote, '/');
return $remote;
}
}

View File

@ -45,7 +45,8 @@ class Application extends App {
$container->registerService('RequestHandlerController', function(SimpleContainer $c) use ($server) {
$addressHandler = new AddressHandler(
$server->getURLGenerator(),
$server->getL10N('federatedfilesharing')
$server->getL10N('federatedfilesharing'),
$server->getCloudIdManager()
);
$notification = new Notifications(
$addressHandler,
@ -64,7 +65,8 @@ class Application extends App {
$server->getShareManager(),
$notification,
$addressHandler,
$server->getUserManager()
$server->getUserManager(),
$server->getCloudIdManager()
);
});
}
@ -94,7 +96,8 @@ class Application extends App {
protected function initFederatedShareProvider() {
$addressHandler = new \OCA\FederatedFileSharing\AddressHandler(
\OC::$server->getURLGenerator(),
\OC::$server->getL10N('federatedfilesharing')
\OC::$server->getL10N('federatedfilesharing'),
\OC::$server->getCloudIdManager()
);
$discoveryManager = new \OCA\FederatedFileSharing\DiscoveryManager(
\OC::$server->getMemCacheFactory(),
@ -119,7 +122,8 @@ class Application extends App {
\OC::$server->getLogger(),
\OC::$server->getLazyRootFolder(),
\OC::$server->getConfig(),
\OC::$server->getUserManager()
\OC::$server->getUserManager(),
\OC::$server->getCloudIdManager()
);
}

View File

@ -65,7 +65,8 @@ class RetryJob extends Job {
} else {
$addressHandler = new AddressHandler(
\OC::$server->getURLGenerator(),
\OC::$server->getL10N('federatedfilesharing')
\OC::$server->getL10N('federatedfilesharing'),
\OC::$server->getCloudIdManager()
);
$discoveryManager = new DiscoveryManager(
\OC::$server->getMemCacheFactory(),

View File

@ -35,6 +35,7 @@ use OCA\Files_Sharing\External\Manager;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse;
use OCP\Federation\ICloudIdManager;
use OCP\Files\StorageInvalidException;
use OCP\Http\Client\IClientService;
use OCP\IL10N;
@ -74,6 +75,9 @@ class MountPublicLinkController extends Controller {
/** @var IClientService */
private $clientService;
/** @var ICloudIdManager */
private $cloudIdManager;
/**
* MountPublicLinkController constructor.
*
@ -86,6 +90,7 @@ class MountPublicLinkController extends Controller {
* @param IL10N $l
* @param IUserSession $userSession
* @param IClientService $clientService
* @param ICloudIdManager $cloudIdManager
*/
public function __construct($appName,
IRequest $request,
@ -95,7 +100,8 @@ class MountPublicLinkController extends Controller {
ISession $session,
IL10N $l,
IUserSession $userSession,
IClientService $clientService
IClientService $clientService,
ICloudIdManager $cloudIdManager
) {
parent::__construct($appName, $request);
@ -106,6 +112,7 @@ class MountPublicLinkController extends Controller {
$this->l = $l;
$this->userSession = $userSession;
$this->clientService = $clientService;
$this->cloudIdManager = $cloudIdManager;
}
/**
@ -177,7 +184,7 @@ class MountPublicLinkController extends Controller {
return new JSONResponse(['message' => $this->l->t('Server to server sharing is not enabled on this server')], Http::STATUS_BAD_REQUEST);
}
$shareWith = $this->userSession->getUser()->getUID() . '@' . $this->addressHandler->generateRemoteURL();
$cloudId = $this->cloudIdManager->getCloudId($this->userSession->getUser()->getUID(), $this->addressHandler->generateRemoteURL());
$httpClient = $this->clientService->newClient();
@ -187,7 +194,7 @@ class MountPublicLinkController extends Controller {
'body' =>
[
'token' => $token,
'shareWith' => rtrim($shareWith, '/'),
'shareWith' => rtrim($cloudId->getId(), '/'),
'password' => $password
],
'connect_timeout' => 10,

View File

@ -38,6 +38,7 @@ use OCP\AppFramework\OCS\OCSForbiddenException;
use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\AppFramework\OCSController;
use OCP\Constants;
use OCP\Federation\ICloudIdManager;
use OCP\Files\NotFoundException;
use OCP\IDBConnection;
use OCP\IRequest;
@ -68,6 +69,9 @@ class RequestHandlerController extends OCSController {
/** @var string */
private $shareTable = 'share';
/** @var ICloudIdManager */
private $cloudIdManager;
/**
* Server2Server constructor.
*
@ -79,6 +83,7 @@ class RequestHandlerController extends OCSController {
* @param Notifications $notifications
* @param AddressHandler $addressHandler
* @param IUserManager $userManager
* @param ICloudIdManager $cloudIdManager
*/
public function __construct($appName,
IRequest $request,
@ -87,7 +92,8 @@ class RequestHandlerController extends OCSController {
Share\IManager $shareManager,
Notifications $notifications,
AddressHandler $addressHandler,
IUserManager $userManager
IUserManager $userManager,
ICloudIdManager $cloudIdManager
) {
parent::__construct($appName, $request);
@ -97,6 +103,7 @@ class RequestHandlerController extends OCSController {
$this->notifications = $notifications;
$this->addressHandler = $addressHandler;
$this->userManager = $userManager;
$this->cloudIdManager = $cloudIdManager;
}
/**
@ -164,7 +171,7 @@ class RequestHandlerController extends OCSController {
$shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external');
if ($ownerFederatedId === null) {
$ownerFederatedId = $owner . '@' . $this->cleanupRemote($remote);
$ownerFederatedId = $this->cloudIdManager->getCloudId($owner, $this->cleanupRemote($remote))->getId();
}
// if the owner of the share and the initiator are the same user
// we also complete the federated share ID for the initiator
@ -424,7 +431,7 @@ class RequestHandlerController extends OCSController {
$remote = $this->cleanupRemote($share['remote']);
$owner = $share['owner'] . '@' . $remote;
$owner = $this->cloudIdManager->getCloudId($share['owner'], $remote);
$mountpoint = $share['mountpoint'];
$user = $share['user'];

View File

@ -27,6 +27,7 @@
namespace OCA\FederatedFileSharing;
use OC\Share20\Share;
use OCP\Federation\ICloudIdManager;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\IConfig;
@ -80,6 +81,9 @@ class FederatedShareProvider implements IShareProvider {
/** @var IUserManager */
private $userManager;
/** @var ICloudIdManager */
private $cloudIdManager;
/**
* DefaultShareProvider constructor.
*
@ -92,6 +96,7 @@ class FederatedShareProvider implements IShareProvider {
* @param IRootFolder $rootFolder
* @param IConfig $config
* @param IUserManager $userManager
* @param ICloudIdManager $cloudIdManager
*/
public function __construct(
IDBConnection $connection,
@ -102,7 +107,8 @@ class FederatedShareProvider implements IShareProvider {
ILogger $logger,
IRootFolder $rootFolder,
IConfig $config,
IUserManager $userManager
IUserManager $userManager,
ICloudIdManager $cloudIdManager
) {
$this->dbConnection = $connection;
$this->addressHandler = $addressHandler;
@ -113,6 +119,7 @@ class FederatedShareProvider implements IShareProvider {
$this->rootFolder = $rootFolder;
$this->config = $config;
$this->userManager = $userManager;
$this->cloudIdManager = $cloudIdManager;
}
/**
@ -153,17 +160,18 @@ class FederatedShareProvider implements IShareProvider {
// don't allow federated shares if source and target server are the same
list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith);
$cloudId = $this->cloudIdManager->resolveCloudId($shareWith);
$currentServer = $this->addressHandler->generateRemoteURL();
$currentUser = $sharedBy;
if ($this->addressHandler->compareAddresses($user, $remote, $currentUser, $currentServer)) {
if ($this->addressHandler->compareAddresses($cloudId->getUser(), $cloudId->getRemote(), $currentUser, $currentServer)) {
$message = 'Not allowed to create a federated share with the same user.';
$message_t = $this->l->t('Not allowed to create a federated share with the same user');
$this->logger->debug($message, ['app' => 'Federated File Sharing']);
throw new \Exception($message_t);
}
$share->setSharedWith($user . '@' . $remote);
$share->setSharedWith($cloudId->getId());
try {
$remoteShare = $this->getShareFromExternalShareTable($share);
@ -173,8 +181,8 @@ class FederatedShareProvider implements IShareProvider {
if ($remoteShare) {
try {
$uidOwner = $remoteShare['owner'] . '@' . $remoteShare['remote'];
$shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, 'tmp_token_' . time());
$ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']);
$shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time());
$share->setId($shareId);
list($token, $remoteId) = $this->askOwnerToReShare($shareWith, $share, $shareId);
// remote share was create successfully if we get a valid token as return
@ -227,15 +235,17 @@ class FederatedShareProvider implements IShareProvider {
try {
$sharedByFederatedId = $share->getSharedBy();
if ($this->userManager->userExists($sharedByFederatedId)) {
$sharedByFederatedId = $sharedByFederatedId . '@' . $this->addressHandler->generateRemoteURL();
$cloudId = $this->cloudIdManager->getCloudId($sharedByFederatedId, $this->addressHandler->generateRemoteURL());
$sharedByFederatedId = $cloudId->getId();
}
$ownerCloudId = $this->cloudIdManager->getCloudId($share->getShareOwner(), $this->addressHandler->generateRemoteURL());
$send = $this->notifications->sendRemoteShare(
$token,
$share->getSharedWith(),
$share->getNode()->getName(),
$shareId,
$share->getShareOwner(),
$share->getShareOwner() . '@' . $this->addressHandler->generateRemoteURL(),
$ownerCloudId->getId(),
$share->getSharedBy(),
$sharedByFederatedId
);

View File

@ -27,6 +27,8 @@ namespace OCA\FederatedFileSharing;
use OC\HintException;
use OC\Share\Helper;
use OCP\Contacts\IManager;
use OCP\Federation\ICloudId;
use OCP\Federation\ICloudIdManager;
use OCP\IURLGenerator;
use OCP\L10N\IFactory;
use OCP\Notification\INotification;
@ -41,16 +43,20 @@ class Notifier implements INotifier {
protected $url;
/** @var array */
protected $federatedContacts;
/** @var ICloudIdManager */
protected $cloudIdManager;
/**
* @param IFactory $factory
* @param IManager $contactsManager
* @param IURLGenerator $url
* @param ICloudIdManager $cloudIdManager
*/
public function __construct(IFactory $factory, IManager $contactsManager, IURLGenerator $url) {
public function __construct(IFactory $factory, IManager $contactsManager, IURLGenerator $url, ICloudIdManager $cloudIdManager) {
$this->factory = $factory;
$this->contactsManager = $contactsManager;
$this->url = $url;
$this->cloudIdManager = $cloudIdManager;
}
/**
@ -140,8 +146,10 @@ class Notifier implements INotifier {
protected function createRemoteUser($cloudId) {
$displayName = $cloudId;
try {
list($user, $server) = Helper::splitUserRemote($cloudId);
$displayName = $this->getDisplayName($user, $server);
$resolvedId = $this->cloudIdManager->resolveCloudId($cloudId);
$displayName = $this->getDisplayName($resolvedId);
$user = $resolvedId->getUser();
$server = $resolvedId->getRemote();
} catch (HintException $e) {
$user = $cloudId;
$server = '';
@ -158,14 +166,12 @@ class Notifier implements INotifier {
/**
* Try to find the user in the contacts
*
* @param string $user
* @param string $server
* @param ICloudId $cloudId
* @return string
* @throws \OutOfBoundsException when there is no contact for the id
*/
protected function getDisplayName($user, $server) {
$server = strtolower(rtrim($server, '/'));
protected function getDisplayName(ICloudId $cloudId) {
$server = $cloudId->getRemote();
$user = $cloudId->getUser();
if (strpos($server, 'http://') === 0) {
$server = substr($server, strlen('http://'));
} else if (strpos($server, 'https://') === 0) {
@ -173,7 +179,7 @@ class Notifier implements INotifier {
}
try {
return $this->getDisplayNameFromContact($user . '@' . $server);
return $this->getDisplayNameFromContact($cloudId->getId());
} catch (\OutOfBoundsException $e) {
}
@ -187,7 +193,7 @@ class Notifier implements INotifier {
} catch (\OutOfBoundsException $e) {
}
return $user . '@' . $server;
return $cloudId->getId();
}
/**

View File

@ -25,6 +25,7 @@
namespace OCA\FederatedFileSharing\Tests;
use OC\Federation\CloudIdManager;
use OCA\FederatedFileSharing\AddressHandler;
use OCP\IL10N;
use OCP\IURLGenerator;
@ -40,6 +41,9 @@ class AddressHandlerTest extends \Test\TestCase {
/** @var IL10N | \PHPUnit_Framework_MockObject_MockObject */
private $il10n;
/** @var CloudIdManager */
private $cloudIdManager;
public function setUp() {
parent::setUp();
@ -48,7 +52,9 @@ class AddressHandlerTest extends \Test\TestCase {
$this->il10n = $this->getMockBuilder('OCP\IL10N')
->getMock();
$this->addressHandler = new AddressHandler($this->urlGenerator, $this->il10n);
$this->cloudIdManager = new CloudIdManager();
$this->addressHandler = new AddressHandler($this->urlGenerator, $this->il10n, $this->cloudIdManager);
}
public function dataTestSplitUserRemote() {
@ -196,26 +202,4 @@ class AddressHandlerTest extends \Test\TestCase {
['httpserver.com', false],
];
}
/**
* @dataProvider dataTestFixRemoteUrl
*
* @param string $url
* @param string $expected
*/
public function testFixRemoteUrl($url, $expected) {
$this->assertSame($expected,
$this->invokePrivate($this->addressHandler, 'fixRemoteURL', [$url])
);
}
public function dataTestFixRemoteUrl() {
return [
['http://localhost', 'http://localhost'],
['http://localhost/', 'http://localhost'],
['http://localhost/index.php', 'http://localhost'],
['http://localhost/index.php/s/AShareToken', 'http://localhost'],
];
}
}

View File

@ -25,11 +25,13 @@
namespace OCA\FederatedFileSharing\Tests\Controller;
use OC\Federation\CloudIdManager;
use OC\HintException;
use OCA\FederatedFileSharing\AddressHandler;
use OCA\FederatedFileSharing\Controller\MountPublicLinkController;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCP\AppFramework\Http;
use OCP\Federation\ICloudIdManager;
use OCP\Files\IRootFolder;
use OCP\Http\Client\IClientService;
use OCP\IL10N;
@ -77,6 +79,9 @@ class MountPublicLinkControllerTest extends \Test\TestCase {
/** @var IShare */
private $share;
/** @var ICloudIdManager */
private $cloudIdManager;
public function setUp() {
parent::setUp();
@ -93,6 +98,7 @@ class MountPublicLinkControllerTest extends \Test\TestCase {
$this->l10n = $this->getMockBuilder('OCP\IL10N')->disableOriginalConstructor()->getMock();
$this->userSession = $this->getMockBuilder('OCP\IUserSession')->disableOriginalConstructor()->getMock();
$this->clientService = $this->getMockBuilder('OCP\Http\Client\IClientService')->disableOriginalConstructor()->getMock();
$this->cloudIdManager = new CloudIdManager();
$this->controller = new MountPublicLinkController(
'federatedfilesharing', $this->request,
@ -102,7 +108,8 @@ class MountPublicLinkControllerTest extends \Test\TestCase {
$this->session,
$this->l10n,
$this->userSession,
$this->clientService
$this->clientService,
$this->cloudIdManager
);
}

View File

@ -27,10 +27,12 @@
namespace OCA\FederatedFileSharing\Tests;
use OC\Federation\CloudIdManager;
use OC\Files\Filesystem;
use OCA\FederatedFileSharing\DiscoveryManager;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCA\FederatedFileSharing\Controller\RequestHandlerController;
use OCP\Federation\ICloudIdManager;
use OCP\Http\Client\IClient;
use OCP\Http\Client\IClientService;
use OCP\Http\Client\IResponse;
@ -72,6 +74,9 @@ class RequestHandlerControllerTest extends TestCase {
/** @var IShare|\PHPUnit_Framework_MockObject_MockObject */
private $share;
/** @var ICloudIdManager */
private $cloudIdManager;
protected function setUp() {
parent::setUp();
@ -101,6 +106,8 @@ class RequestHandlerControllerTest extends TestCase {
->disableOriginalConstructor()->getMock();
$this->userManager = $this->getMockBuilder('OCP\IUserManager')->getMock();
$this->cloudIdManager = new CloudIdManager();
$this->registerHttpHelper($httpHelperMock);
$this->s2s = new RequestHandlerController(
@ -111,7 +118,8 @@ class RequestHandlerControllerTest extends TestCase {
\OC::$server->getShareManager(),
$this->notifications,
$this->addressHandler,
$this->userManager
$this->userManager,
$this->cloudIdManager
);
$this->connection = \OC::$server->getDatabaseConnection();
@ -190,7 +198,8 @@ class RequestHandlerControllerTest extends TestCase {
\OC::$server->getShareManager(),
$this->notifications,
$this->addressHandler,
$this->userManager
$this->userManager,
$this->cloudIdManager
]
)->setMethods(['executeDeclineShare', 'verifyShare'])->getMock();

View File

@ -25,10 +25,12 @@
namespace OCA\FederatedFileSharing\Tests;
use OC\Federation\CloudIdManager;
use OCA\FederatedFileSharing\AddressHandler;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCA\FederatedFileSharing\Notifications;
use OCA\FederatedFileSharing\TokenHandler;
use OCP\Federation\ICloudIdManager;
use OCP\Files\IRootFolder;
use OCP\IConfig;
use OCP\IDBConnection;
@ -69,6 +71,9 @@ class FederatedShareProviderTest extends \Test\TestCase {
/** @var FederatedShareProvider */
protected $provider;
/** @var ICloudIdManager */
private $cloudIdManager;
public function setUp() {
parent::setUp();
@ -94,6 +99,8 @@ class FederatedShareProviderTest extends \Test\TestCase {
$this->userManager->expects($this->any())->method('userExists')->willReturn(true);
$this->cloudIdManager = new CloudIdManager();
$this->provider = new FederatedShareProvider(
$this->connection,
$this->addressHandler,
@ -103,7 +110,8 @@ class FederatedShareProviderTest extends \Test\TestCase {
$this->logger,
$this->rootFolder,
$this->config,
$this->userManager
$this->userManager,
$this->cloudIdManager
);
$this->shareManager = \OC::$server->getShareManager();
@ -400,7 +408,8 @@ class FederatedShareProviderTest extends \Test\TestCase {
$this->logger,
$this->rootFolder,
$this->config,
$this->userManager
$this->userManager,
$this->cloudIdManager
]
)->setMethods(['sendPermissionUpdate'])->getMock();

View File

@ -24,17 +24,38 @@ namespace OCA\Files_Sharing\Activity\Providers;
use OCP\Activity\IEvent;
use OCP\Activity\IManager;
use OCP\Activity\IProvider;
use OCP\Federation\ICloudIdManager;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\IUserManager;
use OCP\L10N\IFactory;
class RemoteShares extends Base {
protected $cloudIdManager;
const SUBJECT_REMOTE_SHARE_ACCEPTED = 'remote_share_accepted';
const SUBJECT_REMOTE_SHARE_DECLINED = 'remote_share_declined';
const SUBJECT_REMOTE_SHARE_RECEIVED = 'remote_share_received';
const SUBJECT_REMOTE_SHARE_UNSHARED = 'remote_share_unshared';
/**
* @param IFactory $languageFactory
* @param IURLGenerator $url
* @param IManager $activityManager
* @param IUserManager $userManager
* @param ICloudIdManager $cloudIdManager
*/
public function __construct(IFactory $languageFactory,
IURLGenerator $url,
IManager $activityManager,
IUserManager $userManager,
ICloudIdManager $cloudIdManager
) {
parent::__construct($languageFactory, $url, $activityManager, $userManager);
$this->cloudIdManager = $cloudIdManager;
}
/**
* @param IEvent $event
* @return IEvent
@ -115,12 +136,12 @@ class RemoteShares extends Base {
* @return array
*/
protected function getFederatedUser($cloudId) {
$remoteUser = explode('@', $cloudId, 2);
$remoteUser = $this->cloudIdManager->resolveCloudId($cloudId);
return [
'type' => 'user',
'id' => $remoteUser[0],
'id' => $remoteUser->getUser(),
'name' => $cloudId,// Todo display name from contacts
'server' => $remoteUser[1],
'server' => $remoteUser->getRemote(),
];
}
}

View File

@ -35,6 +35,7 @@ use OC\AppFramework\Utility\SimpleContainer;
use OCA\Files_Sharing\Controller\ExternalSharesController;
use OCA\Files_Sharing\Controller\ShareController;
use OCA\Files_Sharing\Middleware\SharingCheckMiddleware;
use OCP\Federation\ICloudIdManager;
use \OCP\IContainer;
use OCP\IServerContainer;
@ -84,6 +85,9 @@ class Application extends App {
$container->registerService('HttpClientService', function (SimpleContainer $c) use ($server) {
return $server->getHTTPClientService();
});
$container->registerService(ICloudIdManager::class, function (SimpleContainer $c) use ($server) {
return $server->getCloudIdManager();
});
$container->registerService('ExternalManager', function (SimpleContainer $c) use ($server) {
$user = $server->getUserSession()->getUser();
$uid = $user ? $user->getUID() : null;
@ -145,7 +149,8 @@ class Application extends App {
$server->getDatabaseConnection(),
function() use ($c) {
return $c->query('ExternalManager');
}
},
$server->getCloudIdManager()
);
});

View File

@ -28,6 +28,7 @@ use OCP\AppFramework\Http;
use OCP\AppFramework\OCS\OCSBadRequestException;
use OCP\AppFramework\OCSController;
use OCP\Contacts\IManager;
use OCP\Federation\ICloudIdManager;
use OCP\Http\Client\IClientService;
use OCP\IGroup;
use OCP\IGroupManager;
@ -69,6 +70,9 @@ class ShareesAPIController extends OCSController {
/** @var IClientService */
protected $clientService;
/** @var ICloudIdManager */
protected $cloudIdManager;
/** @var bool */
protected $shareWithGroupOnly = false;
@ -110,6 +114,7 @@ class ShareesAPIController extends OCSController {
* @param ILogger $logger
* @param \OCP\Share\IManager $shareManager
* @param IClientService $clientService
* @param ICloudIdManager $cloudIdManager
*/
public function __construct($appName,
IRequest $request,
@ -121,7 +126,9 @@ class ShareesAPIController extends OCSController {
IURLGenerator $urlGenerator,
ILogger $logger,
\OCP\Share\IManager $shareManager,
IClientService $clientService) {
IClientService $clientService,
ICloudIdManager $cloudIdManager
) {
parent::__construct($appName, $request);
$this->groupManager = $groupManager;
@ -133,6 +140,7 @@ class ShareesAPIController extends OCSController {
$this->logger = $logger;
$this->shareManager = $shareManager;
$this->clientService = $clientService;
$this->cloudIdManager = $cloudIdManager;
}
/**
@ -339,7 +347,7 @@ class ShareesAPIController extends OCSController {
$result['results'] = [];
}
if (!$result['exactIdMatch'] && substr_count($search, '@') >= 1 && $this->offset === 0) {
if (!$result['exactIdMatch'] && $this->cloudIdManager->isValidCloudId($search) && $this->offset === 0) {
$result['exact'][] = [
'label' => $search,
'value' => [
@ -362,42 +370,12 @@ class ShareesAPIController extends OCSController {
* @throws \Exception
*/
public function splitUserRemote($address) {
if (strpos($address, '@') === false) {
throw new \Exception('Invalid Federated Cloud ID');
try {
$cloudId = $this->cloudIdManager->resolveCloudId($address);
return [$cloudId->getUser(), $cloudId->getRemote()];
} catch (\InvalidArgumentException $e) {
throw new \Exception('Invalid Federated Cloud ID', 0, $e);
}
// Find the first character that is not allowed in user names
$id = str_replace('\\', '/', $address);
$posSlash = strpos($id, '/');
$posColon = strpos($id, ':');
if ($posSlash === false && $posColon === false) {
$invalidPos = strlen($id);
} else if ($posSlash === false) {
$invalidPos = $posColon;
} else if ($posColon === false) {
$invalidPos = $posSlash;
} else {
$invalidPos = min($posSlash, $posColon);
}
// Find the last @ before $invalidPos
$pos = $lastAtPos = 0;
while ($lastAtPos !== false && $lastAtPos <= $invalidPos) {
$pos = $lastAtPos;
$lastAtPos = strpos($id, '@', $pos + 1);
}
if ($pos !== false) {
$user = substr($id, 0, $pos);
$remote = substr($id, $pos + 1);
$remote = $this->fixRemoteURL($remote);
if (!empty($user) && !empty($remote)) {
return array($user, $remote);
}
}
throw new \Exception('Invalid Federated Cloud ID');
}
/**

View File

@ -24,21 +24,25 @@
namespace OCA\Files_Sharing\External;
use OCP\Federation\ICloudId;
class Cache extends \OC\Files\Cache\Cache {
/** @var ICloudId */
private $cloudId;
private $remote;
private $remoteUser;
private $storage;
/**
* @param \OCA\Files_Sharing\External\Storage $storage
* @param string $remote
* @param string $remoteUser
* @param ICloudId $cloudId
*/
public function __construct($storage, $remote, $remoteUser) {
public function __construct($storage, ICloudId $cloudId) {
$this->cloudId = $cloudId;
$this->storage = $storage;
list(, $remote) = explode('://', $remote, 2);
list(, $remote) = explode('://', $cloudId->getRemote(), 2);
$this->remote = $remote;
$this->remoteUser = $remoteUser;
$this->remoteUser = $cloudId->getUser();
parent::__construct($storage);
}
@ -47,7 +51,7 @@ class Cache extends \OC\Files\Cache\Cache {
if (!$result) {
return false;
}
$result['displayname_owner'] = $this->remoteUser . '@' . $this->remote;
$result['displayname_owner'] = $this->cloudId->getDisplayId();
if (!$file || $file === '') {
$result['is_share_mount_point'] = true;
$mountPoint = rtrim($this->storage->getMountPoint());
@ -59,7 +63,7 @@ class Cache extends \OC\Files\Cache\Cache {
public function getFolderContentsById($id) {
$results = parent::getFolderContentsById($id);
foreach ($results as &$file) {
$file['displayname_owner'] = $this->remoteUser . '@' . $this->remote;
$file['displayname_owner'] = $this->cloudId->getDisplayId();
}
return $results;
}

View File

@ -22,6 +22,7 @@
namespace OCA\Files_Sharing\External;
use OCP\Federation\ICloudIdManager;
use OCP\Files\Config\IMountProvider;
use OCP\Files\Storage\IStorageFactory;
use OCP\IDBConnection;
@ -40,13 +41,20 @@ class MountProvider implements IMountProvider {
*/
private $managerProvider;
/**
* @var ICloudIdManager
*/
private $cloudIdManager;
/**
* @param \OCP\IDBConnection $connection
* @param callable $managerProvider due to setup order we need a callable that return the manager instead of the manager itself
* @param ICloudIdManager $cloudIdManager
*/
public function __construct(IDBConnection $connection, callable $managerProvider) {
public function __construct(IDBConnection $connection, callable $managerProvider, ICloudIdManager $cloudIdManager) {
$this->connection = $connection;
$this->managerProvider = $managerProvider;
$this->cloudIdManager = $cloudIdManager;
}
public function getMount(IUser $user, $data, IStorageFactory $storageFactory) {
@ -55,6 +63,7 @@ class MountProvider implements IMountProvider {
$data['manager'] = $manager;
$mountPoint = '/' . $user->getUID() . '/files/' . ltrim($data['mountpoint'], '/');
$data['mountpoint'] = $mountPoint;
$data['cloudId'] = $this->cloudIdManager->getCloudId($data['owner'], $data['remote']);
$data['certificateManager'] = \OC::$server->getCertificateManager($user->getUID());
$data['HttpClientService'] = \OC::$server->getHTTPClientService();
return new Mount(self::STORAGE, $mountPoint, $data, $manager, $storageFactory);

View File

@ -35,15 +35,14 @@ use OC\ForbiddenException;
use OCA\FederatedFileSharing\DiscoveryManager;
use OCA\Files_Sharing\ISharedStorage;
use OCP\AppFramework\Http;
use OCP\Federation\ICloudId;
use OCP\Files\NotFoundException;
use OCP\Files\StorageInvalidException;
use OCP\Files\StorageNotAvailableException;
class Storage extends DAV implements ISharedStorage {
/** @var string */
private $remoteUser;
/** @var string */
private $remote;
/** @var ICloudId */
private $cloudId;
/** @var string */
private $mountPoint;
/** @var string */
@ -72,9 +71,8 @@ class Storage extends DAV implements ISharedStorage {
$this->manager = $options['manager'];
$this->certificateManager = $options['certificateManager'];
$this->remote = $options['remote'];
$this->remoteUser = $options['owner'];
list($protocol, $remote) = explode('://', $this->remote);
$this->cloudId = $options['cloudId'];
list($protocol, $remote) = explode('://', $this->cloudId->getRemote());
if (strpos($remote, '/')) {
list($host, $root) = explode('/', $remote, 2);
} else {
@ -82,7 +80,7 @@ class Storage extends DAV implements ISharedStorage {
$root = '';
}
$secure = $protocol === 'https';
$root = rtrim($root, '/') . $discoveryManager->getWebDavEndpoint($this->remote);
$root = rtrim($root, '/') . $discoveryManager->getWebDavEndpoint($this->cloudId->getRemote());
$this->mountPoint = $options['mountpoint'];
$this->token = $options['token'];
parent::__construct(array(
@ -106,11 +104,11 @@ class Storage extends DAV implements ISharedStorage {
}
public function getRemoteUser() {
return $this->remoteUser;
return $this->cloudId->getUser();
}
public function getRemote() {
return $this->remote;
return $this->cloudId->getRemote();
}
public function getMountPoint() {
@ -130,12 +128,12 @@ class Storage extends DAV implements ISharedStorage {
* @return string
*/
public function getId() {
return 'shared::' . md5($this->token . '@' . $this->remote);
return 'shared::' . md5($this->token . '@' . $this->getRemote());
}
public function getCache($path = '', $storage = null) {
if (is_null($this->cache)) {
$this->cache = new Cache($this, $this->remote, $this->remoteUser);
$this->cache = new Cache($this, $this->cloudId);
}
return $this->cache;
}
@ -251,9 +249,9 @@ class Storage extends DAV implements ISharedStorage {
*/
protected function testRemote() {
try {
return $this->testRemoteUrl($this->remote . '/ocs-provider/index.php')
|| $this->testRemoteUrl($this->remote . '/ocs-provider/')
|| $this->testRemoteUrl($this->remote . '/status.php');
return $this->testRemoteUrl($this->getRemote() . '/ocs-provider/index.php')
|| $this->testRemoteUrl($this->getRemote() . '/ocs-provider/')
|| $this->testRemoteUrl($this->getRemote() . '/status.php');
} catch (\Exception $e) {
return false;
}
@ -343,8 +341,7 @@ class Storage extends DAV implements ISharedStorage {
}
public function getOwner($path) {
list(, $remote) = explode('://', $this->remote, 2);
return $this->remoteUser . '@' . $remote;
return $this->cloudId->getDisplayId();
}
public function isSharable($path) {

View File

@ -25,10 +25,12 @@
namespace OCA\Files_Sharing\Tests\Controller;
use OC\Federation\CloudIdManager;
use OCA\Files_Sharing\Controller\ShareesAPIController;
use OCA\Files_Sharing\Tests\TestCase;
use OCP\AppFramework\Http;
use OCP\AppFramework\OCS\OCSBadRequestException;
use OCP\Federation\ICloudIdManager;
use OCP\Http\Client\IClientService;
use OCP\Share;
@ -64,6 +66,9 @@ class ShareesAPIControllerTest extends TestCase {
/** @var IClientService|\PHPUnit_Framework_MockObject_MockObject */
private $clientService;
/** @var ICloudIdManager */
private $cloudIdManager;
protected function setUp() {
parent::setUp();
@ -93,6 +98,8 @@ class ShareesAPIControllerTest extends TestCase {
$this->clientService = $this->createMock(IClientService::class);
$this->cloudIdManager = new CloudIdManager();
$this->sharees = new ShareesAPIController(
'files_sharing',
$this->request,
@ -104,7 +111,8 @@ class ShareesAPIControllerTest extends TestCase {
$this->getMockBuilder('OCP\IURLGenerator')->disableOriginalConstructor()->getMock(),
$this->getMockBuilder('OCP\ILogger')->disableOriginalConstructor()->getMock(),
$this->shareManager,
$this->clientService
$this->clientService,
$this->cloudIdManager
);
}
@ -1434,7 +1442,8 @@ class ShareesAPIControllerTest extends TestCase {
$this->getMockBuilder('OCP\IURLGenerator')->disableOriginalConstructor()->getMock(),
$this->getMockBuilder('OCP\ILogger')->disableOriginalConstructor()->getMock(),
$this->shareManager,
$this->clientService
$this->clientService,
$this->cloudIdManager
])
->setMethods(array('searchSharees', 'isRemoteSharingAllowed', 'shareProviderExists'))
->getMock();
@ -1526,7 +1535,8 @@ class ShareesAPIControllerTest extends TestCase {
$this->getMockBuilder('OCP\IURLGenerator')->disableOriginalConstructor()->getMock(),
$this->getMockBuilder('OCP\ILogger')->disableOriginalConstructor()->getMock(),
$this->shareManager,
$this->clientService
$this->clientService,
$this->cloudIdManager
])
->setMethods(array('searchSharees', 'isRemoteSharingAllowed'))
->getMock();
@ -1692,7 +1702,8 @@ class ShareesAPIControllerTest extends TestCase {
$this->getMockBuilder('OCP\IURLGenerator')->disableOriginalConstructor()->getMock(),
$this->getMockBuilder('OCP\ILogger')->disableOriginalConstructor()->getMock(),
$this->shareManager,
$this->clientService
$this->clientService,
$this->cloudIdManager
])
->setMethods(array('getShareesForShareIds', 'getUsers', 'getGroups', 'getRemote'))
->getMock();

View File

@ -24,7 +24,9 @@
*/
namespace OCA\Files_Sharing\Tests\External;
use OC\Federation\CloudIdManager;
use OCA\Files_Sharing\Tests\TestCase;
use OCP\Federation\ICloudIdManager;
/**
* Class Cache
@ -50,9 +52,13 @@ class CacheTest extends TestCase {
*/
private $remoteUser;
/** @var ICloudIdManager */
private $cloudIdManager;
protected function setUp() {
parent::setUp();
$this->cloudIdManager = new CloudIdManager();
$this->remoteUser = $this->getUniqueID('remoteuser');
$this->storage = $this->getMockBuilder('\OCA\Files_Sharing\External\Storage')
@ -64,8 +70,7 @@ class CacheTest extends TestCase {
->will($this->returnValue('dummystorage::'));
$this->cache = new \OCA\Files_Sharing\External\Cache(
$this->storage,
'http://example.com/owncloud',
$this->remoteUser
$this->cloudIdManager->getCloudId($this->remoteUser, 'http://example.com/owncloud')
);
$this->cache->put(
'test.txt',

View File

@ -25,6 +25,7 @@
namespace OCA\Files_Sharing\Tests\External;
use OC\Federation\CloudIdManager;
use OC\Files\Storage\StorageFactory;
use OCA\FederatedFileSharing\DiscoveryManager;
use OCA\Files_Sharing\External\Manager;
@ -84,7 +85,7 @@ class ManagerTest extends TestCase {
);
$this->testMountProvider = new MountProvider(\OC::$server->getDatabaseConnection(), function() {
return $this->manager;
});
}, new CloudIdManager());
}
private function setupMounts() {

View File

@ -25,6 +25,7 @@
*/
namespace OCA\Files_Sharing\Tests;
use OC\Federation\CloudId;
use OCP\Http\Client\IClient;
use OCP\Http\Client\IClientService;
use OCP\Http\Client\IResponse;
@ -90,6 +91,7 @@ class ExternalStorageTest extends \Test\TestCase {
return new TestSharingExternalStorage(
array(
'cloudId' => new CloudId('testOwner@' . $uri, 'testOwner', $uri),
'remote' => $uri,
'owner' => 'testOwner',
'mountpoint' => 'remoteshare',

View File

@ -98,6 +98,8 @@ return array(
'OCP\\Encryption\\IFile' => $baseDir . '/lib/public/Encryption/IFile.php',
'OCP\\Encryption\\IManager' => $baseDir . '/lib/public/Encryption/IManager.php',
'OCP\\Encryption\\Keys\\IStorage' => $baseDir . '/lib/public/Encryption/Keys/IStorage.php',
'OCP\\Federation\\ICloudId' => $baseDir . '/lib/public/Federation/ICloudId.php',
'OCP\\Federation\\ICloudIdManager' => $baseDir . '/lib/public/Federation/ICloudIdManager.php',
'OCP\\Files' => $baseDir . '/lib/public/Files.php',
'OCP\\Files\\AlreadyExistsException' => $baseDir . '/lib/public/Files/AlreadyExistsException.php',
'OCP\\Files\\Cache\\ICache' => $baseDir . '/lib/public/Files/Cache/ICache.php',
@ -497,6 +499,8 @@ return array(
'OC\\Encryption\\Manager' => $baseDir . '/lib/private/Encryption/Manager.php',
'OC\\Encryption\\Update' => $baseDir . '/lib/private/Encryption/Update.php',
'OC\\Encryption\\Util' => $baseDir . '/lib/private/Encryption/Util.php',
'OC\\Federation\\CloudId' => $baseDir . '/lib/private/Federation/CloudId.php',
'OC\\Federation\\CloudIdManager' => $baseDir . '/lib/private/Federation/CloudIdManager.php',
'OC\\Files\\AppData\\AppData' => $baseDir . '/lib/private/Files/AppData/AppData.php',
'OC\\Files\\AppData\\Factory' => $baseDir . '/lib/private/Files/AppData/Factory.php',
'OC\\Files\\Cache\\Cache' => $baseDir . '/lib/private/Files/Cache/Cache.php',

View File

@ -128,6 +128,8 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OCP\\Encryption\\IFile' => __DIR__ . '/../../..' . '/lib/public/Encryption/IFile.php',
'OCP\\Encryption\\IManager' => __DIR__ . '/../../..' . '/lib/public/Encryption/IManager.php',
'OCP\\Encryption\\Keys\\IStorage' => __DIR__ . '/../../..' . '/lib/public/Encryption/Keys/IStorage.php',
'OCP\\Federation\\ICloudId' => __DIR__ . '/../../..' . '/lib/public/Federation/ICloudId.php',
'OCP\\Federation\\ICloudIdManager' => __DIR__ . '/../../..' . '/lib/public/Federation/ICloudIdManager.php',
'OCP\\Files' => __DIR__ . '/../../..' . '/lib/public/Files.php',
'OCP\\Files\\AlreadyExistsException' => __DIR__ . '/../../..' . '/lib/public/Files/AlreadyExistsException.php',
'OCP\\Files\\Cache\\ICache' => __DIR__ . '/../../..' . '/lib/public/Files/Cache/ICache.php',
@ -527,6 +529,8 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Encryption\\Manager' => __DIR__ . '/../../..' . '/lib/private/Encryption/Manager.php',
'OC\\Encryption\\Update' => __DIR__ . '/../../..' . '/lib/private/Encryption/Update.php',
'OC\\Encryption\\Util' => __DIR__ . '/../../..' . '/lib/private/Encryption/Util.php',
'OC\\Federation\\CloudId' => __DIR__ . '/../../..' . '/lib/private/Federation/CloudId.php',
'OC\\Federation\\CloudIdManager' => __DIR__ . '/../../..' . '/lib/private/Federation/CloudIdManager.php',
'OC\\Files\\AppData\\AppData' => __DIR__ . '/../../..' . '/lib/private/Files/AppData/AppData.php',
'OC\\Files\\AppData\\Factory' => __DIR__ . '/../../..' . '/lib/private/Files/AppData/Factory.php',
'OC\\Files\\Cache\\Cache' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Cache.php',

View File

@ -0,0 +1,76 @@
<?php
/**
* @copyright Copyright (c) 2017, Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* 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 OC\Federation;
use OCP\Federation\ICloudId;
class CloudId implements ICloudId {
/** @var string */
private $id;
/** @var string */
private $user;
/** @var string */
private $remote;
/**
* CloudId constructor.
*
* @param string $id
* @param string $user
* @param string $remote
*/
public function __construct($id, $user, $remote) {
$this->id = $id;
$this->user = $user;
$this->remote = $remote;
}
/**
* The full remote cloud id
*
* @return string
*/
public function getId() {
return $this->id;
}
public function getDisplayId() {
return str_replace('https://', '', str_replace('http://', '', $this->getId()));
}
/**
* The username on the remote server
*
* @return string
*/
public function getUser() {
return $this->user;
}
/**
* The base address of the remote server
*
* @return string
*/
public function getRemote() {
return $this->remote;
}
}

View File

@ -0,0 +1,109 @@
<?php
/**
* @copyright Copyright (c) 2017, Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* 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 OC\Federation;
use OCP\Federation\ICloudId;
use OCP\Federation\ICloudIdManager;
class CloudIdManager implements ICloudIdManager {
/**
* @param string $cloudId
* @return ICloudId
*/
public function resolveCloudId($cloudId) {
// TODO magic here to get the url and user instead of just splitting on @
if (!$this->isValidCloudId($cloudId)) {
throw new \InvalidArgumentException('Invalid cloud id');
}
// Find the first character that is not allowed in user names
$id = $this->fixRemoteURL($cloudId);
$posSlash = strpos($id, '/');
$posColon = strpos($id, ':');
if ($posSlash === false && $posColon === false) {
$invalidPos = strlen($id);
} else if ($posSlash === false) {
$invalidPos = $posColon;
} else if ($posColon === false) {
$invalidPos = $posSlash;
} else {
$invalidPos = min($posSlash, $posColon);
}
// Find the last @ before $invalidPos
$pos = $lastAtPos = 0;
while ($lastAtPos !== false && $lastAtPos <= $invalidPos) {
$pos = $lastAtPos;
$lastAtPos = strpos($id, '@', $pos + 1);
}
if ($pos !== false) {
$user = substr($id, 0, $pos);
$remote = substr($id, $pos + 1);
if (!empty($user) && !empty($remote)) {
return new CloudId($id, $user, $remote);
}
}
throw new \InvalidArgumentException('Invalid cloud id');
}
/**
* @param string $user
* @param string $remote
* @return CloudId
*/
public function getCloudId($user, $remote) {
// TODO check what the correct url is for remote (asking the remote)
return new CloudId($user. '@' . $remote, $user, $remote);
}
/**
* Strips away a potential file names and trailing slashes:
* - http://localhost
* - http://localhost/
* - http://localhost/index.php
* - http://localhost/index.php/s/{shareToken}
*
* all return: http://localhost
*
* @param string $remote
* @return string
*/
protected function fixRemoteURL($remote) {
$remote = str_replace('\\', '/', $remote);
if ($fileNamePosition = strpos($remote, '/index.php')) {
$remote = substr($remote, 0, $fileNamePosition);
}
$remote = rtrim($remote, '/');
return $remote;
}
/**
* @param string $cloudId
* @return bool
*/
public function isValidCloudId($cloudId) {
return strpos($cloudId, '@') !== false;
}
}

View File

@ -52,6 +52,7 @@ use OC\Diagnostics\EventLogger;
use OC\Diagnostics\NullEventLogger;
use OC\Diagnostics\NullQueryLogger;
use OC\Diagnostics\QueryLogger;
use OC\Federation\CloudIdManager;
use OC\Files\Config\UserMountCache;
use OC\Files\Config\UserMountCacheListener;
use OC\Files\Mount\CacheMountProvider;
@ -90,6 +91,7 @@ use OC\Security\TrustedDomainHelper;
use OC\Session\CryptoWrapper;
use OC\Tagging\TagMapper;
use OCA\Theming\ThemingDefaults;
use OCP\Federation\ICloudIdManager;
use OCP\Authentication\LoginCredentials\IStore;
use OCP\IL10N;
use OCP\IServerContainer;
@ -825,6 +827,10 @@ class Server extends ServerContainer implements IServerContainer {
return new LockdownManager();
});
$this->registerService(ICloudIdManager::class, function (Server $c) {
return new CloudIdManager();
});
/* To trick DI since we don't extend the DIContainer here */
$this->registerService(CleanPreviewsBackgroundJob::class, function (Server $c) {
return new CleanPreviewsBackgroundJob(
@ -1570,4 +1576,11 @@ class Server extends ServerContainer implements IServerContainer {
public function getLockdownManager() {
return $this->query('LockdownManager');
}
/**
* @return \OCP\Federation\ICloudIdManager
*/
public function getCloudIdManager() {
return $this->query(ICloudIdManager::class);
}
}

View File

@ -249,46 +249,14 @@ class Helper extends \OC\Share\Constants {
* @throws HintException
*/
public static function splitUserRemote($id) {
if (strpos($id, '@') === false) {
try {
$cloudId = \OC::$server->getCloudIdManager()->resolveCloudId($id);
return [$cloudId->getUser(), $cloudId->getRemote()];
} catch (\InvalidArgumentException $e) {
$l = \OC::$server->getL10N('core');
$hint = $l->t('Invalid Federated Cloud ID');
throw new HintException('Invalid Federated Cloud ID', $hint);
throw new HintException('Invalid Federated Cloud ID', $hint, 0, $e);
}
// Find the first character that is not allowed in user names
$id = str_replace('\\', '/', $id);
$posSlash = strpos($id, '/');
$posColon = strpos($id, ':');
if ($posSlash === false && $posColon === false) {
$invalidPos = strlen($id);
} else if ($posSlash === false) {
$invalidPos = $posColon;
} else if ($posColon === false) {
$invalidPos = $posSlash;
} else {
$invalidPos = min($posSlash, $posColon);
}
// Find the last @ before $invalidPos
$pos = $lastAtPos = 0;
while ($lastAtPos !== false && $lastAtPos <= $invalidPos) {
$pos = $lastAtPos;
$lastAtPos = strpos($id, '@', $pos + 1);
}
if ($pos !== false) {
$user = substr($id, 0, $pos);
$remote = substr($id, $pos + 1);
$remote = self::fixRemoteURL($remote);
if (!empty($user) && !empty($remote)) {
return array($user, $remote);
}
}
$l = \OC::$server->getL10N('core');
$hint = $l->t('Invalid Federated Cloud ID');
throw new HintException('Invalid Fededrated Cloud ID', $hint);
}
/**

View File

@ -96,7 +96,8 @@ class ProviderFactory implements IProviderFactory {
$l = $this->serverContainer->getL10N('federatedfilessharing');
$addressHandler = new AddressHandler(
$this->serverContainer->getURLGenerator(),
$l
$l,
$this->serverContainer->getCloudIdManager()
);
$discoveryManager = new DiscoveryManager(
$this->serverContainer->getMemCacheFactory(),
@ -121,7 +122,8 @@ class ProviderFactory implements IProviderFactory {
$this->serverContainer->getLogger(),
$this->serverContainer->getLazyRootFolder(),
$this->serverContainer->getConfig(),
$this->serverContainer->getUserManager()
$this->serverContainer->getUserManager(),
$this->serverContainer->getCloudIdManager()
);
}

View File

@ -411,7 +411,8 @@ class User implements IUser {
public function getCloudId() {
$uid = $this->getUID();
$server = $this->urlGenerator->getAbsoluteURL('/');
return $uid . '@' . rtrim( $this->removeProtocolFromUrl($server), '/');
$server = rtrim( $this->removeProtocolFromUrl($server), '/');
return \OC::$server->getCloudIdManager()->getCloudId($uid, $server)->getId();
}
/**

View File

@ -0,0 +1,60 @@
<?php
/**
* @copyright Copyright (c) 2017, Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* 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 OCP\Federation;
/**
* Parsed federated cloud id
*
* @since 12.0.0
*/
interface ICloudId {
/**
* The remote cloud id
*
* @return string
* @since 12.0.0
*/
public function getId();
/**
* Get a clean representation of the cloud id for display
*
* @return string
* @since 12.0.0
*/
public function getDisplayId();
/**
* The username on the remote server
*
* @return string
* @since 12.0.0
*/
public function getUser();
/**
* The base address of the remote server
*
* @return string
* @since 12.0.0
*/
public function getRemote();
}

View File

@ -0,0 +1,57 @@
<?php
/**
* @copyright Copyright (c) 2017, Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* 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 OCP\Federation;
/**
* Interface for resolving federated cloud ids
*
* @since 12.0.0
*/
interface ICloudIdManager {
/**
* @param string $cloudId
* @return ICloudId
*
* @since 12.0.0
*/
public function resolveCloudId($cloudId);
/**
* Get the cloud id for a remote user
*
* @param string $user
* @param string $remote
* @return ICloudId
*
* @since 12.0.0
*/
public function getCloudId($user, $remote);
/**
* Check if the input is a correctly formatted cloud id
*
* @param string $cloudId
* @return bool
*
* @since 12.0.0
*/
public function isValidCloudId($cloudId);
}

View File

@ -525,4 +525,10 @@ interface IServerContainer {
* @since 8.0.0
*/
public function getDateTimeFormatter();
/**
* @return \OCP\Federation\ICloudIdManager
* @since 12.0.0
*/
public function getCloudIdManager();
}

View File

@ -90,6 +90,7 @@ try {
} catch (\OC\User\LoginException $e) {
OC_API::respond(new OC_OCS_Result(null, \OCP\API::RESPOND_UNAUTHORISED, 'Unauthorised'));
} catch (\Exception $e) {
\OC::$server->getLogger()->logException($e);
OC_API::setContentType();
OC_OCS::notFound();
}

View File

@ -0,0 +1,99 @@
<?php
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @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\Federation;
use OC\Federation\CloudIdManager;
use Test\TestCase;
class CloudIdManagerTest extends TestCase {
/** @var CloudIdManager */
private $cloudIdManager;
protected function setUp() {
parent::setUp();
$this->cloudIdManager = new CloudIdManager();
}
public function cloudIdProvider() {
return [
['test@example.com', 'test', 'example.com', 'test@example.com'],
['test@example.com/cloud', 'test', 'example.com/cloud', 'test@example.com/cloud'],
['test@example.com/cloud/', 'test', 'example.com/cloud', 'test@example.com/cloud'],
['test@example.com/cloud/index.php', 'test', 'example.com/cloud', 'test@example.com/cloud'],
['test@example.com@example.com', 'test@example.com', 'example.com', 'test@example.com@example.com'],
];
}
/**
* @dataProvider cloudIdProvider
*
* @param string $cloudId
* @param string $user
* @param string $remote
*/
public function testResolveCloudId($cloudId, $user, $remote, $cleanId) {
$cloudId = $this->cloudIdManager->resolveCloudId($cloudId);
$this->assertEquals($user, $cloudId->getUser());
$this->assertEquals($remote, $cloudId->getRemote());
$this->assertEquals($cleanId, $cloudId->getId());
}
public function invalidCloudIdProvider() {
return [
['example.com'],
['test:foo@example.com'],
['test/foo@example.com']
];
}
/**
* @dataProvider invalidCloudIdProvider
*
* @param string $cloudId
*
* @expectedException \InvalidArgumentException
*/
public function testInvalidCloudId($cloudId) {
$this->cloudIdManager->resolveCloudId($cloudId);
}
public function getCloudIdProvider() {
return [
['test', 'example.com', 'test@example.com'],
['test@example.com', 'example.com', 'test@example.com@example.com'],
];
}
/**
* @dataProvider getCloudIdProvider
*
* @param string $user
* @param string $remote
* @param string $id
*/
public function testGetCloudId($user, $remote, $id) {
$cloudId = $this->cloudIdManager->getCloudId($user, $remote);
$this->assertEquals($id, $cloudId->getId());
}
}

View File

@ -0,0 +1,46 @@
<?php
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @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\Federation;
use OC\Federation\CloudId;
use Test\TestCase;
class CloudIdTest extends TestCase {
public function testGetDisplayCloudIdProvider() {
return [
['test@example.com', 'test@example.com'],
['test@http://example.com', 'test@example.com'],
['test@https://example.com', 'test@example.com'],
];
}
/**
* @dataProvider testGetDisplayCloudIdProvider
*
* @param string $id
* @param string $display
*/
public function testGetDisplayCloudId($id, $display) {
$cloudId = new CloudId($id, '', '');
$this->assertEquals($display, $cloudId->getDisplayId());
}
}