aboutsummaryrefslogtreecommitdiffstats
path: root/apps/federatedfilesharing/lib
diff options
context:
space:
mode:
authorBjörn Schießle <schiessle@owncloud.com>2016-05-04 15:26:30 +0200
committerBjörn Schießle <schiessle@owncloud.com>2016-05-20 21:15:11 +0200
commitd23df4cba770c9b49bb6c7820cc865a137667922 (patch)
tree7657db0a6251426cc3ecccec8228ee9040aa1fbd /apps/federatedfilesharing/lib
parent8f87e1104d37063ff561a69348f725a2b907b9f5 (diff)
downloadnextcloud-server-d23df4cba770c9b49bb6c7820cc865a137667922.tar.gz
nextcloud-server-d23df4cba770c9b49bb6c7820cc865a137667922.zip
create re-share by owner and propagate unshare and unshare-from self request
correctly accross share owner and share initiator
Diffstat (limited to 'apps/federatedfilesharing/lib')
-rw-r--r--apps/federatedfilesharing/lib/BackgroundJob/RetryJob.php (renamed from apps/federatedfilesharing/lib/BackgroundJob/UnShare.php)32
-rw-r--r--apps/federatedfilesharing/lib/FederatedShareProvider.php213
-rw-r--r--apps/federatedfilesharing/lib/Notifications.php135
-rw-r--r--apps/federatedfilesharing/lib/RequestHandler.php284
4 files changed, 591 insertions, 73 deletions
diff --git a/apps/federatedfilesharing/lib/BackgroundJob/UnShare.php b/apps/federatedfilesharing/lib/BackgroundJob/RetryJob.php
index b056db4eac7..109a607bff0 100644
--- a/apps/federatedfilesharing/lib/BackgroundJob/UnShare.php
+++ b/apps/federatedfilesharing/lib/BackgroundJob/RetryJob.php
@@ -32,26 +32,26 @@ use OCP\BackgroundJob\IJobList;
use OCP\ILogger;
/**
- * Class UnShare
+ * Class RetryJob
*
- * Background job to re-send the un-share notification to the remote server in
+ * Background job to re-send update of federated re-shares to the remote server in
* case the server was not available on the first try
*
* @package OCA\FederatedFileSharing\BackgroundJob
*/
-class UnShare extends Job {
+class RetryJob extends Job {
/** @var bool */
private $retainJob = true;
-
+
/** @var Notifications */
private $notifications;
- /** @var int max number of attempts to send the un-share request */
- private $maxTry = 10;
+ /** @var int max number of attempts to send the request */
+ private $maxTry = 20;
- /** @var int how much time should be between two tries (12 hours) */
- private $interval = 43200;
+ /** @var int how much time should be between two tries (10 minutes) */
+ private $interval = 600;
/**
* UnShare constructor.
@@ -77,7 +77,7 @@ class UnShare extends Job {
\OC::$server->getJobList()
);
}
-
+
}
/**
@@ -99,12 +99,14 @@ class UnShare extends Job {
protected function run($argument) {
$remote = $argument['remote'];
- $id = (int)$argument['id'];
+ $remoteId = $argument['remoteId'];
$token = $argument['token'];
+ $action = $argument['action'];
+ $data = json_decode($argument['data'], true);
$try = (int)$argument['try'] + 1;
- $result = $this->notifications->sendRemoteUnShare($remote, $id, $token, $try);
-
+ $result = $this->notifications->sendUpdateToRemote($remote, $remoteId, $token, $action, $data, $try);
+
if ($result === true || $try > $this->maxTry) {
$this->retainJob = false;
}
@@ -117,11 +119,13 @@ class UnShare extends Job {
* @param array $argument
*/
protected function reAddJob(IJobList $jobList, array $argument) {
- $jobList->add('OCA\FederatedFileSharing\BackgroundJob\UnShare',
+ $jobList->add('OCA\FederatedFileSharing\BackgroundJob\RetryJob',
[
'remote' => $argument['remote'],
- 'id' => $argument['id'],
+ 'remoteId' => $argument['remoteId'],
'token' => $argument['token'],
+ 'data' => $argument['data'],
+ 'action' => $argument['action'],
'try' => (int)$argument['try'] + 1,
'lastRun' => time()
]
diff --git a/apps/federatedfilesharing/lib/FederatedShareProvider.php b/apps/federatedfilesharing/lib/FederatedShareProvider.php
index d014a6219a3..590c61559bf 100644
--- a/apps/federatedfilesharing/lib/FederatedShareProvider.php
+++ b/apps/federatedfilesharing/lib/FederatedShareProvider.php
@@ -23,6 +23,7 @@
namespace OCA\FederatedFileSharing;
+use OC\Files\View;
use OC\Share20\Share;
use OCP\Files\IRootFolder;
use OCP\IAppConfig;
@@ -70,6 +71,9 @@ class FederatedShareProvider implements IShareProvider {
/** @var IConfig */
private $config;
+ /** @var string */
+ private $externalShareTable = 'share_external';
+
/**
* DefaultShareProvider constructor.
*
@@ -127,7 +131,7 @@ class FederatedShareProvider implements IShareProvider {
$uidOwner = $share->getShareOwner();
$permissions = $share->getPermissions();
$sharedBy = $share->getSharedBy();
-
+
/*
* Check if file is not already shared with the remote user
*/
@@ -151,19 +155,42 @@ class FederatedShareProvider implements IShareProvider {
throw new \Exception($message_t);
}
- $token = $this->tokenHandler->generateToken();
-
$shareWith = $user . '@' . $remote;
- $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token);
+ try {
+ $remoteShare = $this->getShareFromExternalShareTable($share);
+ } catch (ShareNotFound $e) {
+ $remoteShare = null;
+ }
- $send = $this->notifications->sendRemoteShare(
- $token,
- $shareWith,
- $share->getNode()->getName(),
- $shareId,
- $share->getSharedBy()
- );
+ if ($remoteShare) {
+ $uidOwner = $remoteShare['owner'] . '@' . $remoteShare['remote'];
+ $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, 'tmp_token_' . time());
+ list($token, $remoteId) = $this->askOwnerToReShare($shareWith, $share, $shareId);
+ // remote share was create successfully if we get a valid token as return
+ $send = is_string($token) && $token !== '';
+ if ($send) {
+ $this->updateSuccessfulReshare($shareId, $token);
+ $this->storeRemoteId($shareId, $remoteId);
+ }
+ } else {
+ $token = $this->tokenHandler->generateToken();
+ $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token);
+ $sharedByFederatedId = $share->getSharedBy();
+ if ($this->userManager->userExists($sharedByFederatedId)) {
+ $sharedByFederatedId = $sharedByFederatedId . '@' . $this->addressHandler->generateRemoteURL();
+ }
+ $send = $this->notifications->sendRemoteShare(
+ $token,
+ $shareWith,
+ $share->getNode()->getName(),
+ $shareId,
+ $share->getShareOwner(),
+ $share->getShareOwner() . '@' . $this->addressHandler->generateRemoteURL(),
+ $share->getSharedBy(),
+ $sharedByFederatedId
+ );
+ }
$data = $this->getRawShare($shareId);
$share = $this->createShare($data);
@@ -179,6 +206,53 @@ class FederatedShareProvider implements IShareProvider {
}
/**
+ * @param string $shareWith
+ * @param IShare $share
+ * @param string $shareId internal share Id
+ * @return array
+ * @throws \Exception
+ */
+ protected function askOwnerToReShare($shareWith, IShare $share, $shareId) {
+
+ $remoteShare = $this->getShareFromExternalShareTable($share);
+ $token = $remoteShare['share_token'];
+ $remoteId = $remoteShare['remote_id'];
+ $remote = $remoteShare['remote'];
+
+ list($token, $remoteId) = $this->notifications->requestReShare(
+ $token,
+ $remoteId,
+ $shareId,
+ $remote,
+ $shareWith,
+ $share->getPermissions()
+ );
+
+ return [$token, $remoteId];
+ }
+
+ /**
+ * get federated share from the share_external table but exclude mounted link shares
+ *
+ * @param IShare $share
+ * @return array
+ * @throws ShareNotFound
+ */
+ protected function getShareFromExternalShareTable(IShare $share) {
+ $query = $this->dbConnection->getQueryBuilder();
+ $query->select('*')->from($this->externalShareTable)
+ ->where($query->expr()->eq('user', $query->createNamedParameter($share->getShareOwner())))
+ ->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget())));
+ $result = $query->execute()->fetchAll();
+
+ if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) {
+ return $result[0];
+ }
+
+ throw new ShareNotFound('share not found in share_external table');
+ }
+
+ /**
* add share to the database and return the ID
*
* @param int $itemSource
@@ -238,6 +312,58 @@ class FederatedShareProvider implements IShareProvider {
}
/**
+ * update successful reShare with the correct token
+ *
+ * @param int $shareId
+ * @param string $token
+ */
+ protected function updateSuccessfulReShare($shareId, $token) {
+ $query = $this->dbConnection->getQueryBuilder();
+ $query->update('share')
+ ->where($query->expr()->eq('id', $query->createNamedParameter($shareId)))
+ ->set('token', $query->createNamedParameter($token))
+ ->execute();
+ }
+
+ /**
+ * store remote ID in federated reShare table
+ *
+ * @param $shareId
+ * @param $remoteId
+ */
+ public function storeRemoteId($shareId, $remoteId) {
+ $query = $this->dbConnection->getQueryBuilder();
+ $query->insert('federated_reshares')
+ ->values(
+ [
+ 'share_id' => $query->createNamedParameter($shareId),
+ 'remote_id' => $query->createNamedParameter($remoteId),
+ ]
+ );
+ $query->execute();
+ }
+
+ /**
+ * get share ID on remote server for federated re-shares
+ *
+ * @param IShare $share
+ * @return int
+ * @throws ShareNotFound
+ */
+ public function getRemoteId(IShare $share) {
+ $query = $this->dbConnection->getQueryBuilder();
+ $query->select('remote_id')->from('federated_reshares')
+ ->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId())));
+ $data = $query->execute()->fetch();
+
+ if (!is_array($data) || !isset($data['remote_id'])) {
+ throw new ShareNotFound();
+ }
+
+ return (int)$data['remote_id'];
+ }
+
+ /**
* @inheritdoc
*/
public function move(IShare $share, $recipient) {
@@ -274,18 +400,77 @@ class FederatedShareProvider implements IShareProvider {
}
/**
- * Delete a share
+ * Delete a share (owner unShares the file)
*
* @param IShare $share
*/
public function delete(IShare $share) {
+
+ list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedWith());
+
+ $isOwner = false;
+
+ // if the local user is the owner we can send the unShare request directly...
+ if ($this->userManager->userExists($share->getShareOwner())) {
+ $this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken());
+ $this->revokeShare($share, true);
+ $isOwner = true;
+ } else { // ... if not we need to correct ID for the unShare request
+ $remoteId = $this->getRemoteId($share);
+ $this->notifications->sendRemoteUnShare($remote, $remoteId, $share->getToken());
+ $this->revokeShare($share, false);
+ }
+
+ // send revoke notification to the other user, if initiator and owner are not the same user
+ if ($share->getShareOwner() !== $share->getSharedBy()) {
+ $remoteId = $this->getRemoteId($share);
+ if ($isOwner) {
+ list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
+ } else {
+ list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
+ }
+ $this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken());
+ }
+
+ $this->removeShareFromTable($share);
+ }
+
+ /**
+ * in case of a re-share we need to send the other use (initiator or owner)
+ * a message that the file was unshared
+ *
+ * @param IShare $share
+ * @param bool $isOwner the user can either be the owner or the user who re-sahred it
+ * @throws ShareNotFound
+ * @throws \OC\HintException
+ */
+ protected function revokeShare($share, $isOwner) {
+ // also send a unShare request to the initiator, if this is a different user than the owner
+ if ($share->getShareOwner() !== $share->getSharedBy()) {
+ if ($isOwner) {
+ list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
+ } else {
+ list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner());
+ }
+ $remoteId = $this->getRemoteId($share);
+ $this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken());
+ }
+ }
+
+ /**
+ * remove share from table
+ *
+ * @param IShare $share
+ */
+ public function removeShareFromTable(IShare $share) {
$qb = $this->dbConnection->getQueryBuilder();
$qb->delete('share')
->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())));
$qb->execute();
- list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedWith());
- $this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken());
+ $qb->delete('federated_reshares')
+ ->where($qb->expr()->eq('share_id', $qb->createNamedParameter($share->getId())));
+ $qb->execute();
}
/**
diff --git a/apps/federatedfilesharing/lib/Notifications.php b/apps/federatedfilesharing/lib/Notifications.php
index 9cdc7760361..c65da212aad 100644
--- a/apps/federatedfilesharing/lib/Notifications.php
+++ b/apps/federatedfilesharing/lib/Notifications.php
@@ -67,9 +67,14 @@ class Notifications {
* @param string $name
* @param int $remote_id
* @param string $owner
+ * @param string $ownerFederatedId
+ * @param string $sharedBy
+ * @param string $sharedByFederatedId
* @return bool
+ * @throws \OC\HintException
+ * @throws \OC\ServerNotAvailableException
*/
- public function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner) {
+ public function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner, $ownerFederatedId, $sharedBy, $sharedByFederatedId) {
list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith);
@@ -83,6 +88,9 @@ class Notifications {
'name' => $name,
'remoteId' => $remote_id,
'owner' => $owner,
+ 'ownerFederatedId' => $ownerFederatedId,
+ 'sharedBy' => $sharedBy,
+ 'sharedByFederatedId' => $sharedByFederatedId,
'remote' => $local,
);
@@ -101,34 +109,138 @@ class Notifications {
}
/**
+ * ask owner to re-share the file with the given user
+ *
+ * @param string $token
+ * @param int $id remote Id
+ * @param int $shareId internal share Id
+ * @param string $remote remote address of the owner
+ * @param string $shareWith
+ * @param int $permission
+ * @return bool
+ * @throws \OC\HintException
+ * @throws \OC\ServerNotAvailableException
+ */
+ public function requestReShare($token, $id, $shareId, $remote, $shareWith, $permission) {
+
+ $fields = array(
+ 'shareWith' => $shareWith,
+ 'token' => $token,
+ 'permission' => $permission,
+ 'remoteId' => $shareId
+ );
+
+ $url = $this->addressHandler->removeProtocolFromUrl($remote);
+ $result = $this->tryHttpPostToShareEndpoint(rtrim($url, '/'), '/' . $id . '/reshare', $fields);
+ $status = json_decode($result['result'], true);
+
+ $httpRequestSuccessful = $result['success'];
+ $ocsCallSuccessful = $status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200;
+ $validToken = isset($status['ocs']['data']['token']) && is_string($status['ocs']['data']['token']);
+ $validRemoteId = isset($status['ocs']['data']['remoteId']);
+
+ if ($httpRequestSuccessful && $ocsCallSuccessful && $validToken && $validRemoteId) {
+ return [
+ $status['ocs']['data']['token'],
+ (int)$status['ocs']['data']['remoteId']
+ ];
+ }
+
+ return false;
+ }
+
+ /**
+ * send server-to-server unshare to remote server
+ *
+ * @param string $remote url
+ * @param int $id share id
+ * @param string $token
+ * @return bool
+ */
+ public function sendRemoteUnShare($remote, $id, $token) {
+ $this->sendUpdateToRemote($remote, $id, $token, 'unshare');
+ }
+
+ /**
* send server-to-server unshare to remote server
*
* @param string $remote url
* @param int $id share id
* @param string $token
- * @param int $try how often did we already tried to send the un-share request
* @return bool
*/
- public function sendRemoteUnShare($remote, $id, $token, $try = 0) {
- $url = rtrim($remote, '/');
- $fields = array('token' => $token, 'format' => 'json');
- $url = $this->addressHandler->removeProtocolFromUrl($url);
- $result = $this->tryHttpPostToShareEndpoint($url, '/'.$id.'/unshare', $fields);
+ public function sendRevokeShare($remote, $id, $token) {
+ $this->sendUpdateToRemote($remote, $id, $token, 'revoke');
+ }
+
+ /**
+ * send notification to remote server if the permissions was changed
+ *
+ * @param string $remote
+ * @param int $remoteId
+ * @param string $token
+ * @param int $permissions
+ * @return bool
+ */
+ public function sendPermissionChange($remote, $remoteId, $token, $permissions) {
+ $this->sendUpdateToRemote($remote, $remoteId, $token, ['permissions' => $permissions]);
+ }
+
+ /**
+ * forward accept reShare to remote server
+ *
+ * @param string $remote
+ * @param int $remoteId
+ * @param string $token
+ */
+ public function sendAcceptShare($remote, $remoteId, $token) {
+ $this->sendUpdateToRemote($remote, $remoteId, $token, 'accept');
+ }
+
+ /**
+ * forward decline reShare to remote server
+ *
+ * @param string $remote
+ * @param int $remoteId
+ * @param string $token
+ */
+ public function sendDeclineShare($remote, $remoteId, $token) {
+ $this->sendUpdateToRemote($remote, $remoteId, $token, 'decline');
+ }
+
+ /**
+ * inform remote server whether server-to-server share was accepted/declined
+ *
+ * @param string $remote
+ * @param string $token
+ * @param int $remoteId Share id on the remote host
+ * @param string $action possible actions: accept, decline, unshare, revoke, permissions
+ * @param array $data
+ * @param int $try
+ * @return boolean
+ */
+ public function sendUpdateToRemote($remote, $remoteId, $token, $action, $data = [], $try = 0) {
+
+ $fields = array('token' => $token);
+ $url = $this->addressHandler->removeProtocolFromUrl($remote);
+ $result = $this->tryHttpPostToShareEndpoint(rtrim($url, '/'), '/' . $remoteId . '/' . $action, $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
)
) {
return true;
} elseif ($try === 0) {
// only add new job on first try
- $this->jobList->add('OCA\FederatedFileSharing\BackgroundJob\UnShare',
+ $this->jobList->add('OCA\FederatedFileSharing\BackgroundJob\RetryJob',
[
'remote' => $remote,
- 'id' => $id,
+ 'remoteId' => $remoteId,
'token' => $token,
+ 'action' => $action,
+ 'data' => json_encode($data),
'try' => $try,
'lastRun' => $this->getTimestamp()
]
@@ -138,6 +250,7 @@ class Notifications {
return false;
}
+
/**
* return current timestamp
*
diff --git a/apps/federatedfilesharing/lib/RequestHandler.php b/apps/federatedfilesharing/lib/RequestHandler.php
index 90621666b6a..b6630496dcb 100644
--- a/apps/federatedfilesharing/lib/RequestHandler.php
+++ b/apps/federatedfilesharing/lib/RequestHandler.php
@@ -25,11 +25,14 @@
namespace OCA\FederatedFileSharing;
-use OCA\FederatedFileSharing\DiscoveryManager;
-use OCA\FederatedFileSharing\FederatedShareProvider;
use OCA\Files_Sharing\Activity;
+use OCP\AppFramework\Http;
+use OCP\Constants;
use OCP\Files\NotFoundException;
use OCP\IDBConnection;
+use OCP\IRequest;
+use OCP\IUserManager;
+use OCP\Share;
/**
* Class RequestHandler
@@ -46,6 +49,21 @@ class RequestHandler {
/** @var IDBConnection */
private $connection;
+ /** @var Share\IManager */
+ private $shareManager;
+
+ /** @var IRequest */
+ private $request;
+
+ /** @var Notifications */
+ private $notifications;
+
+ /** @var AddressHandler */
+ private $addressHandler;
+
+ /** @var IUserManager */
+ private $userManager;
+
/** @var string */
private $shareTable = 'share';
@@ -54,10 +72,27 @@ class RequestHandler {
*
* @param FederatedShareProvider $federatedShareProvider
* @param IDBConnection $connection
+ * @param Share\IManager $shareManager
+ * @param IRequest $request
+ * @param Notifications $notifications
+ * @param AddressHandler $addressHandler
+ * @param IUserManager $userManager
*/
- public function __construct(FederatedShareProvider $federatedShareProvider, IDBConnection $connection) {
+ public function __construct(FederatedShareProvider $federatedShareProvider,
+ IDBConnection $connection,
+ Share\IManager $shareManager,
+ IRequest $request,
+ Notifications $notifications,
+ AddressHandler $addressHandler,
+ IUserManager $userManager
+ ) {
$this->federatedShareProvider = $federatedShareProvider;
$this->connection = $connection;
+ $this->shareManager = $shareManager;
+ $this->request = $request;
+ $this->notifications = $notifications;
+ $this->addressHandler = $addressHandler;
+ $this->userManager = $userManager;
}
/**
@@ -76,8 +111,11 @@ class RequestHandler {
$token = isset($_POST['token']) ? $_POST['token'] : null;
$name = isset($_POST['name']) ? $_POST['name'] : null;
$owner = isset($_POST['owner']) ? $_POST['owner'] : null;
+ $sharedBy = isset($_POST['sharedBy']) ? $_POST['sharedBy'] : null;
$shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null;
$remoteId = isset($_POST['remoteId']) ? (int)$_POST['remoteId'] : null;
+ $sharedByFederatedId = isset($_POST['sharedByFederatedId']) ? $_POST['sharedByFederatedId'] : null;
+ $ownerFederatedId = isset($_POST['ownerFederatedId']) ? $_POST['ownerFederatedId'] : null;
if ($remote && $token && $name && $owner && $remoteId && $shareWith) {
@@ -118,10 +156,17 @@ class RequestHandler {
$externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId);
$shareId = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share_external');
- $user = $owner . '@' . $this->cleanupRemote($remote);
+ if ($ownerFederatedId === null) {
+ $ownerFederatedId = $owner . '@' . $this->cleanupRemote($remote);
+ }
+ // if the owner of the share and the initiator are the same user
+ // we also complete the federated share ID for the initiator
+ if ($sharedByFederatedId === null && $owner === $sharedBy) {
+ $sharedByFederatedId = $ownerFederatedId;
+ }
\OC::$server->getActivityManager()->publishActivity(
- Activity::FILES_SHARING_APP, Activity::SUBJECT_REMOTE_SHARE_RECEIVED, array($user, trim($name, '/')), '', array(),
+ Activity::FILES_SHARING_APP, Activity::SUBJECT_REMOTE_SHARE_RECEIVED, array($ownerFederatedId, trim($name, '/')), '', array(),
'', '', $shareWith, Activity::TYPE_REMOTE_SHARE, Activity::PRIORITY_LOW);
$urlGenerator = \OC::$server->getURLGenerator();
@@ -132,7 +177,7 @@ class RequestHandler {
->setUser($shareWith)
->setDateTime(new \DateTime())
->setObject('remote_share', $shareId)
- ->setSubject('remote_share', [$user, trim($name, '/')]);
+ ->setSubject('remote_share', [$ownerFederatedId, $sharedByFederatedId, trim($name, '/')]);
$declineAction = $notification->createAction();
$declineAction->setLabel('decline')
@@ -157,6 +202,66 @@ class RequestHandler {
}
/**
+ * create re-share on behalf of another user
+ *
+ * @param $params
+ * @return \OC_OCS_Result
+ */
+ public function reShare($params) {
+
+ $id = isset($params['id']) ? (int)$params['id'] : null;
+ $token = $this->request->getParam('token', null);
+ $shareWith = $this->request->getParam('shareWith', null);
+ $permission = (int)$this->request->getParam('permission', null);
+ $remoteId = (int)$this->request->getParam('remoteId', null);
+
+ if ($id === null ||
+ $token === null ||
+ $shareWith === null ||
+ $permission === null ||
+ $remoteId === null
+ ) {
+ return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST);
+ }
+
+ try {
+ $share = $this->federatedShareProvider->getShareById($id);
+ } catch (Share\Exceptions\ShareNotFound $e) {
+ return new \OC_OCS_Result(null, Http::STATUS_NOT_FOUND);
+ }
+
+ // don't allow to share a file back to the owner
+ list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith);
+ $owner = $share->getShareOwner();
+ $currentServer = $this->addressHandler->generateRemoteURL();
+ if ($this->addressHandler->compareAddresses($user, $remote,$owner , $currentServer)) {
+ return new \OC_OCS_Result(null, Http::STATUS_FORBIDDEN);
+ }
+
+ if ($this->verifyShare($share, $token)) {
+
+ // check if re-sharing is allowed
+ if ($share->getPermissions() | ~Constants::PERMISSION_SHARE) {
+ $share->setPermissions($share->getPermissions() & $permission);
+ // the recipient of the initial share is now the initiator for the re-share
+ $share->setSharedBy($share->getSharedWith());
+ $share->setSharedWith($shareWith);
+ try {
+ $result = $this->federatedShareProvider->create($share);
+ $this->federatedShareProvider->storeRemoteId((int)$result->getId(), $remoteId);
+ return new \OC_OCS_Result(['token' => $result->getToken(), 'remoteId' => $result->getId()]);
+ } catch (\Exception $e) {
+ return new \OC_OCS_Result(null, Http::STATUS_INTERNAL_SERVER_ERROR);
+ }
+ } else {
+ return new \OC_OCS_Result(null, Http::STATUS_FORBIDDEN);
+ }
+ }
+ return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST);
+
+ }
+
+ /**
* accept server-to-server share
*
* @param array $params
@@ -170,24 +275,38 @@ class RequestHandler {
$id = $params['id'];
$token = isset($_POST['token']) ? $_POST['token'] : null;
- $share = $this->getShare($id, $token);
-
- if ($share) {
- list($file, $link) = $this->getFile($share['uid_owner'], $share['file_source']);
-
- $event = \OC::$server->getActivityManager()->generateEvent();
- $event->setApp(Activity::FILES_SHARING_APP)
- ->setType(Activity::TYPE_REMOTE_SHARE)
- ->setAffectedUser($share['uid_owner'])
- ->setSubject(Activity::SUBJECT_REMOTE_SHARE_ACCEPTED, [$share['share_with'], basename($file)])
- ->setObject('files', $share['file_source'], $file)
- ->setLink($link);
- \OC::$server->getActivityManager()->publish($event);
+
+ try {
+ $share = $this->federatedShareProvider->getShareById($id);
+ } catch (Share\Exceptions\ShareNotFound $e) {
+ return new \OC_OCS_Result();
+ }
+
+ if ($this->verifyShare($share, $token)) {
+ $this->executeAcceptShare($share);
+ if ($share->getShareOwner() !== $share->getSharedBy()) {
+ list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
+ $remoteId = $this->federatedShareProvider->getRemoteId($share);
+ $this->notifications->sendAcceptShare($remote, $remoteId, $share->getToken());
+ }
}
return new \OC_OCS_Result();
}
+ protected function executeAcceptShare(Share\IShare $share) {
+ list($file, $link) = $this->getFile($this->getCorrectUid($share), $share->getNode()->getId());
+
+ $event = \OC::$server->getActivityManager()->generateEvent();
+ $event->setApp(Activity::FILES_SHARING_APP)
+ ->setType(Activity::TYPE_REMOTE_SHARE)
+ ->setAffectedUser($this->getCorrectUid($share))
+ ->setSubject(Activity::SUBJECT_REMOTE_SHARE_ACCEPTED, [$share->getSharedWith(), basename($file)])
+ ->setObject('files', $share->getNode()->getId(), $file)
+ ->setLink($link);
+ \OC::$server->getActivityManager()->publish($event);
+ }
+
/**
* decline server-to-server share
*
@@ -200,28 +319,59 @@ class RequestHandler {
return new \OC_OCS_Result(null, 503, 'Server does not support federated cloud sharing');
}
- $id = $params['id'];
+ $id = (int)$params['id'];
$token = isset($_POST['token']) ? $_POST['token'] : null;
- $share = $this->getShare($id, $token);
+ try {
+ $share = $this->federatedShareProvider->getShareById($id);
+ } catch (Share\Exceptions\ShareNotFound $e) {
+ return new \OC_OCS_Result();
+ }
+
+ if($this->verifyShare($share, $token)) {
+ if ($share->getShareOwner() !== $share->getSharedBy()) {
+ list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy());
+ $remoteId = $this->federatedShareProvider->getRemoteId($share);
+ $this->notifications->sendDeclineShare($remote, $remoteId, $share->getToken());
+ }
+ $this->executeDeclineShare($share);
+ }
- if ($share) {
- // userId must be set to the user who unshares
- \OCP\Share::unshare($share['item_type'], $share['item_source'], $share['share_type'], $share['share_with'], $share['uid_owner']);
+ return new \OC_OCS_Result();
+ }
- list($file, $link) = $this->getFile($share['uid_owner'], $share['file_source']);
+ /**
+ * delete declined share and create a activity
+ *
+ * @param Share\IShare $share
+ */
+ protected function executeDeclineShare(Share\IShare $share) {
+ $this->federatedShareProvider->removeShareFromTable($share);
+ list($file, $link) = $this->getFile($this->getCorrectUid($share), $share->getNode()->getId());
+
+ $event = \OC::$server->getActivityManager()->generateEvent();
+ $event->setApp(Activity::FILES_SHARING_APP)
+ ->setType(Activity::TYPE_REMOTE_SHARE)
+ ->setAffectedUser($this->getCorrectUid($share))
+ ->setSubject(Activity::SUBJECT_REMOTE_SHARE_DECLINED, [$share->getSharedWith(), basename($file)])
+ ->setObject('files', $share->getNode()->getId(), $file)
+ ->setLink($link);
+ \OC::$server->getActivityManager()->publish($event);
- $event = \OC::$server->getActivityManager()->generateEvent();
- $event->setApp(Activity::FILES_SHARING_APP)
- ->setType(Activity::TYPE_REMOTE_SHARE)
- ->setAffectedUser($share['uid_owner'])
- ->setSubject(Activity::SUBJECT_REMOTE_SHARE_DECLINED, [$share['share_with'], basename($file)])
- ->setObject('files', $share['file_source'], $file)
- ->setLink($link);
- \OC::$server->getActivityManager()->publish($event);
+ }
+
+ /**
+ * check if we are the initiator or the owner of a re-share and return the correct UID
+ *
+ * @param Share\IShare $share
+ * @return string
+ */
+ protected function getCorrectUid(Share\IShare $share) {
+ if($this->userManager->userExists($share->getShareOwner())) {
+ return $share->getShareOwner();
}
- return new \OC_OCS_Result();
+ return $share->getSharedBy();
}
/**
@@ -281,6 +431,28 @@ class RequestHandler {
return rtrim($remote, '/');
}
+
+ /**
+ * federated share was revoked, either by the owner or the re-sharer
+ *
+ * @param $params
+ * @return \OC_OCS_Result
+ */
+ public function revoke($params) {
+ $id = (int)$params['id'];
+ $token = $this->request->getParam('token');
+
+ $share = $this->federatedShareProvider->getShareById($id);
+
+ if ($this->verifyShare($share, $token)) {
+ $this->federatedShareProvider->removeShareFromTable($share);
+ return new \OC_OCS_Result();
+ }
+
+ return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST);
+
+ }
+
/**
* get share
*
@@ -345,4 +517,48 @@ class RequestHandler {
return $result;
}
+ /**
+ * check if we got the right share
+ *
+ * @param Share\IShare $share
+ * @param string $token
+ * @return bool
+ */
+ protected function verifyShare(Share\IShare $share, $token) {
+ if (
+ $share->getShareType() === FederatedShareProvider::SHARE_TYPE_REMOTE &&
+ $share->getToken() === $token
+ ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * update share information to keep federated re-shares in sync
+ */
+ public function update() {
+ $token = $this->request->getParam('token', null);
+ $data = $this->request->getParam('data', []);
+
+ $dataArray = json_decode($data, true);
+
+ try {
+ $share = $this->federatedShareProvider->getShareByToken($token);
+ } catch (Share\Exceptions\ShareNotFound $e) {
+ return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST);
+ }
+
+ if (isset($dataArray['decline'])) {
+ $this->executeDeclineShare($share);
+ }
+
+ if (isset($dataArray['accept'])) {
+ $this->executeAcceptShare($share);
+ }
+
+ return new \OC_OCS_Result();
+ }
+
}