diff options
author | Björn Schießle <bjoern@schiessle.org> | 2014-12-19 19:04:44 +0100 |
---|---|---|
committer | Björn Schießle <bjoern@schiessle.org> | 2014-12-19 19:04:44 +0100 |
commit | 8164415b45386cb87e05e6e50cf4b8f3128b2e69 (patch) | |
tree | 1edbf481b6596533be0813d7639277fc9a92b98b /apps | |
parent | ad6814f9207ac50ad9e3e6f157ec9746c81392e9 (diff) | |
parent | 24993280edcf66f9daa5a5e82428fefef4a3ab56 (diff) | |
download | nextcloud-server-8164415b45386cb87e05e6e50cf4b8f3128b2e69.tar.gz nextcloud-server-8164415b45386cb87e05e6e50cf4b8f3128b2e69.zip |
Merge pull request #12749 from owncloud/server2server-sharing-ng
server to server sharing next generation
Diffstat (limited to 'apps')
-rw-r--r-- | apps/files_encryption/lib/hooks.php | 13 | ||||
-rw-r--r-- | apps/files_encryption/lib/util.php | 8 | ||||
-rwxr-xr-x | apps/files_encryption/tests/share.php | 99 | ||||
-rw-r--r-- | apps/files_sharing/ajax/external.php | 11 | ||||
-rw-r--r-- | apps/files_sharing/api/server2server.php | 51 | ||||
-rw-r--r-- | apps/files_sharing/appinfo/routes.php | 22 | ||||
-rw-r--r-- | apps/files_sharing/application.php | 21 | ||||
-rw-r--r-- | apps/files_sharing/js/external.js | 95 | ||||
-rw-r--r-- | apps/files_sharing/lib/activity.php | 2 | ||||
-rw-r--r-- | apps/files_sharing/lib/connector/publicauth.php | 2 | ||||
-rw-r--r-- | apps/files_sharing/lib/controllers/externalsharescontroller.php | 86 | ||||
-rw-r--r-- | apps/files_sharing/lib/external/manager.php | 136 | ||||
-rw-r--r-- | apps/files_sharing/lib/helper.php | 28 | ||||
-rw-r--r-- | apps/files_sharing/lib/share/file.php | 14 | ||||
-rw-r--r-- | apps/files_sharing/lib/updater.php | 7 | ||||
-rw-r--r-- | apps/files_sharing/tests/server2server.php | 41 |
16 files changed, 513 insertions, 123 deletions
diff --git a/apps/files_encryption/lib/hooks.php b/apps/files_encryption/lib/hooks.php index bddfb7b2544..7ddde0a3112 100644 --- a/apps/files_encryption/lib/hooks.php +++ b/apps/files_encryption/lib/hooks.php @@ -25,8 +25,6 @@ namespace OCA\Files_Encryption;
-use OC\Files\Filesystem;
-
/**
* Class for hook specific logic
*/
@@ -364,15 +362,16 @@ class Hooks { if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
$view = new \OC\Files\View('/');
- $userId = \OCP\User::getUser();
+ $userId = $params['uidOwner'];
+ $userView = new \OC\Files\View('/' . $userId . '/files');
$util = new Util($view, $userId);
- $path = \OC\Files\Filesystem::getPath($params['fileSource']);
+ $path = $userView->getPath($params['fileSource']);
// for group shares get a list of the group members
if ($params['shareType'] === \OCP\Share::SHARE_TYPE_GROUP) {
$userIds = \OC_Group::usersInGroup($params['shareWith']);
} else {
- if ($params['shareType'] === \OCP\Share::SHARE_TYPE_LINK) {
+ if ($params['shareType'] === \OCP\Share::SHARE_TYPE_LINK || $params['shareType'] === \OCP\Share::SHARE_TYPE_REMOTE) {
$userIds = array($util->getPublicShareKeyId());
} else {
$userIds = array($params['shareWith']);
@@ -619,8 +618,8 @@ class Hooks { // check if the user still has access to the file, otherwise delete share key
$sharingUsers = \OCP\Share::getUsersSharingFile($path, $user);
- if (!in_array(\OCP\User::getUser(), $sharingUsers['users'])) {
- Keymanager::delShareKey($view, array(\OCP\User::getUser()), $keyPath, $owner, $ownerPath);
+ if (!in_array($user, $sharingUsers['users'])) {
+ Keymanager::delShareKey($view, array($user), $keyPath, $owner, $ownerPath);
}
}
diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index ad6948b95a6..4aaf7aa2571 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -1207,13 +1207,7 @@ class Util { // handle public access if ($this->isPublic) { - $filename = $path; - $fileOwnerUid = $this->userId; - - return array( - $fileOwnerUid, - $filename - ); + return array($this->userId, $path); } else { // Check that UID is valid diff --git a/apps/files_encryption/tests/share.php b/apps/files_encryption/tests/share.php index 9c53c73aafa..d29e6a191c8 100755 --- a/apps/files_encryption/tests/share.php +++ b/apps/files_encryption/tests/share.php @@ -115,6 +115,91 @@ class Share extends TestCase { parent::tearDownAfterClass(); } + /** + * @medium + */ + function testDeclineServer2ServerShare() { + + $config = $this->getMockBuilder('\OCP\IConfig') + ->disableOriginalConstructor()->getMock(); + $certificateManager = $this->getMock('\OCP\ICertificateManager'); + $httpHelperMock = $this->getMockBuilder('\OC\HTTPHelper') + ->setConstructorArgs(array($config, $certificateManager)) + ->getMock(); + $httpHelperMock->expects($this->once())->method('post')->with($this->anything())->will($this->returnValue(true)); + + self::loginHelper(self::TEST_ENCRYPTION_SHARE_USER1); + + // save file with content + $cryptedFile = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename, $this->dataShort); + + // test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); + + // get the file info from previous created file + $fileInfo = $this->view->getFileInfo( + '/' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename); + + + // share the file + $token = \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, '', \OCP\Constants::PERMISSION_ALL); + $this->assertTrue(is_string($token)); + + $publicShareKeyId = \OC::$server->getConfig()->getAppValue('files_encryption', 'publicShareKeyId'); + + // check if share key for public exists + $this->assertTrue($this->view->file_exists( + '/' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/keys/' + . $this->filename . '/' . $publicShareKeyId . '.shareKey')); + + // manipulate share + $query = \OC::$server->getDatabaseConnection()->prepare('UPDATE `*PREFIX*share` SET `share_type` = ?, `share_with` = ? WHERE `token`=?'); + $this->assertTrue($query->execute(array(\OCP\Share::SHARE_TYPE_REMOTE, 'foo@bar', $token))); + + // check if share key not exists + $this->assertTrue($this->view->file_exists( + '/' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/keys/' + . $this->filename . '/' . $publicShareKeyId . '.shareKey')); + + + $query = \OC::$server->getDatabaseConnection()->prepare('SELECT * FROM `*PREFIX*share` WHERE `token`=?'); + $query->execute(array($token)); + + $share = $query->fetch(); + + $this->registerHttpHelper($httpHelperMock); + $_POST['token'] = $token; + $s2s = new \OCA\Files_Sharing\API\Server2Server(); + $s2s->declineShare(array('id' => $share['id'])); + $this->restoreHttpHelper(); + + $this->assertFalse($this->view->file_exists( + '/' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/keys/' + . $this->filename . '/' . $publicShareKeyId . '.shareKey')); + + } + + + /** + * Register an http helper mock for testing purposes. + * @param $httpHelper http helper mock + */ + private function registerHttpHelper($httpHelper) { + $this->oldHttpHelper = \OC::$server->query('HTTPHelper'); + \OC::$server->registerService('HTTPHelper', function ($c) use ($httpHelper) { + return $httpHelper; + }); + } + + /** + * Restore the original http helper + */ + private function restoreHttpHelper() { + $oldHttpHelper = $this->oldHttpHelper; + \OC::$server->registerService('HTTPHelper', function ($c) use ($oldHttpHelper) { + return $oldHttpHelper; + }); + } /** * @medium @@ -285,7 +370,7 @@ class Share extends TestCase { // save file with content $cryptedFile = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' - . $this->filename, $this->dataShort); + . $this->filename, $this->dataShort); // test that data was successfully written $this->assertTrue(is_int($cryptedFile)); @@ -677,7 +762,7 @@ class Share extends TestCase { // save file with content $cryptedFile1 = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename, $this->dataShort); $cryptedFile2 = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' - . $this->filename, $this->dataShort); + . $this->filename, $this->dataShort); // test that data was successfully written $this->assertTrue(is_int($cryptedFile1)); @@ -784,7 +869,7 @@ class Share extends TestCase { // save file with content $cryptedFile1 = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_SHARE_USER2. '/files/' . $this->filename, $this->dataShort); $cryptedFile2 = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' - . $this->filename, $this->dataShort); + . $this->filename, $this->dataShort); // test that data was successfully written $this->assertTrue(is_int($cryptedFile1)); @@ -925,8 +1010,8 @@ class Share extends TestCase { // remove share file $this->view->unlink('/' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/keys/' - . $this->filename . '/' . self::TEST_ENCRYPTION_SHARE_USER3 - . '.shareKey'); + . $this->filename . '/' . self::TEST_ENCRYPTION_SHARE_USER3 + . '.shareKey'); // re-enable the file proxy \OC_FileProxy::$enabled = $proxyStatus; @@ -990,7 +1075,7 @@ class Share extends TestCase { // move the file to a subfolder $this->view->rename('/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename, - '/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->folder1 . $this->filename); + '/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->folder1 . $this->filename); // check if we can read the moved file $retrievedRenamedFile = $this->view->file_get_contents( @@ -1122,4 +1207,4 @@ class Share extends TestCase { \OC\Files\Filesystem::unlink($folder); } -} +}
\ No newline at end of file diff --git a/apps/files_sharing/ajax/external.php b/apps/files_sharing/ajax/external.php index 6d68b5f7f82..1a709eda07c 100644 --- a/apps/files_sharing/ajax/external.php +++ b/apps/files_sharing/ajax/external.php @@ -31,10 +31,11 @@ if(!\OCP\Util::isValidFileName($name)) { } $externalManager = new \OCA\Files_Sharing\External\Manager( - \OC::$server->getDatabaseConnection(), - \OC\Files\Filesystem::getMountManager(), - \OC\Files\Filesystem::getLoader(), - \OC::$server->getUserSession() + \OC::$server->getDatabaseConnection(), + \OC\Files\Filesystem::getMountManager(), + \OC\Files\Filesystem::getLoader(), + \OC::$server->getUserSession(), + \OC::$server->getHTTPHelper() ); $name = OCP\Files::buildNotExistingFileName('/', $name); @@ -44,7 +45,7 @@ if (substr($remote, 0, 5) === 'https' and !OC_Util::getUrlContent($remote)) { \OCP\JSON::error(array('data' => array('message' => $l->t("Invalid or untrusted SSL certificate")))); exit; } else { - $mount = $externalManager->addShare($remote, $token, $password, $name, $owner); + $mount = $externalManager->addShare($remote, $token, $password, $name, $owner, true); /** * @var \OCA\Files_Sharing\External\Storage $storage */ diff --git a/apps/files_sharing/api/server2server.php b/apps/files_sharing/api/server2server.php index 2949e2dd09c..f78d64caa73 100644 --- a/apps/files_sharing/api/server2server.php +++ b/apps/files_sharing/api/server2server.php @@ -34,7 +34,7 @@ class Server2Server { public function createShare($params) { if (!$this->isS2SEnabled(true)) { - return \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing'); + return new \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing'); } $remote = isset($_POST['remote']) ? $_POST['remote'] : null; @@ -42,7 +42,7 @@ class Server2Server { $name = isset($_POST['name']) ? $_POST['name'] : null; $owner = isset($_POST['owner']) ? $_POST['owner'] : null; $shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null; - $remoteId = isset($_POST['remote_id']) ? (int)$_POST['remote_id'] : null; + $remoteId = isset($_POST['remoteId']) ? (int)$_POST['remoteId'] : null; if ($remote && $token && $name && $owner && $remoteId && $shareWith) { @@ -56,19 +56,28 @@ class Server2Server { \OC_Util::setupFS($shareWith); - $mountPoint = \OC\Files\Filesystem::normalizePath('/' . $name); + $externalManager = new \OCA\Files_Sharing\External\Manager( + \OC::$server->getDatabaseConnection(), + \OC\Files\Filesystem::getMountManager(), + \OC\Files\Filesystem::getLoader(), + \OC::$server->getUserSession(), + \OC::$server->getHTTPHelper()); + $name = \OCP\Files::buildNotExistingFileName('/', $name); try { - \OCA\Files_Sharing\Helper::addServer2ServerShare($remote, $token, $name, $mountPoint, $owner, $shareWith, '', $remoteId); + $externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId); + + $user = $owner . '@' . $this->cleanupRemote($remote); \OC::$server->getActivityManager()->publishActivity( - 'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_RECEIVED, array($owner), '', array(), - '', '', $shareWith, \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_LOW); + 'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_RECEIVED, array($user), '', array(), + '', '', $shareWith, \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_LOW); return new \OC_OCS_Result(); } catch (\Exception $e) { - return new \OC_OCS_Result(null, 500, 'server can not add remote share, ' . $e->getMessage()); + \OCP\Util::writeLog('files_sharing', 'server can not add remote share, ' . $e->getMessage(), \OCP\Util::ERROR); + return new \OC_OCS_Result(null, 500, 'internal server error, was not able to add share from ' . $remote); } } @@ -84,7 +93,7 @@ class Server2Server { public function acceptShare($params) { if (!$this->isS2SEnabled()) { - return \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing'); + return new \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing'); } $id = $params['id']; @@ -95,8 +104,8 @@ class Server2Server { list($file, $link) = self::getFile($share['uid_owner'], $share['file_source']); \OC::$server->getActivityManager()->publishActivity( - 'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_ACCEPTED, array($share['share_with'], basename($file)), '', array(), - $file, $link, $share['uid_owner'], \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_LOW); + 'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_ACCEPTED, array($share['share_with'], basename($file)), '', array(), + $file, $link, $share['uid_owner'], \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_LOW); } return new \OC_OCS_Result(); @@ -111,7 +120,7 @@ class Server2Server { public function declineShare($params) { if (!$this->isS2SEnabled()) { - return \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing'); + return new \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing'); } $id = $params['id']; @@ -126,8 +135,8 @@ class Server2Server { list($file, $link) = $this->getFile($share['uid_owner'], $share['file_source']); \OC::$server->getActivityManager()->publishActivity( - 'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_DECLINED, array($share['share_with'], basename($file)), '', array(), - $file, $link, $share['uid_owner'], \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_LOW); + 'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_DECLINED, array($share['share_with'], basename($file)), '', array(), + $file, $link, $share['uid_owner'], \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_LOW); } return new \OC_OCS_Result(); @@ -142,7 +151,7 @@ class Server2Server { public function unshare($params) { if (!$this->isS2SEnabled()) { - return \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing'); + return new \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing'); } $id = $params['id']; @@ -154,7 +163,9 @@ class Server2Server { if ($token && $id && !empty($share)) { - $owner = $share['owner'] . '@' . $share['remote']; + $remote = $this->cleanupRemote($share['remote']); + + $owner = $share['owner'] . '@' . $remote; $mountpoint = $share['mountpoint']; $user = $share['user']; @@ -162,13 +173,19 @@ class Server2Server { $query->execute(array($id, $token)); \OC::$server->getActivityManager()->publishActivity( - 'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_DECLINED, array($owner, $mountpoint), '', array(), - '', '', $user, \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_MEDIUM); + 'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_UNSHARED, array($owner, $mountpoint), '', array(), + '', '', $user, \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_MEDIUM); } return new \OC_OCS_Result(); } + private function cleanupRemote($remote) { + $remote = substr($remote, strpos($remote, '://') + 3); + + return rtrim($remote, '/'); + } + /** * get share * diff --git a/apps/files_sharing/appinfo/routes.php b/apps/files_sharing/appinfo/routes.php index 41bdf554fc5..dd9509575b7 100644 --- a/apps/files_sharing/appinfo/routes.php +++ b/apps/files_sharing/appinfo/routes.php @@ -1,5 +1,16 @@ <?php +namespace OCA\Files_Sharing\AppInfo; + +use OCA\Files_Sharing\Application; + +$application = new Application(); +$application->registerRoutes($this, [ + 'resources' => [ + 'ExternalShares' => ['url' => '/api/externalShares'], + ] +]); + /** @var $this \OCP\Route\IRouter */ $this->create('core_ajax_public_preview', '/publicpreview')->action( function() { @@ -16,31 +27,32 @@ $this->create('sharing_external_add', '/external') ->actionInclude('files_sharing/ajax/external.php'); $this->create('sharing_external_test_remote', '/testremote') ->actionInclude('files_sharing/ajax/testremote.php'); + // OCS API //TODO: SET: mail notification, waiting for PR #4689 to be accepted -OC_API::register('get', +\OC_API::register('get', '/apps/files_sharing/api/v1/shares', array('\OCA\Files_Sharing\API\Local', 'getAllShares'), 'files_sharing'); -OC_API::register('post', +\OC_API::register('post', '/apps/files_sharing/api/v1/shares', array('\OCA\Files_Sharing\API\Local', 'createShare'), 'files_sharing'); -OC_API::register('get', +\OC_API::register('get', '/apps/files_sharing/api/v1/shares/{id}', array('\OCA\Files_Sharing\API\Local', 'getShare'), 'files_sharing'); -OC_API::register('put', +\OC_API::register('put', '/apps/files_sharing/api/v1/shares/{id}', array('\OCA\Files_Sharing\API\Local', 'updateShare'), 'files_sharing'); -OC_API::register('delete', +\OC_API::register('delete', '/apps/files_sharing/api/v1/shares/{id}', array('\OCA\Files_Sharing\API\Local', 'deleteShare'), 'files_sharing'); diff --git a/apps/files_sharing/application.php b/apps/files_sharing/application.php index 089ed6afbda..9fe8785df0b 100644 --- a/apps/files_sharing/application.php +++ b/apps/files_sharing/application.php @@ -11,6 +11,7 @@ namespace OCA\Files_Sharing; use OC\AppFramework\Utility\SimpleContainer; +use OCA\Files_Sharing\Controllers\ExternalSharesController; use OCA\Files_Sharing\Controllers\ShareController; use OCA\Files_Sharing\Middleware\SharingCheckMiddleware; use \OCP\AppFramework\App; @@ -44,6 +45,14 @@ class Application extends App { $c->query('ServerContainer')->getLogger() ); }); + $container->registerService('ExternalSharesController', function(SimpleContainer $c) { + return new ExternalSharesController( + $c->query('AppName'), + $c->query('Request'), + $c->query('IsIncomingShareEnabled'), + $c->query('ExternalManager') + ); + }); /** * Core class wrappers @@ -54,6 +63,18 @@ class Application extends App { $container->registerService('URLGenerator', function(SimpleContainer $c) { return $c->query('ServerContainer')->getUrlGenerator(); }); + $container->registerService('IsIncomingShareEnabled', function(SimpleContainer $c) { + return Helper::isIncomingServer2serverShareEnabled(); + }); + $container->registerService('ExternalManager', function(SimpleContainer $c) { + return new \OCA\Files_Sharing\External\Manager( + \OC::$server->getDatabaseConnection(), + \OC\Files\Filesystem::getMountManager(), + \OC\Files\Filesystem::getLoader(), + \OC::$server->getUserSession(), + \OC::$server->getHTTPHelper() + ); + }); /** * Middleware diff --git a/apps/files_sharing/js/external.js b/apps/files_sharing/js/external.js index 6ede2584cd9..aeb4b2461f8 100644 --- a/apps/files_sharing/js/external.js +++ b/apps/files_sharing/js/external.js @@ -8,16 +8,6 @@ * */ (function () { - var addExternalShare = function (remote, token, owner, name, password) { - return $.post(OC.generateUrl('apps/files_sharing/external'), { - remote: remote, - token: token, - owner: owner, - name: name, - password: password - }); - }; - /** * Shows "add external share" dialog. * @@ -27,20 +17,12 @@ * @param {String} token authentication token * @param {bool} passwordProtected true if the share is password protected */ - OCA.Sharing.showAddExternalDialog = function (remote, token, owner, name, passwordProtected) { + OCA.Sharing.showAddExternalDialog = function (share, passwordProtected, callback) { + var remote = share.remote; + var owner = share.owner; + var name = share.name; var remoteClean = (remote.substr(0, 8) === 'https://') ? remote.substr(8) : remote.substr(7); - var callback = function (add, password) { - password = password || ''; - if (add) { - addExternalShare(remote, token, owner, name, password).then(function (result) { - if (result.status === 'error') { - OC.Notification.show(result.data.message); - } else { - FileList.reload(); - } - }); - } - }; + if (!passwordProtected) { OC.dialogs.confirm( t( @@ -49,7 +31,9 @@ {name: name, owner: owner, remote: remoteClean} ), t('files_sharing','Remote share'), - callback, + function (result) { + callback(result, share); + }, true ).then(this._adjustDialog); } else { @@ -60,7 +44,9 @@ {name: name, owner: owner, remote: remoteClean} ), t('files_sharing','Remote share'), - callback, + function (result) { + callback(result, share); + }, true, t('files_sharing','Remote share password'), true @@ -82,17 +68,66 @@ $(document).ready(function () { // FIXME: HACK: do not init when running unit tests, need a better way if (!window.TESTING && OCA.Files) {// only run in the files app var params = OC.Util.History.parseUrlQuery(); + + //manually add server-to-server share if (params.remote && params.token && params.owner && params.name) { + + var callbackAddShare = function(result, share) { + var password = share.password || ''; + if (result) { + //$.post(OC.generateUrl('/apps/files_sharing/api/externalShares'), {id: share.id}); + $.post(OC.generateUrl('apps/files_sharing/external'), { + remote: share.remote, + token: share.token, + owner: share.owner, + name: share.name, + password: password}, function(result) { + if (result.status === 'error') { + OC.Notification.show(result.data.message); + } else { + FileList.reload(); + } + }); + } + }; + // clear hash, it is unlikely that it contain any extra parameters location.hash = ''; params.passwordProtected = parseInt(params.protected, 10) === 1; OCA.Sharing.showAddExternalDialog( - params.remote, - params.token, - params.owner, - params.name, - params.passwordProtected + params, + params.passwordProtected, + callbackAddShare ); } + + // check for new server-to-server shares which need to be approved + $.get(OC.generateUrl('/apps/files_sharing/api/externalShares'), + {}, + function(shares) { + var index; + for (index = 0; index < shares.length; ++index) { + OCA.Sharing.showAddExternalDialog( + shares[index], + false, + function(result, share) { + if (result) { + // Accept + $.post(OC.generateUrl('/apps/files_sharing/api/externalShares'), {id: share.id}); + FileList.reload(); + } else { + // Delete + $.ajax({ + url: OC.generateUrl('/apps/files_sharing/api/externalShares/'+share.id), + type: 'DELETE' + }); + } + } + ); + } + + }); + } + }); diff --git a/apps/files_sharing/lib/activity.php b/apps/files_sharing/lib/activity.php index 979df1c1da6..868830d80cd 100644 --- a/apps/files_sharing/lib/activity.php +++ b/apps/files_sharing/lib/activity.php @@ -98,7 +98,7 @@ class Activity implements \OCP\Activity\IExtension { case self::SUBJECT_REMOTE_SHARE_DECLINED: return $l->t('%1$s declined remote share %2$s', $params)->__toString(); case self::SUBJECT_REMOTE_SHARE_UNSHARED: - return $l->t('%1$s unshared %2$s', $params)->__toString(); + return $l->t('%1$s unshared %2$s from you', $params)->__toString(); } } } diff --git a/apps/files_sharing/lib/connector/publicauth.php b/apps/files_sharing/lib/connector/publicauth.php index 4144dafa379..a630d091fd4 100644 --- a/apps/files_sharing/lib/connector/publicauth.php +++ b/apps/files_sharing/lib/connector/publicauth.php @@ -69,6 +69,8 @@ class PublicAuth extends \Sabre\DAV\Auth\Backend\AbstractBasic { } else { return false; } + } elseif ($linkItem['share_type'] == \OCP\Share::SHARE_TYPE_REMOTE) { + return true; } else { return false; } diff --git a/apps/files_sharing/lib/controllers/externalsharescontroller.php b/apps/files_sharing/lib/controllers/externalsharescontroller.php new file mode 100644 index 00000000000..773ff8ce981 --- /dev/null +++ b/apps/files_sharing/lib/controllers/externalsharescontroller.php @@ -0,0 +1,86 @@ +<?php +/** + * @author Lukas Reschke <lukas@owncloud.com> + * @copyright 2014 Lukas Reschke + * + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\Files_Sharing\Controllers; + +use OC; +use OCP; +use OCP\AppFramework\Controller; +use OCP\IRequest; +use OCP\AppFramework\Http\JSONResponse; + +/** + * Class ExternalSharesController + * + * @package OCA\Files_Sharing\Controllers + */ +class ExternalSharesController extends Controller { + + /** @var bool */ + private $incomingShareEnabled; + /** @var \OCA\Files_Sharing\External\Manager */ + private $externalManager; + + /** + * @param string $appName + * @param IRequest $request + * @param \OCA\Files_Sharing\External\Manager $externalManager + */ + public function __construct($appName, + IRequest $request, + $incomingShareEnabled, + \OCA\Files_Sharing\External\Manager $externalManager) { + parent::__construct($appName, $request); + $this->incomingShareEnabled = $incomingShareEnabled; + $this->externalManager = $externalManager; + } + + /** + * @NoAdminRequired + * + * @return JSONResponse + */ + public function index() { + $shares = []; + if ($this->incomingShareEnabled) { + $shares = $this->externalManager->getOpenShares(); + } + return new JSONResponse($shares); + } + + /** + * @NoAdminRequired + * + * @param int $id + * @return JSONResponse + */ + public function create($id) { + if ($this->incomingShareEnabled) { + $this->externalManager->acceptShare($id); + } + + return new JSONResponse(); + } + + /** + * @NoAdminRequired + * + * @param $id + * @return JSONResponse + */ + public function destroy($id) { + if ($this->incomingShareEnabled) { + $this->externalManager->declineShare($id); + } + + return new JSONResponse(); + } + +} diff --git a/apps/files_sharing/lib/external/manager.php b/apps/files_sharing/lib/external/manager.php index b52e1a5044e..665e47c0fe9 100644 --- a/apps/files_sharing/lib/external/manager.php +++ b/apps/files_sharing/lib/external/manager.php @@ -34,25 +34,41 @@ class Manager { private $userSession; /** + * @var \OC\HTTPHelper + */ + private $httpHelper; + + /** * @param \OCP\IDBConnection $connection * @param \OC\Files\Mount\Manager $mountManager * @param \OC\User\Session $userSession * @param \OC\Files\Storage\StorageFactory $storageLoader */ public function __construct(\OCP\IDBConnection $connection, \OC\Files\Mount\Manager $mountManager, - \OC\Files\Storage\StorageFactory $storageLoader, \OC\User\Session $userSession) { + \OC\Files\Storage\StorageFactory $storageLoader, \OC\User\Session $userSession, \OC\HTTPHelper $httpHelper) { $this->connection = $connection; $this->mountManager = $mountManager; $this->userSession = $userSession; $this->storageLoader = $storageLoader; + $this->httpHelper = $httpHelper; } - public function addShare($remote, $token, $password, $name, $owner) { - $user = $this->userSession->getUser(); - if ($user) { - $mountPoint = Filesystem::normalizePath('/' . $name); - \OCA\Files_Sharing\Helper::addServer2ServerShare($remote, $token, $name, $mountPoint, $owner, $user->getUID(), $password, -1, true); + public function addShare($remote, $token, $password, $name, $owner, $accepted=false, $user = null, $remoteId = -1) { + + $user = $user ? $user: $this->userSession->getUser()->getUID(); + $accepted = $accepted ? 1 : 0; + $mountPoint = Filesystem::normalizePath('/' . $name); + + $query = $this->connection->prepare(' + INSERT INTO `*PREFIX*share_external` + (`remote`, `share_token`, `password`, `name`, `owner`, `user`, `mountpoint`, `mountpoint_hash`, `accepted`, `remote_id`) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + '); + $hash = md5($mountPoint); + $query->execute(array($remote, $token, $password, $name, $owner, $user, $mountPoint, $hash, $accepted, $remoteId)); + + if ($accepted) { $options = array( 'remote' => $remote, 'token' => $token, @@ -87,12 +103,85 @@ class Manager { } } + /** + * get share + * + * @param int $id share id + * @return mixed share of false + */ + private function getShare($id) { + $getShare = $this->connection->prepare(' + SELECT `remote`, `share_token` + FROM `*PREFIX*share_external` + WHERE `id` = ? AND `user` = ?'); + $result = $getShare->execute(array($id, $this->userSession->getUser()->getUID())); + + return $result ? $getShare->fetch() : false; + } + + /** + * accept server-to-server share + * + * @param int $id + */ + public function acceptShare($id) { + + $share = $this->getShare($id); + + if ($share) { + $acceptShare = $this->connection->prepare(' + UPDATE `*PREFIX*share_external` + SET `accepted` = ? + WHERE `id` = ? AND `user` = ?'); + $acceptShare->execute(array(1, $id, $this->userSession->getUser()->getUID())); + $this->sendFeedbackToRemote($share['remote'], $share['share_token'], $id, 'accept'); + } + } + + /** + * decline server-to-server share + * + * @param int $id + */ + public function declineShare($id) { + + $share = $this->getShare($id); + + if ($share) { + $removeShare = $this->connection->prepare(' + DELETE FROM `*PREFIX*share_external` WHERE `id` = ? AND `user` = ?'); + $removeShare->execute(array($id, $this->userSession->getUser()->getUID())); + $this->sendFeedbackToRemote($share['remote'], $share['share_token'], $id, 'decline'); + } + } + + /** + * inform remote server whether server-to-server share was accepted/declined + * + * @param string $remote + * @param string $token + * @param int $id + * @param string $feedback + * @return boolean + */ + private function sendFeedbackToRemote($remote, $token, $id, $feedback) { + + $url = $remote . \OCP\Share::BASE_PATH_TO_SHARE_API . '/' . $id . '/' . $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); + } + public static function setup() { $externalManager = new \OCA\Files_Sharing\External\Manager( - \OC::$server->getDatabaseConnection(), - \OC\Files\Filesystem::getMountManager(), - \OC\Files\Filesystem::getLoader(), - \OC::$server->getUserSession() + \OC::$server->getDatabaseConnection(), + \OC\Files\Filesystem::getMountManager(), + \OC\Files\Filesystem::getLoader(), + \OC::$server->getUserSession(), + \OC::$server->getHTTPHelper() ); $externalManager->setupMounts(); } @@ -151,6 +240,18 @@ class Manager { $user = $this->userSession->getUser(); $mountPoint = $this->stripPath($mountPoint); $hash = md5($mountPoint); + + $getShare = $this->connection->prepare(' + SELECT `remote`, `share_token`, `remote_id` + FROM `*PREFIX*share_external` + WHERE `mountpoint_hash` = ? AND `user` = ?'); + $result = $getShare->execute(array($hash, $user->getUID())); + + if ($result) { + $share = $getShare->fetch(); + $this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'decline'); + } + $query = $this->connection->prepare(' DELETE FROM `*PREFIX*share_external` WHERE `mountpoint_hash` = ? @@ -158,4 +259,17 @@ class Manager { '); return (bool)$query->execute(array($hash, $user->getUID())); } -} + + /** + * return a list of shares which are not yet accepted by the user + * + * @return array list of open server-to-server shares + */ + public function getOpenShares() { + $openShares = $this->connection->prepare('SELECT * FROM `*PREFIX*share_external` WHERE `accepted` = ? AND `user` = ?'); + $result = $openShares->execute(array(0, $this->userSession->getUser()->getUID())); + + return $result ? $openShares->fetchAll() : array(); + + } +}
\ No newline at end of file diff --git a/apps/files_sharing/lib/helper.php b/apps/files_sharing/lib/helper.php index 71519bd1d4a..001d0387fa4 100644 --- a/apps/files_sharing/lib/helper.php +++ b/apps/files_sharing/lib/helper.php @@ -2,8 +2,6 @@ namespace OCA\Files_Sharing; -use OC_Config; - class Helper { public static function registerHooks() { @@ -21,30 +19,6 @@ class Helper { } /** - * add server-to-server share to database - * - * @param string $remote - * @param string $token - * @param string $name - * @param string $mountPoint - * @param string $owner - * @param string $user - * @param string $password - * @param int $remoteId - * @param bool $accepted - */ - public static function addServer2ServerShare($remote, $token, $name, $mountPoint, $owner, $user, $password='', $remoteId=-1, $accepted = false) { - $accepted = $accepted ? 1 : 0; - $query = \OCP\DB::prepare(' - INSERT INTO `*PREFIX*share_external` - (`remote`, `share_token`, `password`, `name`, `owner`, `user`, `mountpoint`, `mountpoint_hash`, `accepted`, `remote_id`) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - '); - $hash = md5($mountPoint); - $query->execute(array($remote, $token, $password, $name, $owner, $user, $mountPoint, $hash, $accepted, $remoteId)); - } - - /** * Sets up the filesystem and user for public sharing * @param string $token string share token * @param string $relativePath optional path relative to the share @@ -89,7 +63,7 @@ class Helper { exit(); } - if (isset($linkItem['share_with'])) { + if (isset($linkItem['share_with']) && (int)$linkItem['share_type'] === \OCP\Share::SHARE_TYPE_LINK) { if (!self::authenticate($linkItem, $password)) { \OC_Response::setStatus(403); \OCP\JSON::error(array('success' => false)); diff --git a/apps/files_sharing/lib/share/file.php b/apps/files_sharing/lib/share/file.php index a5b4e75bceb..93e4af3c393 100644 --- a/apps/files_sharing/lib/share/file.php +++ b/apps/files_sharing/lib/share/file.php @@ -160,6 +160,20 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent { } /** + * check if server2server share is enabled + * + * @param int $shareType + * @return boolean + */ + public function isShareTypeAllowed($shareType) { + if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE) { + return \OCA\Files_Sharing\Helper::isOutgoingServer2serverShareEnabled(); + } + + return true; + } + + /** * resolve reshares to return the correct source item * @param array $source * @return array source item diff --git a/apps/files_sharing/lib/updater.php b/apps/files_sharing/lib/updater.php index a34140f5a35..9d8ae7cbb4f 100644 --- a/apps/files_sharing/lib/updater.php +++ b/apps/files_sharing/lib/updater.php @@ -161,7 +161,10 @@ class Shared_Updater { */ static public function postUnshareHook($params) { - if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') { + // only update etags for file/folders shared to local users/groups + if (($params['itemType'] === 'file' || $params['itemType'] === 'folder') && + $params['shareType'] !== \OCP\Share::SHARE_TYPE_LINK && + $params['shareType'] !== \OCP\Share::SHARE_TYPE_REMOTE) { $deletedShares = isset($params['deletedShares']) ? $params['deletedShares'] : array(); @@ -212,7 +215,7 @@ class Shared_Updater { /** * rename mount point from the children if the parent was renamed - * + * * @param string $oldPath old path relative to data/user/files * @param string $newPath new path relative to data/user/files */ diff --git a/apps/files_sharing/tests/server2server.php b/apps/files_sharing/tests/server2server.php index 7aec0c4951f..0400d357b82 100644 --- a/apps/files_sharing/tests/server2server.php +++ b/apps/files_sharing/tests/server2server.php @@ -38,6 +38,16 @@ class Test_Files_Sharing_S2S_OCS_API extends TestCase { self::loginHelper(self::TEST_FILES_SHARING_API_USER1); \OCP\Share::registerBackend('test', 'Test_Share_Backend'); + $config = $this->getMockBuilder('\OCP\IConfig') + ->disableOriginalConstructor()->getMock(); + $certificateManager = $this->getMock('\OCP\ICertificateManager'); + $httpHelperMock = $this->getMockBuilder('\OC\HTTPHelper') + ->setConstructorArgs(array($config, $certificateManager)) + ->getMock(); + $httpHelperMock->expects($this->any())->method('post')->with($this->anything())->will($this->returnValue(true)); + + $this->registerHttpHelper($httpHelperMock); + $this->s2s = new \OCA\Files_Sharing\API\Server2Server(); } @@ -45,10 +55,33 @@ class Test_Files_Sharing_S2S_OCS_API extends TestCase { $query = \OCP\DB::prepare('DELETE FROM `*PREFIX*share_external`'); $query->execute(); + $this->restoreHttpHelper(); + parent::tearDown(); } /** + * Register an http helper mock for testing purposes. + * @param $httpHelper http helper mock + */ + private function registerHttpHelper($httpHelper) { + $this->oldHttpHelper = \OC::$server->query('HTTPHelper'); + \OC::$server->registerService('HTTPHelper', function ($c) use ($httpHelper) { + return $httpHelper; + }); + } + + /** + * Restore the original http helper + */ + private function restoreHttpHelper() { + $oldHttpHelper = $this->oldHttpHelper; + \OC::$server->registerService('HTTPHelper', function ($c) use ($oldHttpHelper) { + return $oldHttpHelper; + }); + } + + /** * @medium */ function testCreateShare() { @@ -58,7 +91,7 @@ class Test_Files_Sharing_S2S_OCS_API extends TestCase { $_POST['name'] = 'name'; $_POST['owner'] = 'owner'; $_POST['shareWith'] = self::TEST_FILES_SHARING_API_USER2; - $_POST['remote_id'] = 1; + $_POST['remoteId'] = 1; $result = $this->s2s->createShare(null); @@ -81,10 +114,10 @@ class Test_Files_Sharing_S2S_OCS_API extends TestCase { function testDeclineShare() { $dummy = \OCP\DB::prepare(' INSERT INTO `*PREFIX*share` - (`share_type`, `uid_owner`, `item_type`, `item_source`, `item_target`, `file_source`, `file_target`, `permissions`, `stime`, `token`) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + (`share_type`, `uid_owner`, `item_type`, `item_source`, `item_target`, `file_source`, `file_target`, `permissions`, `stime`, `token`, `share_with`) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) '); - $dummy->execute(array(\OCP\Share::SHARE_TYPE_REMOTE, self::TEST_FILES_SHARING_API_USER1, 'test', '1', '/1', '1', '/test.txt', '1', time(), 'token')); + $dummy->execute(array(\OCP\Share::SHARE_TYPE_REMOTE, self::TEST_FILES_SHARING_API_USER1, 'test', '1', '/1', '1', '/test.txt', '1', time(), 'token', 'foo@bar')); $verify = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share`'); $result = $verify->execute(); |