/** * Convert an IShare to an array for OCS output * * @param \OCP\Share\IShare $share * @return array */ protected function formatShare(\OCP\Share\IShare $share) { $sharedBy = $this->userManager->get($share->getSharedBy()); $shareOwner = $this->userManager->get($share->getShareOwner()); $result = ['id' => $share->getId(), 'share_type' => $share->getShareType(), 'uid_owner' => $share->getSharedBy(), 'displayname_owner' => $sharedBy->getDisplayName(), 'permissions' => $share->getPermissions(), 'stime' => $share->getShareTime()->getTimestamp(), 'parent' => null, 'expiration' => null, 'token' => null, 'uid_file_owner' => $share->getShareOwner(), 'displayname_file_owner' => $shareOwner->getDisplayName()]; $node = $share->getNode(); $result['path'] = $this->rootFolder->getUserFolder($share->getShareOwner())->getRelativePath($node->getPath()); if ($node instanceof \OCP\Files\Folder) { $result['item_type'] = 'folder'; } else { $result['item_type'] = 'file'; } $result['storage_id'] = $node->getStorage()->getId(); $result['storage'] = $node->getStorage()->getCache()->getNumericStorageId(); $result['item_source'] = $node->getId(); $result['file_source'] = $node->getId(); $result['file_parent'] = $node->getParent()->getId(); $result['file_target'] = $share->getTarget(); if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) { $sharedWith = $this->userManager->get($share->getSharedWith()); $result['share_with'] = $sharedWith->getUID(); $result['share_with_displayname'] = $sharedWith->getDisplayName(); } else { if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { $result['share_with'] = $share->getSharedWith(); $result['share_with_displayname'] = $share->getSharedWith(); } else { if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) { $result['share_with'] = $share->getPassword(); $result['share_with_displayname'] = $share->getPassword(); $result['token'] = $share->getToken(); $result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]); $expiration = $share->getExpirationDate(); if ($expiration !== null) { $result['expiration'] = $expiration->format('Y-m-d 00:00:00'); } } else { if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) { $result['share_with'] = $share->getSharedWith(); $result['share_with_displayname'] = $share->getSharedWith(); $result['token'] = $share->getToken(); } } } } $result['mail_send'] = $share->getMailSend() ? 1 : 0; return $result; }
/** * Share a path * * @param IShare $share * @return IShare The share object * @throws ShareNotFound * @throws \Exception */ public function create(IShare $share) { $shareWith = $share->getSharedWith(); $itemSource = $share->getNodeId(); $itemType = $share->getNodeType(); $uidOwner = $share->getShareOwner(); $permissions = $share->getPermissions(); $sharedBy = $share->getSharedBy(); /* * Check if file is not already shared with the remote user */ $alreadyShared = $this->getSharedWith($shareWith, self::SHARE_TYPE_REMOTE, $share->getNode(), 1, 0); if (!empty($alreadyShared)) { $message = 'Sharing %s failed, because this item is already shared with %s'; $message_t = $this->l->t('Sharing %s failed, because this item is already shared with %s', array($share->getNode()->getName(), $shareWith)); $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']); throw new \Exception($message_t); } // don't allow federated shares if source and target server are the same list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith); $currentServer = $this->addressHandler->generateRemoteURL(); $currentUser = $sharedBy; if ($this->addressHandler->compareAddresses($user, $remote, $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); } $token = $this->tokenHandler->generateToken(); $shareWith = $user . '@' . $remote; $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token); $send = $this->notifications->sendRemoteShare($token, $shareWith, $share->getNode()->getName(), $shareId, $share->getSharedBy()); $data = $this->getRawShare($shareId); $share = $this->createShare($data); if ($send === false) { $this->delete($share); $message_t = $this->l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable.', [$share->getNode()->getName(), $shareWith]); throw new \Exception($message_t); } return $share; }
/** * @inheritdoc */ public function move(\OCP\Share\IShare $share, $recipient) { if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) { // Just update the target $qb = $this->dbConn->getQueryBuilder(); $qb->update('share')->set('file_target', $qb->createNamedParameter($share->getTarget()))->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))->execute(); } else { if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { // Check if there is a usergroup share $qb = $this->dbConn->getQueryBuilder(); $stmt = $qb->select('id')->from('share')->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient)))->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))->setMaxResults(1)->execute(); $data = $stmt->fetch(); $stmt->closeCursor(); if ($data === false) { // No usergroup share yet. Create one. $qb = $this->dbConn->getQueryBuilder(); $qb->insert('share')->values(['share_type' => $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP), 'share_with' => $qb->createNamedParameter($recipient), 'uid_owner' => $qb->createNamedParameter($share->getShareOwner()), 'uid_initiator' => $qb->createNamedParameter($share->getSharedBy()), 'parent' => $qb->createNamedParameter($share->getId()), 'item_type' => $qb->createNamedParameter($share->getNode() instanceof File ? 'file' : 'folder'), 'item_source' => $qb->createNamedParameter($share->getNode()->getId()), 'file_source' => $qb->createNamedParameter($share->getNode()->getId()), 'file_target' => $qb->createNamedParameter($share->getTarget()), 'permissions' => $qb->createNamedParameter($share->getPermissions()), 'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp())])->execute(); } else { // Already a usergroup share. Update it. $qb = $this->dbConn->getQueryBuilder(); $qb->update('share')->set('file_target', $qb->createNamedParameter($share->getTarget()))->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id'])))->execute(); } } } return $share; }
/** * Check for pre share requirements for group shares * * @param \OCP\Share\IShare $share * @throws \Exception */ protected function groupCreateChecks(\OCP\Share\IShare $share) { // Verify if the user can share with this group if ($this->shareWithGroupMembersOnly()) { $sharedBy = $this->userManager->get($share->getSharedBy()); $sharedWith = $this->groupManager->get($share->getSharedWith()); if (!$sharedWith->inGroup($sharedBy)) { throw new \Exception('Only sharing within your own groups is allowed'); } } /* * TODO: Could be costly, fix * * Also this is not what we want in the future.. then we want to squash identical shares. */ $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP); $existingShares = $provider->getSharesByPath($share->getNode()); foreach ($existingShares as $existingShare) { if ($existingShare->getFullId() === $share->getFullId()) { continue; } if ($existingShare->getSharedWith() === $share->getSharedWith()) { throw new \Exception('Path already shared with this group'); } } }
/** * @dataProvider dataFormatShare * * @param array $expects * @param \OCP\Share\IShare $share * @param array $users * @param $exception */ public function testFormatShare(array $expects, \OCP\Share\IShare $share, array $users, $exception) { $this->userManager->method('get')->will($this->returnValueMap($users)); $this->urlGenerator->method('linkToRouteAbsolute')->with('files_sharing.sharecontroller.showShare', ['token' => 'myToken'])->willReturn('myLink'); $this->rootFolder->method('getUserFolder')->with($this->currentUser->getUID())->will($this->returnSelf()); if (!$exception) { $this->rootFolder->method('getById')->with($share->getNodeId())->willReturn([$share->getNode()]); $this->rootFolder->method('getRelativePath')->with($share->getNode()->getPath())->will($this->returnArgument(0)); } try { $result = $this->invokePrivate($this->ocs, 'formatShare', [$share]); $this->assertFalse($exception); $this->assertEquals($expects, $result); } catch (NotFoundException $e) { $this->assertTrue($exception); } }
/** * Validate the permissions of the share * * @param Share\IShare $share * @return bool */ private function validateShare(\OCP\Share\IShare $share) { return $share->getNode()->isReadable() && $share->getNode()->isShareable(); }
/** * create federated share and inform the recipient * * @param IShare $share * @return int * @throws ShareNotFound * @throws \Exception */ protected function createFederatedShare(IShare $share) { $token = $this->tokenHandler->generateToken(); $shareId = $this->addShareToDB($share->getNodeId(), $share->getNodeType(), $share->getSharedWith(), $share->getSharedBy(), $share->getShareOwner(), $share->getPermissions(), $token); $sharedByFederatedId = $share->getSharedBy(); if ($this->userManager->userExists($sharedByFederatedId)) { $sharedByFederatedId = $sharedByFederatedId . '@' . $this->addressHandler->generateRemoteURL(); } $send = $this->notifications->sendRemoteShare($token, $share->getSharedWith(), $share->getNode()->getName(), $shareId, $share->getShareOwner(), $share->getShareOwner() . '@' . $this->addressHandler->generateRemoteURL(), $share->getSharedBy(), $sharedByFederatedId); if ($send === false) { $data = $this->getRawShare($shareId); $share = $this->createShareObject($data); $this->removeShareFromTable($share); $message_t = $this->l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable.', [$share->getNode()->getName(), $share->getSharedWith()]); throw new \Exception($message_t); } return $shareId; }
/** * Unshare a share from the recipient. If this is a group share * this means we need a special entry in the share db. * * @param \OCP\Share\IShare $share * @param IUser $recipient * @throws BackendError * @throws ProviderException */ public function deleteFromSelf(\OCP\Share\IShare $share, IUser $recipient) { if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { /** @var IGroup $group */ $group = $share->getSharedWith(); if (!$group->inGroup($recipient)) { throw new ProviderException('Recipient not in receiving group'); } // Try to fetch user specific share $qb = $this->dbConn->getQueryBuilder(); $stmt = $qb->select('*')->from('share')->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient->getUID())))->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))->execute(); $data = $stmt->fetch(); /* * Check if there already is a user specific group share. * If there is update it (if required). */ if ($data === false) { $qb = $this->dbConn->getQueryBuilder(); $type = $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder'; //Insert new share $qb->insert('share')->values(['share_type' => $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP), 'share_with' => $qb->createNamedParameter($recipient->getUID()), 'uid_owner' => $qb->createNamedParameter($share->getShareOwner()->getUID()), 'uid_initiator' => $qb->createNamedParameter($share->getSharedBy()->getUID()), 'parent' => $qb->createNamedParameter($share->getId()), 'item_type' => $qb->createNamedParameter($type), 'item_source' => $qb->createNamedParameter($share->getNode()->getId()), 'file_source' => $qb->createNamedParameter($share->getNode()->getId()), 'file_target' => $qb->createNamedParameter($share->getTarget()), 'permissions' => $qb->createNamedParameter(0), 'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp())])->execute(); } else { if ($data['permissions'] !== 0) { // Update existing usergroup share $qb = $this->dbConn->getQueryBuilder(); $qb->update('share')->set('permissions', $qb->createNamedParameter(0))->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id'])))->execute(); } } } else { if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) { if ($share->getSharedWith() !== $recipient) { throw new ProviderException('Recipient does not match'); } // We can just delete user and link shares $this->delete($share); } else { throw new ProviderException('Invalid shareType'); } } }
/** * Creates the environment based on the share the token links to * * @param IShare $share */ public function setTokenBasedEnv($share) { $origShareOwnerId = $share->getShareOwner(); $this->userFolder = $this->rootFolder->getUserFolder($origShareOwnerId); $this->sharedNodeId = $share->getNodeId(); $this->sharedNode = $share->getNode(); $this->fromRootToFolder = $this->buildFromRootToFolder($this->sharedNodeId); $this->folderName = $share->getTarget(); $this->userId = $origShareOwnerId; $this->sharePassword = $share->getPassword(); }
/** * create federated share and inform the recipient * * @param IShare $share * @return int * @throws ShareNotFound * @throws \Exception */ protected function createFederatedShare(IShare $share) { $token = $this->tokenHandler->generateToken(); $shareId = $this->addShareToDB($share->getNodeId(), $share->getNodeType(), $share->getSharedWith(), $share->getSharedBy(), $share->getShareOwner(), $share->getPermissions(), $token); try { $sharedByFederatedId = $share->getSharedBy(); if ($this->userManager->userExists($sharedByFederatedId)) { $sharedByFederatedId = $sharedByFederatedId . '@' . $this->addressHandler->generateRemoteURL(); } $send = $this->notifications->sendRemoteShare($token, $share->getSharedWith(), $share->getNode()->getName(), $shareId, $share->getShareOwner(), $share->getShareOwner() . '@' . $this->addressHandler->generateRemoteURL(), $share->getSharedBy(), $sharedByFederatedId); if ($send === false) { $message_t = $this->l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable.', [$share->getNode()->getName(), $share->getSharedWith()]); throw new \Exception($message_t); } } catch (\Exception $e) { $this->logger->error('Failed to notify remote server of federated share, removing share (' . $e->getMessage() . ')'); $this->removeShareFromTableById($shareId); throw $e; } return $shareId; }