2015-10-30 08:10:08 -04:00
< ? php
2019-12-03 13:57:53 -05:00
2018-04-23 14:31:57 -04:00
declare ( strict_types = 1 );
2015-10-30 08:10:08 -04:00
/**
2024-06-06 13:48:28 -04:00
* SPDX - FileCopyrightText : 2016 - 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX - FileCopyrightText : 2016 ownCloud , Inc .
* SPDX - License - Identifier : AGPL - 3.0 - only
2015-10-30 08:10:08 -04:00
*/
2023-02-15 13:22:09 -05:00
2016-10-21 14:25:07 -04:00
namespace OCA\Files_Sharing\Controller ;
2015-10-30 08:10:08 -04:00
2023-06-28 06:27:55 -04:00
use Exception ;
2022-07-15 11:11:54 -04:00
use OC\Files\Storage\Wrapper\Wrapper ;
2024-10-10 06:40:31 -04:00
use OCA\Circles\Api\v1\Circles ;
2024-07-09 05:09:01 -04:00
use OCA\Files\Helper ;
2019-06-25 16:34:38 -04:00
use OCA\Files_Sharing\Exceptions\SharingRightsException ;
use OCA\Files_Sharing\External\Storage ;
2024-07-09 05:09:01 -04:00
use OCA\Files_Sharing\ResponseDefinitions ;
2022-06-13 10:38:34 -04:00
use OCA\Files_Sharing\SharedStorage ;
2024-10-10 06:40:31 -04:00
use OCA\GlobalSiteSelector\Service\SlaveService ;
2018-07-10 07:01:31 -04:00
use OCP\App\IAppManager ;
2024-07-09 06:09:42 -04:00
use OCP\AppFramework\Http ;
2024-12-16 18:53:12 -05:00
use OCP\AppFramework\Http\Attribute\ApiRoute ;
2024-07-05 03:47:40 -04:00
use OCP\AppFramework\Http\Attribute\NoAdminRequired ;
2024-07-09 05:09:01 -04:00
use OCP\AppFramework\Http\Attribute\UserRateLimit ;
2016-07-20 03:55:43 -04:00
use OCP\AppFramework\Http\DataResponse ;
2016-07-20 04:41:09 -04:00
use OCP\AppFramework\OCS\OCSBadRequestException ;
use OCP\AppFramework\OCS\OCSException ;
use OCP\AppFramework\OCS\OCSForbiddenException ;
2016-07-20 03:55:43 -04:00
use OCP\AppFramework\OCS\OCSNotFoundException ;
2016-07-19 08:13:27 -04:00
use OCP\AppFramework\OCSController ;
2018-06-29 07:22:26 -04:00
use OCP\AppFramework\QueryException ;
2017-12-01 08:49:35 -05:00
use OCP\Constants ;
2024-10-10 06:40:31 -04:00
use OCP\Files\File ;
2023-06-28 06:27:55 -04:00
use OCP\Files\Folder ;
2019-06-25 16:34:38 -04:00
use OCP\Files\InvalidPathException ;
2019-11-22 14:52:10 -05:00
use OCP\Files\IRootFolder ;
2024-10-15 05:08:21 -04:00
use OCP\Files\Mount\IShareOwnerlessMount ;
2016-09-20 11:59:04 -04:00
use OCP\Files\Node ;
2016-02-16 10:04:17 -05:00
use OCP\Files\NotFoundException ;
2024-11-19 03:40:26 -05:00
use OCP\HintException ;
2017-12-01 08:49:35 -05:00
use OCP\IConfig ;
2024-01-08 18:46:26 -05:00
use OCP\IDateTimeZone ;
2015-11-24 03:37:17 -05:00
use OCP\IGroupManager ;
2016-04-15 08:05:36 -04:00
use OCP\IL10N ;
2020-10-11 09:19:30 -04:00
use OCP\IPreview ;
2015-11-24 03:37:17 -05:00
use OCP\IRequest ;
2025-02-04 16:40:00 -05:00
use OCP\ITagManager ;
2015-11-24 03:37:17 -05:00
use OCP\IURLGenerator ;
2019-11-22 14:52:10 -05:00
use OCP\IUserManager ;
use OCP\Lock\ILockingProvider ;
2016-03-09 03:11:41 -05:00
use OCP\Lock\LockedException ;
2024-07-09 05:00:38 -04:00
use OCP\Mail\IMailer ;
2023-06-28 06:27:55 -04:00
use OCP\Server ;
2025-04-09 10:12:18 -04:00
use OCP\Share\Exceptions\GenericShareException ;
2019-11-22 14:52:10 -05:00
use OCP\Share\Exceptions\ShareNotFound ;
2024-12-16 18:53:12 -05:00
use OCP\Share\Exceptions\ShareTokenException ;
2019-11-22 14:52:10 -05:00
use OCP\Share\IManager ;
2024-06-20 08:02:53 -04:00
use OCP\Share\IProviderFactory ;
2016-09-07 12:38:08 -04:00
use OCP\Share\IShare ;
2024-07-05 03:47:40 -04:00
use OCP\Share\IShareProviderWithNotification ;
2020-08-05 04:37:20 -04:00
use OCP\UserStatus\IManager as IUserStatusManager ;
2023-06-28 06:27:55 -04:00
use Psr\Container\ContainerExceptionInterface ;
2024-04-15 15:38:26 -04:00
use Psr\Container\ContainerInterface ;
2023-06-28 06:27:55 -04:00
use Psr\Log\LoggerInterface ;
2016-02-02 08:18:59 -05:00
2016-03-07 10:12:40 -05:00
/**
* @ package OCA\Files_Sharing\API
2023-02-15 13:22:09 -05:00
*
2023-10-23 10:47:38 -04:00
* @ psalm - import - type Files_SharingShare from ResponseDefinitions
2016-03-07 10:12:40 -05:00
*/
2016-10-21 14:25:07 -04:00
class ShareAPIController extends OCSController {
2015-10-30 08:10:08 -04:00
2024-04-15 15:38:26 -04:00
private ? Node $lockedNode = null ;
2015-11-24 03:37:17 -05:00
2016-02-03 02:14:48 -05:00
/**
* Share20OCS constructor .
*/
2015-11-24 03:37:17 -05:00
public function __construct (
2018-04-23 14:31:57 -04:00
string $appName ,
2016-09-21 11:35:09 -04:00
IRequest $request ,
2024-04-15 15:38:26 -04:00
private IManager $shareManager ,
private IGroupManager $groupManager ,
private IUserManager $userManager ,
private IRootFolder $rootFolder ,
private IURLGenerator $urlGenerator ,
private IL10N $l ,
private IConfig $config ,
private IAppManager $appManager ,
private ContainerInterface $serverContainer ,
private IUserStatusManager $userStatusManager ,
private IPreview $previewManager ,
2024-01-08 18:46:26 -05:00
private IDateTimeZone $dateTimeZone ,
2024-04-15 15:38:26 -04:00
private LoggerInterface $logger ,
2024-06-20 08:02:53 -04:00
private IProviderFactory $factory ,
2024-07-09 05:00:38 -04:00
private IMailer $mailer ,
2024-10-18 06:04:22 -04:00
private ? string $userId = null ,
2015-11-24 03:37:17 -05:00
) {
2016-07-19 08:13:27 -04:00
parent :: __construct ( $appName , $request );
2015-11-06 06:05:19 -05:00
}
/**
* Convert an IShare to an array for OCS output
*
2024-10-18 06:04:22 -04:00
* @ param IShare $share
2016-09-20 11:59:04 -04:00
* @ param Node | null $recipientNode
2023-10-23 10:47:38 -04:00
* @ return Files_SharingShare
2016-02-16 10:04:17 -05:00
* @ throws NotFoundException In case the node can ' t be resolved .
2018-07-24 05:57:52 -04:00
*
* @ suppress PhanUndeclaredClassMethod
2015-11-06 06:05:19 -05:00
*/
2024-03-28 11:13:19 -04:00
protected function formatShare ( IShare $share , ? Node $recipientNode = null ) : array {
2016-02-03 02:14:48 -05:00
$sharedBy = $this -> userManager -> get ( $share -> getSharedBy ());
2016-06-07 06:50:12 -04:00
$shareOwner = $this -> userManager -> get ( $share -> getShareOwner ());
2023-07-06 02:58:11 -04:00
$isOwnShare = false ;
if ( $shareOwner !== null ) {
2024-10-18 06:04:22 -04:00
$isOwnShare = $shareOwner -> getUID () === $this -> userId ;
2023-07-06 02:58:11 -04:00
}
2015-11-06 06:05:19 -05:00
$result = [
'id' => $share -> getId (),
'share_type' => $share -> getShareType (),
2016-02-03 02:14:48 -05:00
'uid_owner' => $share -> getSharedBy (),
2016-02-11 15:17:22 -05:00
'displayname_owner' => $sharedBy !== null ? $sharedBy -> getDisplayName () : $share -> getSharedBy (),
2019-10-24 09:51:56 -04:00
// recipient permissions
2015-11-06 06:05:19 -05:00
'permissions' => $share -> getPermissions (),
2019-10-24 09:51:56 -04:00
// current user permissions on this share
'can_edit' => $this -> canEditShare ( $share ),
'can_delete' => $this -> canDeleteShare ( $share ),
2016-01-27 14:51:26 -05:00
'stime' => $share -> getShareTime () -> getTimestamp (),
'parent' => null ,
2015-11-06 06:05:19 -05:00
'expiration' => null ,
'token' => null ,
2016-02-03 02:14:48 -05:00
'uid_file_owner' => $share -> getShareOwner (),
2018-07-13 11:53:14 -04:00
'note' => $share -> getNote (),
2018-10-16 04:31:38 -04:00
'label' => $share -> getLabel (),
2016-02-12 04:44:34 -05:00
'displayname_file_owner' => $shareOwner !== null ? $shareOwner -> getDisplayName () : $share -> getShareOwner (),
2015-11-06 06:05:19 -05:00
];
2024-10-18 06:04:22 -04:00
$userFolder = $this -> rootFolder -> getUserFolder ( $this -> userId );
2016-09-20 11:59:04 -04:00
if ( $recipientNode ) {
$node = $recipientNode ;
} else {
2024-02-09 03:54:52 -05:00
$node = $userFolder -> getFirstNodeById ( $share -> getNodeId ());
if ( ! $node ) {
2016-09-21 12:55:58 -04:00
// fallback to guessing the path
$node = $userFolder -> get ( $share -> getTarget ());
2018-04-04 05:33:05 -04:00
if ( $node === null || $share -> getTarget () === '' ) {
2016-09-21 12:55:58 -04:00
throw new NotFoundException ();
}
2016-09-20 11:59:04 -04:00
}
}
2016-06-07 06:50:12 -04:00
$result [ 'path' ] = $userFolder -> getRelativePath ( $node -> getPath ());
2020-04-29 10:43:39 -04:00
if ( $node instanceof Folder ) {
2015-11-06 06:05:19 -05:00
$result [ 'item_type' ] = 'folder' ;
} else {
$result [ 'item_type' ] = 'file' ;
}
2019-08-06 04:22:32 -04:00
2023-07-06 02:58:11 -04:00
// Get the original node permission if the share owner is the current user
if ( $isOwnShare ) {
2023-07-06 12:35:53 -04:00
$result [ 'item_permissions' ] = $node -> getPermissions ();
2023-07-06 02:58:11 -04:00
}
2024-10-18 06:04:22 -04:00
2024-08-22 04:02:37 -04:00
// If we're on the recipient side, the node permissions
// are bound to the share permissions. So we need to
// adjust the permissions to the share permissions if necessary.
if ( ! $isOwnShare ) {
$result [ 'item_permissions' ] = $share -> getPermissions ();
// For some reason, single files share are forbidden to have the delete permission
// since we have custom methods to check those, let's adjust straight away.
// DAV permissions does not have that issue though.
if ( $this -> canDeleteShare ( $share ) || $this -> canDeleteShareFromSelf ( $share )) {
$result [ 'item_permissions' ] |= Constants :: PERMISSION_DELETE ;
}
if ( $this -> canEditShare ( $share )) {
$result [ 'item_permissions' ] |= Constants :: PERMISSION_UPDATE ;
}
}
2023-07-06 02:58:11 -04:00
2024-08-20 05:31:21 -04:00
// See MOUNT_ROOT_PROPERTYNAME dav property
$result [ 'is-mount-root' ] = $node -> getInternalPath () === '' ;
$result [ 'mount-type' ] = $node -> getMountPoint () -> getMountType ();
2016-07-19 08:13:27 -04:00
$result [ 'mimetype' ] = $node -> getMimetype ();
2020-10-11 09:19:30 -04:00
$result [ 'has_preview' ] = $this -> previewManager -> isAvailable ( $node );
2016-01-27 14:51:26 -05:00
$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 ();
2015-11-06 06:05:19 -05:00
$result [ 'file_target' ] = $share -> getTarget ();
2023-07-06 12:35:53 -04:00
$result [ 'item_size' ] = $node -> getSize ();
$result [ 'item_mtime' ] = $node -> getMTime ();
2015-11-06 06:05:19 -05:00
2017-03-29 10:50:23 -04:00
$expiration = $share -> getExpirationDate ();
if ( $expiration !== null ) {
2024-02-07 06:06:12 -05:00
$expiration -> setTimezone ( $this -> dateTimeZone -> getTimeZone ());
2017-03-29 10:50:23 -04:00
$result [ 'expiration' ] = $expiration -> format ( 'Y-m-d 00:00:00' );
}
2020-04-29 10:43:39 -04:00
if ( $share -> getShareType () === IShare :: TYPE_USER ) {
2016-02-03 02:14:48 -05:00
$sharedWith = $this -> userManager -> get ( $share -> getSharedWith ());
2016-02-12 04:44:34 -05:00
$result [ 'share_with' ] = $share -> getSharedWith ();
$result [ 'share_with_displayname' ] = $sharedWith !== null ? $sharedWith -> getDisplayName () : $share -> getSharedWith ();
2020-10-07 06:32:16 -04:00
$result [ 'share_with_displayname_unique' ] = $sharedWith !== null ? (
2021-09-01 09:41:02 -04:00
! empty ( $sharedWith -> getSystemEMailAddress ()) ? $sharedWith -> getSystemEMailAddress () : $sharedWith -> getUID ()
2020-10-07 06:32:16 -04:00
) : $share -> getSharedWith ();
2020-08-05 04:37:20 -04:00
$userStatuses = $this -> userStatusManager -> getUserStatuses ([ $share -> getSharedWith ()]);
$userStatus = array_shift ( $userStatuses );
if ( $userStatus ) {
$result [ 'status' ] = [
'status' => $userStatus -> getStatus (),
'message' => $userStatus -> getMessage (),
'icon' => $userStatus -> getIcon (),
'clearAt' => $userStatus -> getClearAt ()
? ( int ) $userStatus -> getClearAt () -> format ( 'U' )
: null ,
];
}
2020-04-29 10:43:39 -04:00
} elseif ( $share -> getShareType () === IShare :: TYPE_GROUP ) {
2016-11-30 14:56:10 -05:00
$group = $this -> groupManager -> get ( $share -> getSharedWith ());
2016-02-03 02:14:48 -05:00
$result [ 'share_with' ] = $share -> getSharedWith ();
2016-11-30 14:56:10 -05:00
$result [ 'share_with_displayname' ] = $group !== null ? $group -> getDisplayName () : $share -> getSharedWith ();
2020-04-10 04:35:09 -04:00
} elseif ( $share -> getShareType () === IShare :: TYPE_LINK ) {
2015-11-06 06:05:19 -05:00
2018-11-06 17:48:28 -05:00
// "share_with" and "share_with_displayname" for passwords of link
// shares was deprecated in Nextcloud 15, use "password" instead.
2015-11-06 06:05:19 -05:00
$result [ 'share_with' ] = $share -> getPassword ();
2020-01-10 04:03:08 -05:00
$result [ 'share_with_displayname' ] = '(' . $this -> l -> t ( 'Shared link' ) . ')' ;
2015-11-06 06:05:19 -05:00
2018-11-06 17:48:28 -05:00
$result [ 'password' ] = $share -> getPassword ();
2018-10-15 06:27:56 -04:00
$result [ 'send_password_by_talk' ] = $share -> getSendPasswordByTalk ();
2015-11-06 06:05:19 -05:00
$result [ 'token' ] = $share -> getToken ();
$result [ 'url' ] = $this -> urlGenerator -> linkToRouteAbsolute ( 'files_sharing.sharecontroller.showShare' , [ 'token' => $share -> getToken ()]);
2023-06-28 06:27:55 -04:00
} elseif ( $share -> getShareType () === IShare :: TYPE_REMOTE ) {
$result [ 'share_with' ] = $share -> getSharedWith ();
$result [ 'share_with_displayname' ] = $this -> getCachedFederatedDisplayName ( $share -> getSharedWith ());
$result [ 'token' ] = $share -> getToken ();
} elseif ( $share -> getShareType () === IShare :: TYPE_REMOTE_GROUP ) {
2015-11-06 06:05:19 -05:00
$result [ 'share_with' ] = $share -> getSharedWith ();
2016-10-25 10:24:24 -04:00
$result [ 'share_with_displayname' ] = $this -> getDisplayNameFromAddressBook ( $share -> getSharedWith (), 'CLOUD' );
2015-11-06 06:05:19 -05:00
$result [ 'token' ] = $share -> getToken ();
2020-04-29 10:43:39 -04:00
} elseif ( $share -> getShareType () === IShare :: TYPE_EMAIL ) {
2016-07-29 09:38:31 -04:00
$result [ 'share_with' ] = $share -> getSharedWith ();
2017-03-28 09:11:07 -04:00
$result [ 'password' ] = $share -> getPassword ();
2022-04-14 15:08:53 -04:00
$result [ 'password_expiration_time' ] = $share -> getPasswordExpirationTime () !== null ? $share -> getPasswordExpirationTime () -> format ( \DateTime :: ATOM ) : null ;
2018-07-10 07:01:31 -04:00
$result [ 'send_password_by_talk' ] = $share -> getSendPasswordByTalk ();
2016-10-25 10:24:24 -04:00
$result [ 'share_with_displayname' ] = $this -> getDisplayNameFromAddressBook ( $share -> getSharedWith (), 'EMAIL' );
2016-07-29 09:38:31 -04:00
$result [ 'token' ] = $share -> getToken ();
2020-04-29 10:43:39 -04:00
} elseif ( $share -> getShareType () === IShare :: TYPE_CIRCLE ) {
2018-03-15 23:23:46 -04:00
// getSharedWith() returns either "name (type, owner)" or
2024-08-06 08:48:07 -04:00
// "name (type, owner) [id]", depending on the Teams app version.
2018-03-15 23:23:46 -04:00
$hasCircleId = ( substr ( $share -> getSharedWith (), - 1 ) === ']' );
2017-06-06 07:21:42 -04:00
$result [ 'share_with_displayname' ] = $share -> getSharedWithDisplayName ();
if ( empty ( $result [ 'share_with_displayname' ])) {
2019-08-06 04:22:32 -04:00
$displayNameLength = ( $hasCircleId ? strrpos ( $share -> getSharedWith (), ' ' ) : strlen ( $share -> getSharedWith ()));
2017-06-06 07:21:42 -04:00
$result [ 'share_with_displayname' ] = substr ( $share -> getSharedWith (), 0 , $displayNameLength );
}
$result [ 'share_with_avatar' ] = $share -> getSharedWithAvatar ();
2018-03-15 23:23:46 -04:00
2019-08-06 04:22:32 -04:00
$shareWithStart = ( $hasCircleId ? strrpos ( $share -> getSharedWith (), '[' ) + 1 : 0 );
$shareWithLength = ( $hasCircleId ? - 1 : strpos ( $share -> getSharedWith (), ' ' ));
2022-01-03 08:52:09 -05:00
if ( $shareWithLength === false ) {
$result [ 'share_with' ] = substr ( $share -> getSharedWith (), $shareWithStart );
} else {
$result [ 'share_with' ] = substr ( $share -> getSharedWith (), $shareWithStart , $shareWithLength );
2018-10-30 04:58:43 -04:00
}
2020-04-29 10:43:39 -04:00
} elseif ( $share -> getShareType () === IShare :: TYPE_ROOM ) {
2018-06-29 07:22:26 -04:00
$result [ 'share_with' ] = $share -> getSharedWith ();
$result [ 'share_with_displayname' ] = '' ;
try {
2023-02-15 13:22:09 -05:00
/** @var array{share_with_displayname: string, share_with_link: string, share_with?: string, token?: string} $roomShare */
$roomShare = $this -> getRoomShareHelper () -> formatShare ( $share );
$result = array_merge ( $result , $roomShare );
2025-02-04 16:40:00 -05:00
} catch ( ContainerExceptionInterface $e ) {
2019-08-06 04:22:32 -04:00
}
2020-12-03 10:03:35 -05:00
} elseif ( $share -> getShareType () === IShare :: TYPE_DECK ) {
$result [ 'share_with' ] = $share -> getSharedWith ();
$result [ 'share_with_displayname' ] = '' ;
try {
2023-02-15 13:22:09 -05:00
/** @var array{share_with: string, share_with_displayname: string, share_with_link: string} $deckShare */
$deckShare = $this -> getDeckShareHelper () -> formatShare ( $share );
$result = array_merge ( $result , $deckShare );
2025-02-04 16:40:00 -05:00
} catch ( ContainerExceptionInterface $e ) {
2020-12-03 10:03:35 -05:00
}
2023-02-20 04:50:31 -05:00
} elseif ( $share -> getShareType () === IShare :: TYPE_SCIENCEMESH ) {
$result [ 'share_with' ] = $share -> getSharedWith ();
$result [ 'share_with_displayname' ] = '' ;
try {
2023-02-15 13:22:09 -05:00
/** @var array{share_with: string, share_with_displayname: string, token: string} $scienceMeshShare */
$scienceMeshShare = $this -> getSciencemeshShareHelper () -> formatShare ( $share );
$result = array_merge ( $result , $scienceMeshShare );
2025-02-04 16:40:00 -05:00
} catch ( ContainerExceptionInterface $e ) {
2023-02-20 04:50:31 -05:00
}
2015-11-06 06:05:19 -05:00
}
2017-03-17 15:48:33 -04:00
2015-11-06 06:05:19 -05:00
$result [ 'mail_send' ] = $share -> getMailSend () ? 1 : 0 ;
2018-10-18 06:38:07 -04:00
$result [ 'hide_download' ] = $share -> getHideDownload () ? 1 : 0 ;
2015-11-06 06:05:19 -05:00
2022-05-18 08:54:27 -04:00
$result [ 'attributes' ] = null ;
if ( $attributes = $share -> getAttributes ()) {
2023-02-15 13:22:09 -05:00
$result [ 'attributes' ] = ( string ) \json_encode ( $attributes -> toArray ());
2022-05-18 08:54:27 -04:00
}
2015-11-06 06:05:19 -05:00
return $result ;
}
2016-10-25 10:24:24 -04:00
/**
* Check if one of the users address books knows the exact property , if
2023-06-28 06:27:55 -04:00
* not we return the full name .
2016-10-25 10:24:24 -04:00
*
* @ param string $query
* @ param string $property
* @ return string
*/
2018-04-23 14:31:57 -04:00
private function getDisplayNameFromAddressBook ( string $query , string $property ) : string {
2021-12-08 11:26:30 -05:00
// FIXME: If we inject the contacts manager it gets initialized before any address books are registered
2023-06-28 06:27:55 -04:00
try {
$result = \OC :: $server -> getContactsManager () -> search ( $query , [ $property ], [
'limit' => 1 ,
'enumeration' => false ,
'strict_search' => true ,
]);
} catch ( Exception $e ) {
2024-04-15 15:38:26 -04:00
$this -> logger -> error (
2023-06-28 06:27:55 -04:00
$e -> getMessage (),
[ 'exception' => $e ]
);
return $query ;
}
2016-10-25 10:24:24 -04:00
foreach ( $result as $r ) {
2019-08-06 04:22:32 -04:00
foreach ( $r [ $property ] as $value ) {
2020-08-24 09:15:32 -04:00
if ( $value === $query && $r [ 'FN' ]) {
2016-10-25 10:24:24 -04:00
return $r [ 'FN' ];
}
}
}
return $query ;
}
2023-06-28 06:27:55 -04:00
/**
2024-09-24 09:53:13 -04:00
* @ param list < Files_SharingShare > $shares
* @ param array < string , string >| null $updatedDisplayName
2023-06-28 06:27:55 -04:00
*
2024-09-24 09:53:13 -04:00
* @ return list < Files_SharingShare >
2023-06-28 06:27:55 -04:00
*/
private function fixMissingDisplayName ( array $shares , ? array $updatedDisplayName = null ) : array {
$userIds = $updated = [];
foreach ( $shares as $share ) {
// share is federated and share have no display name yet
if ( $share [ 'share_type' ] === IShare :: TYPE_REMOTE
&& ( $share [ 'share_with' ] ? ? '' ) !== ''
&& ( $share [ 'share_with_displayname' ] ? ? '' ) === '' ) {
$userIds [] = $userId = $share [ 'share_with' ];
if ( $updatedDisplayName !== null && array_key_exists ( $userId , $updatedDisplayName )) {
$share [ 'share_with_displayname' ] = $updatedDisplayName [ $userId ];
}
}
// prepping userIds with displayName to be updated
$updated [] = $share ;
}
// if $updatedDisplayName is not null, it means we should have already fixed displayNames of the shares
if ( $updatedDisplayName !== null ) {
return $updated ;
}
// get displayName for the generated list of userId with no displayName
$displayNames = $this -> retrieveFederatedDisplayName ( $userIds );
// if no displayName are updated, we exit
if ( empty ( $displayNames )) {
return $updated ;
}
// let's fix missing display name and returns all shares
return $this -> fixMissingDisplayName ( $shares , $displayNames );
}
/**
* get displayName of a list of userIds from the lookup - server ; through the globalsiteselector app .
* returns an array with userIds as keys and displayName as values .
*
* @ param array $userIds
* @ param bool $cacheOnly - do not reach LUS , get data from cache .
*
* @ return array
* @ throws ContainerExceptionInterface
*/
private function retrieveFederatedDisplayName ( array $userIds , bool $cacheOnly = false ) : array {
// check if gss is enabled and available
if ( count ( $userIds ) === 0
|| ! $this -> appManager -> isInstalled ( 'globalsiteselector' )
|| ! class_exists ( '\OCA\GlobalSiteSelector\Service\SlaveService' )) {
return [];
}
try {
2024-10-10 06:40:31 -04:00
$slaveService = Server :: get ( SlaveService :: class );
2023-06-28 06:27:55 -04:00
} catch ( \Throwable $e ) {
2024-04-15 15:38:26 -04:00
$this -> logger -> error (
2023-06-28 06:27:55 -04:00
$e -> getMessage (),
[ 'exception' => $e ]
);
return [];
}
return $slaveService -> getUsersDisplayName ( $userIds , $cacheOnly );
}
/**
* retrieve displayName from cache if available ( should be used on federated shares )
* if not available in cache / lus , try for get from address - book , else returns empty string .
*
* @ param string $userId
* @ param bool $cacheOnly if true will not reach the lus but will only get data from cache
*
* @ return string
*/
private function getCachedFederatedDisplayName ( string $userId , bool $cacheOnly = true ) : string {
$details = $this -> retrieveFederatedDisplayName ([ $userId ], $cacheOnly );
if ( array_key_exists ( $userId , $details )) {
return $details [ $userId ];
}
$displayName = $this -> getDisplayNameFromAddressBook ( $userId , 'CLOUD' );
return ( $displayName === $userId ) ? '' : $displayName ;
}
2015-11-06 06:05:19 -05:00
/**
* Get a specific share by id
*
2023-02-15 13:22:09 -05:00
* @ param string $id ID of the share
* @ param bool $include_tags Include tags in the share
2024-09-24 09:53:13 -04:00
* @ return DataResponse < Http :: STATUS_OK , list < Files_SharingShare > , array {} >
2023-02-15 13:22:09 -05:00
* @ throws OCSNotFoundException Share not found
2016-07-19 08:13:27 -04:00
*
2023-02-15 13:22:09 -05:00
* 200 : Share returned
2015-11-06 06:05:19 -05:00
*/
2024-07-25 07:14:46 -04:00
#[NoAdminRequired]
2022-09-23 09:51:55 -04:00
public function getShare ( string $id , bool $include_tags = false ) : DataResponse {
2015-11-06 06:05:19 -05:00
try {
2016-03-07 10:10:27 -05:00
$share = $this -> getShareById ( $id );
2016-02-02 08:18:59 -05:00
} catch ( ShareNotFound $e ) {
2022-06-07 07:07:19 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Wrong share ID, share does not exist' ));
2015-11-06 06:05:19 -05:00
}
2019-08-16 09:09:15 -04:00
try {
if ( $this -> canAccessShare ( $share )) {
2016-02-16 10:04:17 -05:00
$share = $this -> formatShare ( $share );
2022-09-19 05:11:09 -04:00
2022-09-23 09:51:55 -04:00
if ( $include_tags ) {
2025-02-04 16:40:00 -05:00
$share = Helper :: populateTags ([ $share ], \OCP\Server :: get ( ITagManager :: class ));
2022-09-21 02:28:03 -04:00
} else {
$share = [ $share ];
2022-09-19 05:11:09 -04:00
}
2022-09-21 02:28:03 -04:00
return new DataResponse ( $share );
2016-02-16 10:04:17 -05:00
}
2019-08-16 09:09:15 -04:00
} catch ( NotFoundException $e ) {
2022-07-28 07:11:38 -04:00
// Fall through
2015-11-24 03:37:17 -05:00
}
2016-02-16 10:04:17 -05:00
2022-06-07 07:07:19 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Wrong share ID, share does not exist' ));
2015-10-30 08:10:08 -04:00
}
/**
* Delete a share
*
2023-02-15 13:22:09 -05:00
* @ param string $id ID of the share
2024-09-24 09:53:13 -04:00
* @ return DataResponse < Http :: STATUS_OK , list < empty > , array {} >
2023-02-15 13:22:09 -05:00
* @ throws OCSNotFoundException Share not found
* @ throws OCSForbiddenException Missing permissions to delete the share
2016-07-19 08:13:27 -04:00
*
2023-02-15 13:22:09 -05:00
* 200 : Share deleted successfully
2015-10-30 08:10:08 -04:00
*/
2024-07-25 07:14:46 -04:00
#[NoAdminRequired]
2018-04-23 14:31:57 -04:00
public function deleteShare ( string $id ) : DataResponse {
2015-10-30 08:10:08 -04:00
try {
2016-03-07 10:10:27 -05:00
$share = $this -> getShareById ( $id );
2016-02-02 08:18:59 -05:00
} catch ( ShareNotFound $e ) {
2022-06-07 07:07:19 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Wrong share ID, share does not exist' ));
2015-11-02 13:49:39 -05:00
}
2016-03-09 03:11:41 -05:00
try {
2016-07-20 04:11:01 -04:00
$this -> lock ( $share -> getNode ());
2016-03-09 03:11:41 -05:00
} catch ( LockedException $e ) {
2019-08-26 07:11:09 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Could not delete share' ));
2016-03-09 03:11:41 -05:00
}
2016-10-25 04:18:42 -04:00
if ( ! $this -> canAccessShare ( $share )) {
2022-06-07 07:07:19 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Wrong share ID, share does not exist' ));
2015-11-24 03:37:17 -05:00
}
2019-08-26 07:11:09 -04:00
// if it's a group share or a room share
// we don't delete the share, but only the
// mount point. Allowing it to be restored
// from the deleted shares
if ( $this -> canDeleteShareFromSelf ( $share )) {
2024-10-18 06:04:22 -04:00
$this -> shareManager -> deleteFromSelf ( $share , $this -> userId );
2016-10-25 04:18:42 -04:00
} else {
2019-08-26 07:11:09 -04:00
if ( ! $this -> canDeleteShare ( $share )) {
throw new OCSForbiddenException ( $this -> l -> t ( 'Could not delete share' ));
}
2016-10-25 04:18:42 -04:00
$this -> shareManager -> deleteShare ( $share );
}
2015-10-30 08:10:08 -04:00
2016-07-20 04:44:52 -04:00
return new DataResponse ();
2015-10-30 08:10:08 -04:00
}
2015-11-24 03:37:17 -05:00
2015-12-15 03:54:50 -05:00
/**
2023-02-15 13:22:09 -05:00
* Create a share
2016-08-16 16:45:49 -04:00
*
2023-02-15 13:22:09 -05:00
* @ param string | null $path Path of the share
* @ param int | null $permissions Permissions for the share
* @ param int $shareType Type of the share
2025-01-20 07:03:45 -05:00
* @ param ? string $shareWith The entity this should be shared with
* @ param 'true' | 'false' | null $publicUpload If public uploading is allowed ( deprecated )
2023-02-15 13:22:09 -05:00
* @ param string $password Password for the share
* @ param string | null $sendPasswordByTalk Send the password for the share over Talk
2024-05-31 09:32:19 -04:00
* @ param ? string $expireDate The expiry date of the share in the user ' s timezone at 00 : 00.
2024-03-20 11:41:26 -04:00
* If $expireDate is not supplied or set to `null` , the system default will be used .
2023-02-15 13:22:09 -05:00
* @ param string $note Note for the share
* @ param string $label Label for the share ( only used in link and email )
* @ param string | null $attributes Additional attributes for the share
2024-07-09 05:09:01 -04:00
* @ param 'false' | 'true' | null $sendMail Send a mail to the recipient
2023-02-15 13:22:09 -05:00
*
2023-10-23 10:47:38 -04:00
* @ return DataResponse < Http :: STATUS_OK , Files_SharingShare , array {} >
2023-02-15 13:22:09 -05:00
* @ throws OCSBadRequestException Unknown share type
2016-07-20 04:41:09 -04:00
* @ throws OCSException
2023-02-15 13:22:09 -05:00
* @ throws OCSForbiddenException Creating the share is not allowed
* @ throws OCSNotFoundException Creating the share failed
2017-07-18 14:38:40 -04:00
* @ suppress PhanUndeclaredClassMethod
2023-02-15 13:22:09 -05:00
*
* 200 : Share created
2015-12-15 03:54:50 -05:00
*/
2024-07-25 07:14:46 -04:00
#[NoAdminRequired]
2025-04-15 04:32:47 -04:00
#[UserRateLimit(limit: 20, period: 600)]
2016-08-16 16:45:49 -04:00
public function createShare (
2024-03-28 11:13:19 -04:00
? string $path = null ,
? int $permissions = null ,
2018-04-23 14:31:57 -04:00
int $shareType = - 1 ,
2024-03-28 11:13:19 -04:00
? string $shareWith = null ,
2025-01-20 07:03:45 -05:00
? string $publicUpload = null ,
2018-04-23 14:31:57 -04:00
string $password = '' ,
2024-03-28 11:13:19 -04:00
? string $sendPasswordByTalk = null ,
2024-03-20 11:41:26 -04:00
? string $expireDate = null ,
2021-11-26 08:42:31 -05:00
string $note = '' ,
2022-05-25 03:55:22 -04:00
string $label = '' ,
2024-07-09 05:00:38 -04:00
? string $attributes = null ,
2024-07-09 05:09:01 -04:00
? string $sendMail = null ,
2018-04-23 14:31:57 -04:00
) : DataResponse {
2025-01-20 07:03:45 -05:00
assert ( $this -> userId !== null );
2015-12-15 03:54:50 -05:00
2025-01-20 07:03:45 -05:00
$share = $this -> shareManager -> newShare ();
$hasPublicUpload = $this -> getLegacyPublicUpload ( $publicUpload );
2017-12-01 08:49:35 -05:00
2015-12-15 03:54:50 -05:00
// Verify path
if ( $path === null ) {
2016-07-20 03:55:43 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Please specify a file or folder path' ));
2015-12-15 03:54:50 -05:00
}
2024-10-18 06:04:22 -04:00
$userFolder = $this -> rootFolder -> getUserFolder ( $this -> userId );
2015-12-15 03:54:50 -05:00
try {
2022-03-23 11:29:10 -04:00
/** @var \OC\Files\Node\Node $node */
$node = $userFolder -> get ( $path );
2016-03-17 06:09:11 -04:00
} catch ( NotFoundException $e ) {
2022-03-18 05:14:34 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Wrong path, file/folder does not exist' ));
2015-12-15 03:54:50 -05:00
}
2022-03-23 11:29:10 -04:00
// a user can have access to a file through different paths, with differing permissions
// combine all permissions to determine if the user can share this file
$nodes = $userFolder -> getById ( $node -> getId ());
foreach ( $nodes as $nodeById ) {
2025-01-20 07:03:45 -05:00
/** @var \OC\Files\FileInfo $fileInfo */
2022-03-23 11:29:10 -04:00
$fileInfo = $node -> getFileInfo ();
$fileInfo [ 'permissions' ] |= $nodeById -> getPermissions ();
}
$share -> setNode ( $node );
2016-03-17 06:09:11 -04:00
try {
2016-07-20 04:11:01 -04:00
$this -> lock ( $share -> getNode ());
2016-03-17 06:09:11 -04:00
} catch ( LockedException $e ) {
2016-07-20 03:55:43 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Could not create share' ));
2016-03-17 06:09:11 -04:00
}
2015-12-15 03:54:50 -05:00
2025-01-20 07:03:45 -05:00
// Set permissions
if ( $shareType === IShare :: TYPE_LINK || $shareType === IShare :: TYPE_EMAIL ) {
$permissions = $this -> getLinkSharePermissions ( $permissions , $hasPublicUpload );
$this -> validateLinkSharePermissions ( $node , $permissions , $hasPublicUpload );
} else {
// Use default permissions only for non-link shares to keep legacy behavior
if ( $permissions === null ) {
$permissions = ( int ) $this -> config -> getAppValue ( 'core' , 'shareapi_default_permissions' , ( string ) Constants :: PERMISSION_ALL );
}
// Non-link shares always require read permissions (link shares could be file drop)
2024-07-16 14:39:28 -04:00
$permissions |= Constants :: PERMISSION_READ ;
}
2015-12-15 03:54:50 -05:00
2025-01-20 07:03:45 -05:00
// For legacy reasons the API allows to pass PERMISSIONS_ALL even for single file shares (I look at you Talk)
2024-10-10 06:40:31 -04:00
if ( $node instanceof File ) {
2025-01-20 07:03:45 -05:00
// if this is a single file share we remove the DELETE and CREATE permissions
$permissions = $permissions & ~ ( Constants :: PERMISSION_DELETE | Constants :: PERMISSION_CREATE );
2015-12-15 03:54:50 -05:00
}
2019-08-06 04:22:32 -04:00
/**
2016-02-25 04:30:03 -05:00
* Hack for https :// github . com / owncloud / core / issues / 22587
* We check the permissions via webdav . But the permissions of the mount point
* do not equal the share permissions . Here we fix that for federated mounts .
*/
2022-03-23 11:29:10 -04:00
if ( $node -> getStorage () -> instanceOfStorage ( Storage :: class )) {
$permissions &= ~ ( $permissions & ~ $node -> getPermissions ());
2016-02-25 04:30:03 -05:00
}
2022-10-10 10:09:14 -04:00
if ( $attributes !== null ) {
$share = $this -> setShareAttributes ( $share , $attributes );
}
2025-02-04 16:40:00 -05:00
// Expire date checks
// Normally, null means no expiration date but we still set the default for backwards compatibility
// If the client sends an empty string, we set noExpirationDate to true
2024-03-20 11:41:26 -04:00
if ( $expireDate !== null ) {
if ( $expireDate !== '' ) {
try {
$expireDateTime = $this -> parseDate ( $expireDate );
$share -> setExpirationDate ( $expireDateTime );
} catch ( \Exception $e ) {
2024-10-22 02:20:04 -04:00
throw new OCSNotFoundException ( $e -> getMessage (), $e );
2024-03-20 11:41:26 -04:00
}
} else {
// Client sent empty string for expire date.
// Set noExpirationDate to true so overwrite is prevented.
$share -> setNoExpirationDate ( true );
2024-04-15 16:38:55 -04:00
}
}
2024-10-18 06:04:22 -04:00
$share -> setSharedBy ( $this -> userId );
2022-07-15 08:52:04 -04:00
2024-07-09 05:00:38 -04:00
// Handle mail send
2024-09-26 07:00:52 -04:00
if ( is_null ( $sendMail )) {
2024-12-17 08:49:49 -05:00
$allowSendMail = $this -> config -> getSystemValueBool ( 'sharing.enable_share_mail' , true );
if ( $allowSendMail !== true || $shareType === IShare :: TYPE_EMAIL ) {
// Define a default behavior when sendMail is not provided
// For email shares with a valid recipient, the default is to send the mail
// For all other share types, the default is to not send the mail
$allowSendMail = ( $shareType === IShare :: TYPE_EMAIL && $shareWith !== null && $shareWith !== '' );
}
2024-10-24 12:47:07 -04:00
$share -> setMailSend ( $allowSendMail );
2024-09-26 07:00:52 -04:00
} else {
2024-07-09 05:09:01 -04:00
$share -> setMailSend ( $sendMail === 'true' );
2024-07-09 05:00:38 -04:00
}
2020-04-29 10:43:39 -04:00
if ( $shareType === IShare :: TYPE_USER ) {
2015-12-15 03:54:50 -05:00
// Valid user is required to share
if ( $shareWith === null || ! $this -> userManager -> userExists ( $shareWith )) {
2022-09-21 11:44:32 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Please specify a valid account to share with' ));
2015-12-15 03:54:50 -05:00
}
2016-02-03 02:14:48 -05:00
$share -> setSharedWith ( $shareWith );
2015-12-15 03:54:50 -05:00
$share -> setPermissions ( $permissions );
2020-04-29 10:43:39 -04:00
} elseif ( $shareType === IShare :: TYPE_GROUP ) {
2016-03-18 11:36:27 -04:00
if ( ! $this -> shareManager -> allowGroupSharing ()) {
2016-07-20 03:55:43 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Group sharing is disabled by the administrator' ));
2016-03-18 11:36:27 -04:00
}
2015-12-15 03:54:50 -05:00
// Valid group is required to share
if ( $shareWith === null || ! $this -> groupManager -> groupExists ( $shareWith )) {
2016-07-20 03:55:43 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Please specify a valid group' ));
2015-12-15 03:54:50 -05:00
}
2016-02-03 02:14:48 -05:00
$share -> setSharedWith ( $shareWith );
2015-12-15 03:54:50 -05:00
$share -> setPermissions ( $permissions );
2020-04-29 10:43:39 -04:00
} elseif ( $shareType === IShare :: TYPE_LINK
|| $shareType === IShare :: TYPE_EMAIL ) {
2019-08-01 07:56:35 -04:00
// Can we even share links?
2015-12-15 03:54:50 -05:00
if ( ! $this -> shareManager -> shareApiAllowLinks ()) {
2016-07-20 03:55:43 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Public link sharing is disabled by the administrator' ));
2015-12-15 03:54:50 -05:00
}
2025-01-20 07:03:45 -05:00
$this -> validateLinkSharePermissions ( $node , $permissions , $hasPublicUpload );
2020-03-05 08:56:31 -05:00
$share -> setPermissions ( $permissions );
2015-12-15 03:54:50 -05:00
// Set password
2016-01-27 09:42:11 -05:00
if ( $password !== '' ) {
$share -> setPassword ( $password );
}
2015-12-15 03:54:50 -05:00
2019-08-01 07:56:35 -04:00
// Only share by mail have a recipient
2020-12-29 18:48:01 -05:00
if ( is_string ( $shareWith ) && $shareType === IShare :: TYPE_EMAIL ) {
2024-07-09 05:00:38 -04:00
// If sending a mail have been requested, validate the mail address
if ( $share -> getMailSend () && ! $this -> mailer -> validateMailAddress ( $shareWith )) {
throw new OCSNotFoundException ( $this -> l -> t ( 'Please specify a valid email address' ));
}
2019-08-01 07:56:35 -04:00
$share -> setSharedWith ( $shareWith );
2020-10-20 07:58:01 -04:00
}
// If we have a label, use it
2025-01-26 13:27:46 -05:00
if ( $label !== '' ) {
if ( strlen ( $label ) > 255 ) {
throw new OCSBadRequestException ( 'Maximum label length is 255' );
}
2020-10-20 07:58:01 -04:00
$share -> setLabel ( $label );
2018-10-16 04:31:38 -04:00
}
2018-10-15 06:27:56 -04:00
if ( $sendPasswordByTalk === 'true' ) {
if ( ! $this -> appManager -> isEnabledForUser ( 'spreed' )) {
2022-03-23 11:29:10 -04:00
throw new OCSForbiddenException ( $this -> l -> t ( 'Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled' , [ $node -> getPath ()]));
2018-10-15 06:27:56 -04:00
}
$share -> setSendPasswordByTalk ( true );
}
2020-04-29 10:43:39 -04:00
} elseif ( $shareType === IShare :: TYPE_REMOTE ) {
2016-02-04 05:13:06 -05:00
if ( ! $this -> shareManager -> outgoingServer2ServerSharesAllowed ()) {
2022-03-23 11:29:10 -04:00
throw new OCSForbiddenException ( $this -> l -> t ( 'Sharing %1$s failed because the back end does not allow shares from type %2$s' , [ $node -> getPath (), $shareType ]));
2016-02-04 05:13:06 -05:00
}
2021-01-25 09:26:16 -05:00
if ( $shareWith === null ) {
2022-09-21 11:44:32 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Please specify a valid federated account ID' ));
2021-01-25 09:26:16 -05:00
}
2016-02-04 04:01:40 -05:00
$share -> setSharedWith ( $shareWith );
$share -> setPermissions ( $permissions );
2023-06-28 06:27:55 -04:00
$share -> setSharedWithDisplayName ( $this -> getCachedFederatedDisplayName ( $shareWith , false ));
2020-04-29 10:43:39 -04:00
} elseif ( $shareType === IShare :: TYPE_REMOTE_GROUP ) {
2018-06-13 08:19:59 -04:00
if ( ! $this -> shareManager -> outgoingServer2ServerGroupSharesAllowed ()) {
2022-03-23 11:29:10 -04:00
throw new OCSForbiddenException ( $this -> l -> t ( 'Sharing %1$s failed because the back end does not allow shares from type %2$s' , [ $node -> getPath (), $shareType ]));
2018-06-13 08:19:59 -04:00
}
2021-01-25 09:26:16 -05:00
if ( $shareWith === null ) {
2021-04-16 02:56:20 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Please specify a valid federated group ID' ));
2021-01-25 09:26:16 -05:00
}
2018-06-13 08:19:59 -04:00
$share -> setSharedWith ( $shareWith );
$share -> setPermissions ( $permissions );
2020-04-29 10:43:39 -04:00
} elseif ( $shareType === IShare :: TYPE_CIRCLE ) {
2025-02-04 16:40:00 -05:00
if ( ! \OCP\Server :: get ( IAppManager :: class ) -> isEnabledForUser ( 'circles' ) || ! class_exists ( '\OCA\Circles\ShareByCircleProvider' )) {
2024-08-06 08:48:07 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'You cannot share to a Team if the app is not enabled' ));
2017-03-17 15:48:33 -04:00
}
2024-10-10 06:40:31 -04:00
$circle = Circles :: detailsCircle ( $shareWith );
2017-03-17 15:48:33 -04:00
2024-08-06 08:48:07 -04:00
// Valid team is required to share
2017-03-17 15:48:33 -04:00
if ( $circle === null ) {
2024-08-06 08:48:07 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Please specify a valid team' ));
2017-03-17 15:48:33 -04:00
}
$share -> setSharedWith ( $shareWith );
$share -> setPermissions ( $permissions );
2020-04-29 10:43:39 -04:00
} elseif ( $shareType === IShare :: TYPE_ROOM ) {
2018-06-29 07:22:26 -04:00
try {
2024-05-29 07:25:41 -04:00
$this -> getRoomShareHelper () -> createShare ( $share , $shareWith , $permissions , $expireDate ? ? '' );
2025-02-04 16:40:00 -05:00
} catch ( ContainerExceptionInterface $e ) {
2022-03-23 11:29:10 -04:00
throw new OCSForbiddenException ( $this -> l -> t ( 'Sharing %s failed because the back end does not support room shares' , [ $node -> getPath ()]));
2018-06-29 07:22:26 -04:00
}
2020-12-03 10:03:35 -05:00
} elseif ( $shareType === IShare :: TYPE_DECK ) {
try {
2024-05-29 07:25:41 -04:00
$this -> getDeckShareHelper () -> createShare ( $share , $shareWith , $permissions , $expireDate ? ? '' );
2025-02-04 16:40:00 -05:00
} catch ( ContainerExceptionInterface $e ) {
2022-03-23 11:29:10 -04:00
throw new OCSForbiddenException ( $this -> l -> t ( 'Sharing %s failed because the back end does not support room shares' , [ $node -> getPath ()]));
2020-12-03 10:03:35 -05:00
}
2023-02-20 04:50:31 -05:00
} elseif ( $shareType === IShare :: TYPE_SCIENCEMESH ) {
try {
2024-05-29 07:25:41 -04:00
$this -> getSciencemeshShareHelper () -> createShare ( $share , $shareWith , $permissions , $expireDate ? ? '' );
2025-02-04 16:40:00 -05:00
} catch ( ContainerExceptionInterface $e ) {
2023-03-13 06:31:20 -04:00
throw new OCSForbiddenException ( $this -> l -> t ( 'Sharing %s failed because the back end does not support ScienceMesh shares' , [ $node -> getPath ()]));
2023-02-20 04:50:31 -05:00
}
2015-12-15 03:54:50 -05:00
} else {
2016-07-20 04:44:52 -04:00
throw new OCSBadRequestException ( $this -> l -> t ( 'Unknown share type' ));
2015-12-15 03:54:50 -05:00
}
$share -> setShareType ( $shareType );
2025-01-19 05:36:24 -05:00
$this -> checkInheritedAttributes ( $share );
2015-12-15 03:54:50 -05:00
2021-11-26 08:42:31 -05:00
if ( $note !== '' ) {
$share -> setNote ( $note );
}
2015-12-15 03:54:50 -05:00
try {
$share = $this -> shareManager -> createShare ( $share );
2024-11-19 03:40:26 -05:00
} catch ( HintException $e ) {
2016-01-05 06:50:00 -05:00
$code = $e -> getCode () === 0 ? 403 : $e -> getCode ();
2016-07-20 04:41:09 -04:00
throw new OCSException ( $e -> getHint (), $code );
2025-04-09 10:12:18 -04:00
} catch ( GenericShareException | \InvalidArgumentException $e ) {
$this -> logger -> error ( $e -> getMessage (), [ 'exception' => $e ]);
throw new OCSForbiddenException ( $e -> getMessage (), $e );
2016-09-20 05:29:12 -04:00
} catch ( \Exception $e ) {
2024-04-15 15:38:26 -04:00
$this -> logger -> error ( $e -> getMessage (), [ 'exception' => $e ]);
2024-10-22 02:20:04 -04:00
throw new OCSForbiddenException ( 'Failed to create share.' , $e );
2015-12-15 03:54:50 -05:00
}
2016-09-21 12:55:58 -04:00
$output = $this -> formatShare ( $share );
2016-03-09 03:11:41 -05:00
2016-08-09 04:04:29 -04:00
return new DataResponse ( $output );
2015-12-15 03:54:50 -05:00
}
2016-01-29 09:26:04 -05:00
/**
2019-06-25 16:34:38 -04:00
* @ param null | Node $node
2016-11-10 03:13:25 -05:00
* @ param boolean $includeTags
2019-06-25 16:34:38 -04:00
*
2024-09-24 09:53:13 -04:00
* @ return list < Files_SharingShare >
2016-01-29 09:26:04 -05:00
*/
2019-06-25 16:34:38 -04:00
private function getSharedWithMe ( $node , bool $includeTags ) : array {
2024-10-18 06:04:22 -04:00
$userShares = $this -> shareManager -> getSharedWith ( $this -> userId , IShare :: TYPE_USER , $node , - 1 , 0 );
$groupShares = $this -> shareManager -> getSharedWith ( $this -> userId , IShare :: TYPE_GROUP , $node , - 1 , 0 );
$circleShares = $this -> shareManager -> getSharedWith ( $this -> userId , IShare :: TYPE_CIRCLE , $node , - 1 , 0 );
$roomShares = $this -> shareManager -> getSharedWith ( $this -> userId , IShare :: TYPE_ROOM , $node , - 1 , 0 );
$deckShares = $this -> shareManager -> getSharedWith ( $this -> userId , IShare :: TYPE_DECK , $node , - 1 , 0 );
$sciencemeshShares = $this -> shareManager -> getSharedWith ( $this -> userId , IShare :: TYPE_SCIENCEMESH , $node , - 1 , 0 );
2015-12-03 04:51:41 -05:00
2023-02-20 04:50:31 -05:00
$shares = array_merge ( $userShares , $groupShares , $circleShares , $roomShares , $deckShares , $sciencemeshShares );
2015-12-03 04:51:41 -05:00
2020-05-05 12:46:24 -04:00
$filteredShares = array_filter ( $shares , function ( IShare $share ) {
2024-10-18 06:04:22 -04:00
return $share -> getShareOwner () !== $this -> userId ;
2016-09-07 12:38:08 -04:00
});
2015-12-03 04:51:41 -05:00
$formatted = [];
2020-05-05 12:46:24 -04:00
foreach ( $filteredShares as $share ) {
2016-01-27 03:02:12 -05:00
if ( $this -> canAccessShare ( $share )) {
2016-02-16 10:04:17 -05:00
try {
$formatted [] = $this -> formatShare ( $share );
} catch ( NotFoundException $e ) {
// Ignore this share
}
2016-01-27 03:02:12 -05:00
}
2015-12-03 04:51:41 -05:00
}
2016-11-10 03:13:25 -05:00
if ( $includeTags ) {
2025-02-04 16:40:00 -05:00
$formatted = Helper :: populateTags ( $formatted , \OCP\Server :: get ( ITagManager :: class ));
2016-11-10 03:13:25 -05:00
}
2019-06-25 16:34:38 -04:00
return $formatted ;
2015-12-03 04:51:41 -05:00
}
2016-01-19 08:35:16 -05:00
/**
2024-10-18 06:04:22 -04:00
* @ param Node $folder
2019-06-25 16:34:38 -04:00
*
2024-09-24 09:53:13 -04:00
* @ return list < Files_SharingShare >
2016-07-20 04:41:09 -04:00
* @ throws OCSBadRequestException
2019-06-25 16:34:38 -04:00
* @ throws NotFoundException
2016-01-19 08:35:16 -05:00
*/
2019-08-19 04:53:29 -04:00
private function getSharesInDir ( Node $folder ) : array {
2024-10-10 06:40:31 -04:00
if ( ! ( $folder instanceof Folder )) {
2016-07-20 04:41:09 -04:00
throw new OCSBadRequestException ( $this -> l -> t ( 'Not a directory' ));
2016-01-19 08:35:16 -05:00
}
$nodes = $folder -> getDirectoryListing ();
2019-10-25 04:45:49 -04:00
2024-10-18 06:04:22 -04:00
/** @var IShare[] $shares */
2020-04-09 07:53:40 -04:00
$shares = array_reduce ( $nodes , function ( $carry , $node ) {
2019-10-25 04:45:49 -04:00
$carry = array_merge ( $carry , $this -> getAllShares ( $node , true ));
return $carry ;
}, []);
2016-01-19 08:35:16 -05:00
2019-08-19 04:53:29 -04:00
// filter out duplicate shares
$known = [];
2019-11-26 14:28:08 -05:00
$formatted = $miniFormatted = [];
$resharingRight = false ;
$known = [];
foreach ( $shares as $share ) {
2024-10-18 06:04:22 -04:00
if ( in_array ( $share -> getId (), $known ) || $share -> getSharedWith () === $this -> userId ) {
2019-11-26 14:28:08 -05:00
continue ;
2019-08-19 04:53:29 -04:00
}
2019-06-25 16:34:38 -04:00
try {
$format = $this -> formatShare ( $share );
$known [] = $share -> getId ();
$formatted [] = $format ;
2024-10-18 06:04:22 -04:00
if ( $share -> getSharedBy () === $this -> userId ) {
2019-06-25 16:34:38 -04:00
$miniFormatted [] = $format ;
}
2024-10-18 06:04:22 -04:00
if ( ! $resharingRight && $this -> shareProviderResharingRights ( $this -> userId , $share , $folder )) {
2019-06-25 16:34:38 -04:00
$resharingRight = true ;
}
} catch ( \Exception $e ) {
//Ignore this share
}
}
if ( ! $resharingRight ) {
$formatted = $miniFormatted ;
}
return $formatted ;
2016-01-19 08:35:16 -05:00
}
/**
2023-02-15 13:22:09 -05:00
* Get shares of the current user
2016-08-17 04:05:09 -04:00
*
2023-02-15 13:22:09 -05:00
* @ param string $shared_with_me Only get shares with the current user
* @ param string $reshares Only get shares by the current user and reshares
* @ param string $subfiles Only get all shares in a folder
* @ param string $path Get shares for a specific path
* @ param string $include_tags Include tags in the share
2016-01-19 08:35:16 -05:00
*
2024-09-24 09:53:13 -04:00
* @ return DataResponse < Http :: STATUS_OK , list < Files_SharingShare > , array {} >
2023-02-15 13:22:09 -05:00
* @ throws OCSNotFoundException The folder was not found or is inaccessible
2019-06-25 16:34:38 -04:00
*
2023-02-15 13:22:09 -05:00
* 200 : Shares returned
2016-01-19 08:35:16 -05:00
*/
2024-07-25 07:14:46 -04:00
#[NoAdminRequired]
2016-08-17 04:05:09 -04:00
public function getShares (
2018-04-23 14:31:57 -04:00
string $shared_with_me = 'false' ,
string $reshares = 'false' ,
string $subfiles = 'false' ,
2019-06-25 16:34:38 -04:00
string $path = '' ,
2018-04-23 14:31:57 -04:00
string $include_tags = 'false' ,
) : DataResponse {
2019-06-25 16:34:38 -04:00
$node = null ;
if ( $path !== '' ) {
2024-10-18 06:04:22 -04:00
$userFolder = $this -> rootFolder -> getUserFolder ( $this -> userId );
2015-12-03 04:51:41 -05:00
try {
2019-06-25 16:34:38 -04:00
$node = $userFolder -> get ( $path );
$this -> lock ( $node );
} catch ( NotFoundException $e ) {
throw new OCSNotFoundException (
2022-03-18 05:14:34 -04:00
$this -> l -> t ( 'Wrong path, file/folder does not exist' )
2019-06-25 16:34:38 -04:00
);
2016-03-17 06:09:11 -04:00
} catch ( LockedException $e ) {
2019-06-25 16:34:38 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Could not lock node' ));
2015-12-03 04:51:41 -05:00
}
}
2019-06-25 16:34:38 -04:00
$shares = $this -> getFormattedShares (
2024-10-18 06:04:22 -04:00
$this -> userId ,
2019-06-25 16:34:38 -04:00
$node ,
( $shared_with_me === 'true' ),
( $reshares === 'true' ),
( $subfiles === 'true' ),
( $include_tags === 'true' )
);
2018-04-24 02:07:25 -04:00
2019-06-25 16:34:38 -04:00
return new DataResponse ( $shares );
}
2016-01-29 09:26:04 -05:00
2025-01-20 07:03:45 -05:00
private function getLinkSharePermissions ( ? int $permissions , ? bool $legacyPublicUpload ) : int {
$permissions = $permissions ? ? Constants :: PERMISSION_READ ;
// Legacy option handling
if ( $legacyPublicUpload !== null ) {
$permissions = $legacyPublicUpload
? ( Constants :: PERMISSION_READ | Constants :: PERMISSION_CREATE | Constants :: PERMISSION_UPDATE | Constants :: PERMISSION_DELETE )
: Constants :: PERMISSION_READ ;
}
// TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
if ( $this -> hasPermission ( $permissions , Constants :: PERMISSION_READ )
&& $this -> shareManager -> outgoingServer2ServerSharesAllowed ()) {
$permissions |= Constants :: PERMISSION_SHARE ;
}
return $permissions ;
}
/**
* Helper to check for legacy " publicUpload " handling .
* If the value is set to `true` or `false` then true or false are returned .
* Otherwise null is returned to indicate that the option was not ( or wrong ) set .
*
* @ param null | string $legacyPublicUpload The value of `publicUpload`
*/
private function getLegacyPublicUpload ( ? string $legacyPublicUpload ) : ? bool {
if ( $legacyPublicUpload === 'true' ) {
return true ;
} elseif ( $legacyPublicUpload === 'false' ) {
return false ;
}
// Not set at all
return null ;
}
/**
* For link and email shares validate that only allowed combinations are set .
*
* @ throw OCSBadRequestException If permission combination is invalid .
* @ throw OCSForbiddenException If public upload was forbidden by the administrator .
*/
private function validateLinkSharePermissions ( Node $node , int $permissions , ? bool $legacyPublicUpload ) : void {
if ( $legacyPublicUpload && ( $node instanceof File )) {
throw new OCSBadRequestException ( $this -> l -> t ( 'Public upload is only possible for publicly shared folders' ));
}
// We need at least READ or CREATE (file drop)
if ( ! $this -> hasPermission ( $permissions , Constants :: PERMISSION_READ )
&& ! $this -> hasPermission ( $permissions , Constants :: PERMISSION_CREATE )) {
throw new OCSBadRequestException ( $this -> l -> t ( 'Share must at least have READ or CREATE permissions' ));
}
// UPDATE and DELETE require a READ permission
if ( ! $this -> hasPermission ( $permissions , Constants :: PERMISSION_READ )
&& ( $this -> hasPermission ( $permissions , Constants :: PERMISSION_UPDATE ) || $this -> hasPermission ( $permissions , Constants :: PERMISSION_DELETE ))) {
throw new OCSBadRequestException ( $this -> l -> t ( 'Share must have READ permission if UPDATE or DELETE permission is set' ));
}
// Check if public uploading was disabled
if ( $this -> hasPermission ( $permissions , Constants :: PERMISSION_CREATE )
&& ! $this -> shareManager -> shareApiLinkAllowPublicUpload ()) {
throw new OCSForbiddenException ( $this -> l -> t ( 'Public upload disabled by the administrator' ));
}
}
2019-06-25 16:34:38 -04:00
/**
* @ param string $viewer
* @ param Node $node
* @ param bool $sharedWithMe
* @ param bool $reShares
* @ param bool $subFiles
* @ param bool $includeTags
*
2024-09-24 09:53:13 -04:00
* @ return list < Files_SharingShare >
2019-06-25 16:34:38 -04:00
* @ throws NotFoundException
* @ throws OCSBadRequestException
*/
private function getFormattedShares (
2020-04-29 10:43:39 -04:00
string $viewer ,
$node = null ,
bool $sharedWithMe = false ,
bool $reShares = false ,
bool $subFiles = false ,
bool $includeTags = false ,
2019-06-25 16:34:38 -04:00
) : array {
if ( $sharedWithMe ) {
return $this -> getSharedWithMe ( $node , $includeTags );
2015-12-03 04:51:41 -05:00
}
2019-06-25 16:34:38 -04:00
if ( $subFiles ) {
return $this -> getSharesInDir ( $node );
2019-08-19 04:53:29 -04:00
}
2015-12-03 04:51:41 -05:00
2019-06-25 16:34:38 -04:00
$shares = $this -> getSharesFromNode ( $viewer , $node , $reShares );
2019-12-02 14:16:33 -05:00
$known = $formatted = $miniFormatted = [];
2018-10-29 05:03:52 -04:00
$resharingRight = false ;
2015-12-03 04:51:41 -05:00
foreach ( $shares as $share ) {
2020-03-02 03:18:04 -05:00
try {
$share -> getNode ();
} catch ( NotFoundException $e ) {
/*
* Ignore shares where we can ' t get the node
2020-04-29 10:43:39 -04:00
* For example deleted shares
2020-03-02 03:18:04 -05:00
*/
continue ;
}
2020-05-05 12:46:24 -04:00
if ( in_array ( $share -> getId (), $known )
2024-10-18 06:04:22 -04:00
|| ( $share -> getSharedWith () === $this -> userId && $share -> getShareType () === IShare :: TYPE_USER )) {
2019-12-02 14:16:33 -05:00
continue ;
}
$known [] = $share -> getId ();
2016-02-16 10:04:17 -05:00
try {
2019-06-25 16:34:38 -04:00
/** @var IShare $share */
$format = $this -> formatShare ( $share , $node );
2019-12-02 14:16:33 -05:00
$formatted [] = $format ;
2019-08-19 04:53:29 -04:00
// let's also build a list of shares created
// by the current user only, in case
// there is no resharing rights
2024-10-18 06:04:22 -04:00
if ( $share -> getSharedBy () === $this -> userId ) {
2018-11-01 10:01:01 -04:00
$miniFormatted [] = $format ;
}
2019-08-19 04:53:29 -04:00
// check if one of those share is shared with me
// and if I have resharing rights on it
2024-10-18 06:04:22 -04:00
if ( ! $resharingRight && $this -> shareProviderResharingRights ( $this -> userId , $share , $node )) {
2018-10-29 05:03:52 -04:00
$resharingRight = true ;
}
2019-06-25 16:34:38 -04:00
} catch ( InvalidPathException | NotFoundException $e ) {
2016-02-16 10:04:17 -05:00
}
2015-12-03 04:51:41 -05:00
}
2018-10-29 05:03:52 -04:00
if ( ! $resharingRight ) {
2018-11-01 10:01:01 -04:00
$formatted = $miniFormatted ;
2018-10-29 05:03:52 -04:00
}
2023-06-28 06:27:55 -04:00
// fix eventual missing display name from federated shares
$formatted = $this -> fixMissingDisplayName ( $formatted );
2019-06-25 16:34:38 -04:00
if ( $includeTags ) {
$formatted =
2025-02-04 16:40:00 -05:00
Helper :: populateTags ( $formatted , \OCP\Server :: get ( ITagManager :: class ));
2016-11-10 03:13:25 -05:00
}
2019-06-25 16:34:38 -04:00
return $formatted ;
2015-12-03 04:51:41 -05:00
}
2019-06-25 16:34:38 -04:00
/**
2023-02-15 13:22:09 -05:00
* Get all shares relative to a file , including parent folders shares rights
2019-06-25 16:34:38 -04:00
*
2023-02-15 13:22:09 -05:00
* @ param string $path Path all shares will be relative to
2019-06-25 16:34:38 -04:00
*
2024-09-24 09:53:13 -04:00
* @ return DataResponse < Http :: STATUS_OK , list < Files_SharingShare > , array {} >
2019-06-25 16:34:38 -04:00
* @ throws InvalidPathException
* @ throws NotFoundException
2023-02-15 13:22:09 -05:00
* @ throws OCSNotFoundException The given path is invalid
2019-06-25 16:34:38 -04:00
* @ throws SharingRightsException
2023-02-15 13:22:09 -05:00
*
* 200 : Shares returned
2019-06-25 16:34:38 -04:00
*/
2024-07-25 07:14:46 -04:00
#[NoAdminRequired]
2019-06-25 16:34:38 -04:00
public function getInheritedShares ( string $path ) : DataResponse {
// get Node from (string) path.
2024-10-18 06:04:22 -04:00
$userFolder = $this -> rootFolder -> getUserFolder ( $this -> userId );
2019-06-25 16:34:38 -04:00
try {
$node = $userFolder -> get ( $path );
$this -> lock ( $node );
2024-10-10 06:40:31 -04:00
} catch ( NotFoundException $e ) {
2022-03-18 05:14:34 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Wrong path, file/folder does not exist' ));
2019-06-25 16:34:38 -04:00
} catch ( LockedException $e ) {
throw new OCSNotFoundException ( $this -> l -> t ( 'Could not lock path' ));
}
2020-04-01 09:07:35 -04:00
if ( ! ( $node -> getPermissions () & Constants :: PERMISSION_SHARE )) {
2024-07-12 04:41:41 -04:00
throw new SharingRightsException ( $this -> l -> t ( 'no sharing rights on this item' ));
2020-04-01 09:07:35 -04:00
}
// The current top parent we have access to
$parent = $node ;
2019-06-25 16:34:38 -04:00
// initiate real owner.
$owner = $node -> getOwner ()
-> getUID ();
if ( ! $this -> userManager -> userExists ( $owner )) {
return new DataResponse ([]);
}
// get node based on the owner, fix owner in case of external storage
$userFolder = $this -> rootFolder -> getUserFolder ( $owner );
if ( $node -> getId () !== $userFolder -> getId () && ! $userFolder -> isSubNode ( $node )) {
$owner = $node -> getOwner ()
-> getUID ();
$userFolder = $this -> rootFolder -> getUserFolder ( $owner );
2024-02-09 03:54:52 -05:00
$node = $userFolder -> getFirstNodeById ( $node -> getId ());
2019-06-25 16:34:38 -04:00
}
$basePath = $userFolder -> getPath ();
// generate node list for each parent folders
/** @var Node[] $nodes */
$nodes = [];
2024-08-05 10:09:33 -04:00
while ( true ) {
2019-06-25 16:34:38 -04:00
$node = $node -> getParent ();
2024-08-05 10:09:33 -04:00
if ( $node -> getPath () === $basePath ) {
break ;
}
2020-01-08 04:56:14 -05:00
$nodes [] = $node ;
2019-06-25 16:34:38 -04:00
}
2020-04-01 09:07:35 -04:00
// The user that is requesting this list
2024-10-18 06:04:22 -04:00
$currentUserFolder = $this -> rootFolder -> getUserFolder ( $this -> userId );
2020-04-01 09:07:35 -04:00
2019-06-25 16:34:38 -04:00
// for each nodes, retrieve shares.
$shares = [];
2020-04-01 09:07:35 -04:00
2019-06-25 16:34:38 -04:00
foreach ( $nodes as $node ) {
$getShares = $this -> getFormattedShares ( $owner , $node , false , true );
2020-04-01 09:07:35 -04:00
2024-02-09 03:54:52 -05:00
$currentUserNode = $currentUserFolder -> getFirstNodeById ( $node -> getId ());
if ( $currentUserNode ) {
$parent = $currentUserNode ;
2020-04-01 09:07:35 -04:00
}
$subPath = $currentUserFolder -> getRelativePath ( $parent -> getPath ());
foreach ( $getShares as & $share ) {
$share [ 'via_fileid' ] = $parent -> getId ();
$share [ 'via_path' ] = $subPath ;
}
2019-06-25 16:34:38 -04:00
$this -> mergeFormattedShares ( $shares , $getShares );
}
return new DataResponse ( array_values ( $shares ));
}
2022-02-02 10:10:52 -05:00
/**
* Check whether a set of permissions contains the permissions to check .
*/
private function hasPermission ( int $permissionsSet , int $permissionsToCheck ) : bool {
return ( $permissionsSet & $permissionsToCheck ) === $permissionsToCheck ;
}
2016-01-22 08:52:20 -05:00
/**
2023-02-15 13:22:09 -05:00
* Update a share
*
* @ param string $id ID of the share
* @ param int | null $permissions New permissions
* @ param string | null $password New password
* @ param string | null $sendPasswordByTalk New condition if the password should be send over Talk
* @ param string | null $publicUpload New condition if public uploading is allowed
* @ param string | null $expireDate New expiry date
* @ param string | null $note New note
* @ param string | null $label New label
* @ param string | null $hideDownload New condition if the download should be hidden
* @ param string | null $attributes New additional attributes
2024-07-09 05:09:01 -04:00
* @ param string | null $sendMail if the share should be send by mail .
2024-07-09 05:00:38 -04:00
* Considering the share already exists , no mail will be send after the share is updated .
* You will have to use the sendMail action to send the mail .
* @ param string | null $shareWith New recipient for email shares
2024-12-16 18:53:12 -05:00
* @ param string | null $token New token
2023-10-23 10:47:38 -04:00
* @ return DataResponse < Http :: STATUS_OK , Files_SharingShare , array {} >
2023-02-15 13:22:09 -05:00
* @ throws OCSBadRequestException Share could not be updated because the requested changes are invalid
* @ throws OCSForbiddenException Missing permissions to update the share
* @ throws OCSNotFoundException Share not found
*
* 200 : Share updated successfully
2016-01-22 08:52:20 -05:00
*/
2024-07-25 07:14:46 -04:00
#[NoAdminRequired]
2016-08-17 04:05:09 -04:00
public function updateShare (
2018-04-23 14:31:57 -04:00
string $id ,
2024-03-28 11:13:19 -04:00
? int $permissions = null ,
? string $password = null ,
? string $sendPasswordByTalk = null ,
? string $publicUpload = null ,
? string $expireDate = null ,
? string $note = null ,
? string $label = null ,
? string $hideDownload = null ,
2024-07-09 05:00:38 -04:00
? string $attributes = null ,
2024-07-09 05:09:01 -04:00
? string $sendMail = null ,
2024-12-16 18:53:12 -05:00
? string $token = null ,
2018-04-23 14:31:57 -04:00
) : DataResponse {
2016-01-22 08:52:20 -05:00
try {
2016-03-07 10:10:27 -05:00
$share = $this -> getShareById ( $id );
2016-02-02 08:18:59 -05:00
} catch ( ShareNotFound $e ) {
2022-06-07 07:07:19 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Wrong share ID, share does not exist' ));
2016-01-22 08:52:20 -05:00
}
2016-07-20 04:11:01 -04:00
$this -> lock ( $share -> getNode ());
2016-03-09 03:11:41 -05:00
2016-07-28 10:52:00 -04:00
if ( ! $this -> canAccessShare ( $share , false )) {
2022-06-07 07:07:19 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Wrong share ID, share does not exist' ));
2016-01-22 08:52:20 -05:00
}
2019-08-26 07:11:09 -04:00
if ( ! $this -> canEditShare ( $share )) {
2024-07-12 04:41:41 -04:00
throw new OCSForbiddenException ( $this -> l -> t ( 'You are not allowed to edit incoming shares' ));
2018-11-20 03:42:01 -05:00
}
2019-08-06 04:22:32 -04:00
if (
$permissions === null &&
2018-10-17 04:50:58 -04:00
$password === null &&
$sendPasswordByTalk === null &&
$publicUpload === null &&
$expireDate === null &&
$note === null &&
$label === null &&
2022-05-24 06:08:07 -04:00
$hideDownload === null &&
2024-07-09 05:00:38 -04:00
$attributes === null &&
2024-12-16 18:53:12 -05:00
$sendMail === null &&
$token === null
2018-10-17 04:50:58 -04:00
) {
2017-03-30 11:03:04 -04:00
throw new OCSBadRequestException ( $this -> l -> t ( 'Wrong or no update parameter given' ));
}
2019-08-06 04:22:32 -04:00
if ( $note !== null ) {
2018-07-12 08:55:50 -04:00
$share -> setNote ( $note );
}
2022-10-10 10:09:14 -04:00
if ( $attributes !== null ) {
$share = $this -> setShareAttributes ( $share , $attributes );
2022-07-15 11:11:54 -04:00
}
2024-07-09 05:00:38 -04:00
// Handle mail send
2024-07-09 05:09:01 -04:00
if ( $sendMail === 'true' || $sendMail === 'false' ) {
$share -> setMailSend ( $sendMail === 'true' );
2024-07-09 05:00:38 -04:00
}
2019-08-06 04:22:32 -04:00
/**
2025-01-20 07:03:45 -05:00
* expiration date , password and publicUpload only make sense for link shares
2016-01-27 10:46:48 -05:00
*/
2020-04-29 10:43:39 -04:00
if ( $share -> getShareType () === IShare :: TYPE_LINK
|| $share -> getShareType () === IShare :: TYPE_EMAIL ) {
2019-08-06 04:22:32 -04:00
2018-10-18 06:38:07 -04:00
// Update hide download state
2024-08-02 08:32:20 -04:00
$attributes = $share -> getAttributes () ? ? $share -> newAttributes ();
2018-10-18 06:38:07 -04:00
if ( $hideDownload === 'true' ) {
$share -> setHideDownload ( true );
2024-08-02 08:32:20 -04:00
$attributes -> setAttribute ( 'permissions' , 'download' , false );
2020-04-10 04:35:09 -04:00
} elseif ( $hideDownload === 'false' ) {
2018-10-18 06:38:07 -04:00
$share -> setHideDownload ( false );
2024-08-02 08:32:20 -04:00
$attributes -> setAttribute ( 'permissions' , 'download' , true );
2018-10-18 06:38:07 -04:00
}
2024-08-02 08:32:20 -04:00
$share -> setAttributes ( $attributes );
2018-10-18 06:38:07 -04:00
2025-01-20 07:03:45 -05:00
// If either manual permissions are specified or publicUpload
// then we need to also update the permissions of the share
if ( $permissions !== null || $publicUpload !== null ) {
$hasPublicUpload = $this -> getLegacyPublicUpload ( $publicUpload );
$permissions = $this -> getLinkSharePermissions ( $permissions ? ? Constants :: PERMISSION_READ , $hasPublicUpload );
$this -> validateLinkSharePermissions ( $share -> getNode (), $permissions , $hasPublicUpload );
$share -> setPermissions ( $permissions );
2016-01-27 14:32:04 -05:00
}
2016-01-22 08:52:20 -05:00
2016-01-27 10:46:48 -05:00
if ( $password === '' ) {
$share -> setPassword ( null );
2020-04-10 04:35:09 -04:00
} elseif ( $password !== null ) {
2016-01-27 10:46:48 -05:00
$share -> setPassword ( $password );
2016-01-22 08:52:20 -05:00
}
2020-10-20 07:58:01 -04:00
if ( $label !== null ) {
2020-06-12 08:29:36 -04:00
if ( strlen ( $label ) > 255 ) {
2022-07-28 07:11:38 -04:00
throw new OCSBadRequestException ( 'Maximum label length is 255' );
2020-06-12 08:29:36 -04:00
}
2018-10-17 04:50:58 -04:00
$share -> setLabel ( $label );
}
2018-10-15 06:27:56 -04:00
if ( $sendPasswordByTalk === 'true' ) {
if ( ! $this -> appManager -> isEnabledForUser ( 'spreed' )) {
2021-07-07 06:22:54 -04:00
throw new OCSForbiddenException ( $this -> l -> t ( '"Sending the password by Nextcloud Talk" for sharing a file or folder failed because Nextcloud Talk is not enabled.' ));
2018-10-15 06:27:56 -04:00
}
$share -> setSendPasswordByTalk ( true );
2020-04-10 04:35:09 -04:00
} elseif ( $sendPasswordByTalk !== null ) {
2018-10-15 06:27:56 -04:00
$share -> setSendPasswordByTalk ( false );
}
2024-12-16 18:53:12 -05:00
if ( $token !== null ) {
2024-12-16 18:53:12 -05:00
if ( ! $this -> shareManager -> allowCustomTokens ()) {
throw new OCSForbiddenException ( $this -> l -> t ( 'Custom share link tokens have been disabled by the administrator' ));
}
2024-12-16 18:53:12 -05:00
if ( ! $this -> validateToken ( $token )) {
throw new OCSBadRequestException ( $this -> l -> t ( 'Tokens must contain at least 1 character and may only contain letters, numbers, or a hyphen' ));
}
$share -> setToken ( $token );
}
2019-08-06 04:22:32 -04:00
}
// NOT A LINK SHARE
else {
2017-03-29 10:50:23 -04:00
if ( $permissions !== null ) {
2016-01-27 10:46:48 -05:00
$share -> setPermissions ( $permissions );
}
2023-04-27 10:26:24 -04:00
}
2017-03-28 08:39:38 -04:00
2023-04-27 10:26:24 -04:00
if ( $expireDate === '' ) {
$share -> setExpirationDate ( null );
} elseif ( $expireDate !== null ) {
try {
2024-10-22 02:20:04 -04:00
$expireDateTime = $this -> parseDate ( $expireDate );
$share -> setExpirationDate ( $expireDateTime );
2023-04-27 10:26:24 -04:00
} catch ( \Exception $e ) {
throw new OCSBadRequestException ( $e -> getMessage (), $e );
2017-03-29 10:50:23 -04:00
}
2016-01-22 08:52:20 -05:00
}
try {
2025-01-19 05:36:24 -05:00
$this -> checkInheritedAttributes ( $share );
2016-01-22 08:52:20 -05:00
$share = $this -> shareManager -> updateShare ( $share );
2024-11-19 03:40:26 -05:00
} catch ( HintException $e ) {
2019-07-03 10:32:45 -04:00
$code = $e -> getCode () === 0 ? 403 : $e -> getCode ();
2022-10-17 06:36:50 -04:00
throw new OCSException ( $e -> getHint (), ( int ) $code );
2016-01-22 08:52:20 -05:00
} catch ( \Exception $e ) {
2024-10-22 02:20:04 -04:00
$this -> logger -> error ( $e -> getMessage (), [ 'exception' => $e ]);
throw new OCSBadRequestException ( 'Failed to update share.' , $e );
2016-01-22 08:52:20 -05:00
}
2016-08-09 04:04:29 -04:00
return new DataResponse ( $this -> formatShare ( $share ));
2016-01-22 08:52:20 -05:00
}
2024-12-16 18:53:12 -05:00
private function validateToken ( string $token ) : bool {
if ( mb_strlen ( $token ) === 0 ) {
return false ;
}
if ( ! preg_match ( '/^[a-z0-9-]+$/i' , $token )) {
return false ;
}
return true ;
}
2020-01-07 02:53:33 -05:00
/**
2023-02-15 13:22:09 -05:00
* Get all shares that are still pending
*
2024-09-24 09:53:13 -04:00
* @ return DataResponse < Http :: STATUS_OK , list < Files_SharingShare > , array {} >
2023-09-19 08:12:17 -04:00
*
* 200 : Pending shares returned
2020-01-07 02:53:33 -05:00
*/
2024-07-25 07:14:46 -04:00
#[NoAdminRequired]
2020-01-07 02:53:33 -05:00
public function pendingShares () : DataResponse {
$pendingShares = [];
$shareTypes = [
IShare :: TYPE_USER ,
IShare :: TYPE_GROUP
];
foreach ( $shareTypes as $shareType ) {
2024-10-18 06:04:22 -04:00
$shares = $this -> shareManager -> getSharedWith ( $this -> userId , $shareType , null , - 1 , 0 );
2020-01-07 02:53:33 -05:00
foreach ( $shares as $share ) {
if ( $share -> getStatus () === IShare :: STATUS_PENDING || $share -> getStatus () === IShare :: STATUS_REJECTED ) {
$pendingShares [] = $share ;
}
}
}
2024-09-24 09:53:13 -04:00
$result = array_values ( array_filter ( array_map ( function ( IShare $share ) {
2020-01-07 06:57:57 -05:00
$userFolder = $this -> rootFolder -> getUserFolder ( $share -> getSharedBy ());
2024-02-09 03:54:52 -05:00
$node = $userFolder -> getFirstNodeById ( $share -> getNodeId ());
if ( ! $node ) {
2020-01-07 06:57:57 -05:00
// fallback to guessing the path
$node = $userFolder -> get ( $share -> getTarget ());
if ( $node === null || $share -> getTarget () === '' ) {
return null ;
}
}
try {
$formattedShare = $this -> formatShare ( $share , $node );
2023-07-06 02:58:11 -04:00
$formattedShare [ 'path' ] = '/' . $share -> getNode () -> getName ();
2020-01-07 06:57:57 -05:00
$formattedShare [ 'permissions' ] = 0 ;
return $formattedShare ;
} catch ( NotFoundException $e ) {
return null ;
}
}, $pendingShares ), function ( $entry ) {
return $entry !== null ;
2024-09-24 09:53:13 -04:00
}));
2020-01-07 02:53:33 -05:00
return new DataResponse ( $result );
}
2019-08-21 21:17:17 -04:00
/**
2023-02-15 13:22:09 -05:00
* Accept a share
*
* @ param string $id ID of the share
2024-09-24 09:53:13 -04:00
* @ return DataResponse < Http :: STATUS_OK , list < empty > , array {} >
2023-02-15 13:22:09 -05:00
* @ throws OCSNotFoundException Share not found
2019-08-21 21:17:17 -04:00
* @ throws OCSException
2023-02-15 13:22:09 -05:00
* @ throws OCSBadRequestException Share could not be accepted
*
* 200 : Share accepted successfully
2019-08-21 21:17:17 -04:00
*/
2024-07-25 07:14:46 -04:00
#[NoAdminRequired]
2019-08-21 21:17:17 -04:00
public function acceptShare ( string $id ) : DataResponse {
try {
$share = $this -> getShareById ( $id );
} catch ( ShareNotFound $e ) {
2022-06-07 07:07:19 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Wrong share ID, share does not exist' ));
2019-08-21 21:17:17 -04:00
}
2019-09-04 10:50:52 -04:00
if ( ! $this -> canAccessShare ( $share )) {
2022-06-07 07:07:19 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Wrong share ID, share does not exist' ));
2019-08-21 21:17:17 -04:00
}
try {
2024-10-18 06:04:22 -04:00
$this -> shareManager -> acceptShare ( $share , $this -> userId );
2024-11-19 03:40:26 -05:00
} catch ( HintException $e ) {
2019-08-21 21:17:17 -04:00
$code = $e -> getCode () === 0 ? 403 : $e -> getCode ();
2022-10-17 06:36:50 -04:00
throw new OCSException ( $e -> getHint (), ( int ) $code );
2019-08-21 21:17:17 -04:00
} catch ( \Exception $e ) {
2024-10-22 02:20:04 -04:00
$this -> logger -> error ( $e -> getMessage (), [ 'exception' => $e ]);
throw new OCSBadRequestException ( 'Failed to accept share.' , $e );
2019-08-21 21:17:17 -04:00
}
return new DataResponse ();
}
2018-07-24 05:57:52 -04:00
/**
2019-08-16 09:09:15 -04:00
* Does the user have read permission on the share
*
2024-10-18 06:04:22 -04:00
* @ param IShare $share the share to check
2019-08-16 09:09:15 -04:00
* @ param boolean $checkGroups check groups as well ?
* @ return boolean
* @ throws NotFoundException
*
2018-07-24 05:57:52 -04:00
* @ suppress PhanUndeclaredClassMethod
*/
2024-10-10 06:40:31 -04:00
protected function canAccessShare ( IShare $share , bool $checkGroups = true ) : bool {
2016-01-27 03:02:12 -05:00
// A file with permissions 0 can't be accessed by us. So Don't show it
if ( $share -> getPermissions () === 0 ) {
return false ;
}
2015-11-24 03:37:17 -05:00
// Owner of the file and the sharer of the file can always get share
2024-10-18 06:04:22 -04:00
if ( $share -> getShareOwner () === $this -> userId
|| $share -> getSharedBy () === $this -> userId ) {
2015-11-24 03:37:17 -05:00
return true ;
}
2019-08-16 09:09:15 -04:00
// If the share is shared with you, you can access it!
2020-04-29 10:43:39 -04:00
if ( $share -> getShareType () === IShare :: TYPE_USER
2024-10-18 06:04:22 -04:00
&& $share -> getSharedWith () === $this -> userId ) {
2015-11-24 03:37:17 -05:00
return true ;
}
2019-08-16 09:09:15 -04:00
// Have reshare rights on the shared file/folder ?
// Does the currentUser have access to the shared file?
2024-10-18 06:04:22 -04:00
$userFolder = $this -> rootFolder -> getUserFolder ( $this -> userId );
2024-02-09 03:54:52 -05:00
$file = $userFolder -> getFirstNodeById ( $share -> getNodeId ());
2024-10-18 06:04:22 -04:00
if ( $file && $this -> shareProviderResharingRights ( $this -> userId , $share , $file )) {
2019-08-16 09:09:15 -04:00
return true ;
}
// If in the recipient group, you can see the share
2020-04-29 10:43:39 -04:00
if ( $checkGroups && $share -> getShareType () === IShare :: TYPE_GROUP ) {
2016-02-03 02:14:48 -05:00
$sharedWith = $this -> groupManager -> get ( $share -> getSharedWith ());
2024-10-18 06:04:22 -04:00
$user = $this -> userManager -> get ( $this -> userId );
2017-01-19 09:02:46 -05:00
if ( $user !== null && $sharedWith !== null && $sharedWith -> inGroup ( $user )) {
2016-02-03 02:14:48 -05:00
return true ;
}
2015-11-24 03:37:17 -05:00
}
2020-04-29 10:43:39 -04:00
if ( $share -> getShareType () === IShare :: TYPE_CIRCLE ) {
2017-03-17 15:48:33 -04:00
// TODO: have a sanity check like above?
return true ;
}
2020-04-29 10:43:39 -04:00
if ( $share -> getShareType () === IShare :: TYPE_ROOM ) {
2018-06-29 07:22:26 -04:00
try {
2024-10-18 06:04:22 -04:00
return $this -> getRoomShareHelper () -> canAccessShare ( $share , $this -> userId );
2025-02-04 16:40:00 -05:00
} catch ( ContainerExceptionInterface $e ) {
2018-06-29 07:22:26 -04:00
return false ;
}
}
2020-12-03 10:03:35 -05:00
if ( $share -> getShareType () === IShare :: TYPE_DECK ) {
try {
2024-10-18 06:04:22 -04:00
return $this -> getDeckShareHelper () -> canAccessShare ( $share , $this -> userId );
2025-02-04 16:40:00 -05:00
} catch ( ContainerExceptionInterface $e ) {
2020-12-03 10:03:35 -05:00
return false ;
}
}
2023-02-20 04:50:31 -05:00
if ( $share -> getShareType () === IShare :: TYPE_SCIENCEMESH ) {
try {
2024-10-18 06:04:22 -04:00
return $this -> getSciencemeshShareHelper () -> canAccessShare ( $share , $this -> userId );
2025-02-04 16:40:00 -05:00
} catch ( ContainerExceptionInterface $e ) {
2023-02-20 04:50:31 -05:00
return false ;
}
}
2015-11-24 03:37:17 -05:00
return false ;
}
2015-12-15 03:54:50 -05:00
2019-08-26 07:11:09 -04:00
/**
* Does the user have edit permission on the share
*
2024-10-18 06:04:22 -04:00
* @ param IShare $share the share to check
2019-08-26 07:11:09 -04:00
* @ return boolean
*/
2024-10-10 06:40:31 -04:00
protected function canEditShare ( IShare $share ) : bool {
2019-08-26 07:11:09 -04:00
// A file with permissions 0 can't be accessed by us. So Don't show it
if ( $share -> getPermissions () === 0 ) {
return false ;
}
// The owner of the file and the creator of the share
// can always edit the share
2024-10-18 06:04:22 -04:00
if ( $share -> getShareOwner () === $this -> userId ||
$share -> getSharedBy () === $this -> userId
2019-08-26 07:11:09 -04:00
) {
return true ;
}
2024-10-15 05:08:21 -04:00
$userFolder = $this -> rootFolder -> getUserFolder ( $this -> userId );
$file = $userFolder -> getFirstNodeById ( $share -> getNodeId ());
if ( $file ? -> getMountPoint () instanceof IShareOwnerlessMount && $this -> shareProviderResharingRights ( $this -> userId , $share , $file )) {
return true ;
}
2019-08-26 07:11:09 -04:00
//! we do NOT support some kind of `admin` in groups.
//! You cannot edit shares shared to a group you're
//! a member of if you're not the share owner or the file owner!
return false ;
}
2019-08-26 07:11:09 -04:00
/**
* Does the user have delete permission on the share
*
2024-10-18 06:04:22 -04:00
* @ param IShare $share the share to check
2019-08-26 07:11:09 -04:00
* @ return boolean
*/
2024-10-10 06:40:31 -04:00
protected function canDeleteShare ( IShare $share ) : bool {
2019-08-26 07:11:09 -04:00
// A file with permissions 0 can't be accessed by us. So Don't show it
if ( $share -> getPermissions () === 0 ) {
return false ;
}
// if the user is the recipient, i can unshare
// the share with self
2020-04-29 10:43:39 -04:00
if ( $share -> getShareType () === IShare :: TYPE_USER &&
2024-10-18 06:04:22 -04:00
$share -> getSharedWith () === $this -> userId
2019-08-26 07:11:09 -04:00
) {
return true ;
}
// The owner of the file and the creator of the share
// can always delete the share
2024-10-18 06:04:22 -04:00
if ( $share -> getShareOwner () === $this -> userId ||
$share -> getSharedBy () === $this -> userId
2019-08-26 07:11:09 -04:00
) {
return true ;
}
2024-10-15 05:08:21 -04:00
$userFolder = $this -> rootFolder -> getUserFolder ( $this -> userId );
$file = $userFolder -> getFirstNodeById ( $share -> getNodeId ());
if ( $file ? -> getMountPoint () instanceof IShareOwnerlessMount && $this -> shareProviderResharingRights ( $this -> userId , $share , $file )) {
return true ;
}
2019-08-26 07:11:09 -04:00
return false ;
}
/**
* Does the user have delete permission on the share
* This differs from the canDeleteShare function as it only
* remove the share for the current user . It does NOT
* completely delete the share but only the mount point .
* It can then be restored from the deleted shares section .
*
2024-10-18 06:04:22 -04:00
* @ param IShare $share the share to check
2019-08-26 07:11:09 -04:00
* @ return boolean
*
* @ suppress PhanUndeclaredClassMethod
*/
2024-10-10 06:40:31 -04:00
protected function canDeleteShareFromSelf ( IShare $share ) : bool {
2019-09-04 10:50:52 -04:00
if ( $share -> getShareType () !== IShare :: TYPE_GROUP &&
2020-12-03 10:03:35 -05:00
$share -> getShareType () !== IShare :: TYPE_ROOM &&
2023-02-20 04:50:31 -05:00
$share -> getShareType () !== IShare :: TYPE_DECK &&
$share -> getShareType () !== IShare :: TYPE_SCIENCEMESH
2019-08-26 07:11:09 -04:00
) {
return false ;
}
2024-10-18 06:04:22 -04:00
if ( $share -> getShareOwner () === $this -> userId ||
$share -> getSharedBy () === $this -> userId
2019-08-26 07:11:09 -04:00
) {
// Delete the whole share, not just for self
return false ;
}
// If in the recipient group, you can delete the share from self
2020-04-29 10:43:39 -04:00
if ( $share -> getShareType () === IShare :: TYPE_GROUP ) {
2019-08-26 07:11:09 -04:00
$sharedWith = $this -> groupManager -> get ( $share -> getSharedWith ());
2024-10-18 06:04:22 -04:00
$user = $this -> userManager -> get ( $this -> userId );
2019-08-26 07:11:09 -04:00
if ( $user !== null && $sharedWith !== null && $sharedWith -> inGroup ( $user )) {
return true ;
}
}
2020-04-29 10:43:39 -04:00
if ( $share -> getShareType () === IShare :: TYPE_ROOM ) {
2019-08-26 07:11:09 -04:00
try {
2024-10-18 06:04:22 -04:00
return $this -> getRoomShareHelper () -> canAccessShare ( $share , $this -> userId );
2025-02-04 16:40:00 -05:00
} catch ( ContainerExceptionInterface $e ) {
2019-08-26 07:11:09 -04:00
return false ;
}
}
2020-12-03 10:03:35 -05:00
if ( $share -> getShareType () === IShare :: TYPE_DECK ) {
try {
2024-10-18 06:04:22 -04:00
return $this -> getDeckShareHelper () -> canAccessShare ( $share , $this -> userId );
2025-02-04 16:40:00 -05:00
} catch ( ContainerExceptionInterface $e ) {
2020-12-03 10:03:35 -05:00
return false ;
}
}
2023-02-20 04:50:31 -05:00
if ( $share -> getShareType () === IShare :: TYPE_SCIENCEMESH ) {
try {
2024-10-18 06:04:22 -04:00
return $this -> getSciencemeshShareHelper () -> canAccessShare ( $share , $this -> userId );
2025-02-04 16:40:00 -05:00
} catch ( ContainerExceptionInterface $e ) {
2023-02-20 04:50:31 -05:00
return false ;
}
}
2019-08-26 07:11:09 -04:00
return false ;
}
2015-12-15 03:54:50 -05:00
/**
* Make sure that the passed date is valid ISO 8601
* So YYYY - MM - DD
* If not throw an exception
*
* @ param string $expireDate
*
* @ throws \Exception
* @ return \DateTime
*/
2018-04-23 14:31:57 -04:00
private function parseDate ( string $expireDate ) : \DateTime {
2015-12-15 03:54:50 -05:00
try {
2024-01-08 18:46:26 -05:00
$date = new \DateTime ( trim ( $expireDate , '"' ), $this -> dateTimeZone -> getTimeZone ());
2024-02-07 06:06:12 -05:00
// Make sure it expires at midnight in owner timezone
$date -> setTime ( 0 , 0 , 0 );
2015-12-15 03:54:50 -05:00
} catch ( \Exception $e ) {
2024-07-12 04:41:41 -04:00
throw new \Exception ( $this -> l -> t ( 'Invalid date. Format must be YYYY-MM-DD' ));
2015-12-15 03:54:50 -05:00
}
return $date ;
}
2016-03-07 10:10:27 -05:00
/**
* Since we have multiple providers but the OCS Share API v1 does
* not support this we need to check all backends .
*
* @ param string $id
2024-10-18 06:04:22 -04:00
* @ return IShare
2016-03-07 10:10:27 -05:00
* @ throws ShareNotFound
*/
2018-04-23 14:31:57 -04:00
private function getShareById ( string $id ) : IShare {
2016-03-07 10:10:27 -05:00
$share = null ;
// First check if it is an internal share.
try {
2024-10-18 06:04:22 -04:00
$share = $this -> shareManager -> getShareById ( 'ocinternal:' . $id , $this -> userId );
2016-07-29 09:38:31 -04:00
return $share ;
} catch ( ShareNotFound $e ) {
// Do nothing, just try the other share type
}
2017-03-17 15:48:33 -04:00
try {
2020-04-29 10:43:39 -04:00
if ( $this -> shareManager -> shareProviderExists ( IShare :: TYPE_CIRCLE )) {
2024-10-18 06:04:22 -04:00
$share = $this -> shareManager -> getShareById ( 'ocCircleShare:' . $id , $this -> userId );
2017-03-17 15:48:33 -04:00
return $share ;
}
} catch ( ShareNotFound $e ) {
// Do nothing, just try the other share type
}
2016-07-29 09:38:31 -04:00
try {
2020-04-29 10:43:39 -04:00
if ( $this -> shareManager -> shareProviderExists ( IShare :: TYPE_EMAIL )) {
2024-10-18 06:04:22 -04:00
$share = $this -> shareManager -> getShareById ( 'ocMailShare:' . $id , $this -> userId );
2016-10-27 06:27:09 -04:00
return $share ;
2016-03-07 10:10:27 -05:00
}
2016-10-27 06:27:09 -04:00
} catch ( ShareNotFound $e ) {
// Do nothing, just try the other share type
}
2016-03-07 10:10:27 -05:00
2018-06-29 07:22:26 -04:00
try {
2024-10-18 06:04:22 -04:00
$share = $this -> shareManager -> getShareById ( 'ocRoomShare:' . $id , $this -> userId );
2018-06-29 07:22:26 -04:00
return $share ;
} catch ( ShareNotFound $e ) {
// Do nothing, just try the other share type
}
2020-12-03 10:03:35 -05:00
try {
if ( $this -> shareManager -> shareProviderExists ( IShare :: TYPE_DECK )) {
2024-10-18 06:04:22 -04:00
$share = $this -> shareManager -> getShareById ( 'deck:' . $id , $this -> userId );
2020-12-03 10:03:35 -05:00
return $share ;
}
} catch ( ShareNotFound $e ) {
// Do nothing, just try the other share type
}
2023-02-20 04:50:31 -05:00
try {
if ( $this -> shareManager -> shareProviderExists ( IShare :: TYPE_SCIENCEMESH )) {
2024-10-18 06:04:22 -04:00
$share = $this -> shareManager -> getShareById ( 'sciencemesh:' . $id , $this -> userId );
2023-02-20 04:50:31 -05:00
return $share ;
}
} catch ( ShareNotFound $e ) {
// Do nothing, just try the other share type
}
2016-10-27 06:27:09 -04:00
if ( ! $this -> shareManager -> outgoingServer2ServerSharesAllowed ()) {
throw new ShareNotFound ();
2016-03-07 10:10:27 -05:00
}
2024-10-18 06:04:22 -04:00
$share = $this -> shareManager -> getShareById ( 'ocFederatedSharing:' . $id , $this -> userId );
2016-03-07 10:10:27 -05:00
return $share ;
}
2016-07-20 04:11:01 -04:00
/**
* Lock a Node
2016-09-21 11:35:09 -04:00
*
2024-10-18 06:04:22 -04:00
* @ param Node $node
2018-04-23 14:31:57 -04:00
* @ throws LockedException
2016-07-20 04:11:01 -04:00
*/
2024-10-10 06:40:31 -04:00
private function lock ( Node $node ) {
2016-07-20 04:11:01 -04:00
$node -> lock ( ILockingProvider :: LOCK_SHARED );
$this -> lockedNode = $node ;
}
/**
* Cleanup the remaining locks
2020-08-14 09:10:48 -04:00
* @ throws LockedException
2016-07-20 04:11:01 -04:00
*/
public function cleanup () {
if ( $this -> lockedNode !== null ) {
$this -> lockedNode -> unlock ( ILockingProvider :: LOCK_SHARED );
}
}
2018-06-29 07:22:26 -04:00
/**
* Returns the helper of ShareAPIController for room shares .
*
* If the Talk application is not enabled or the helper is not available
2025-02-04 16:40:00 -05:00
* a ContainerExceptionInterface is thrown instead .
2018-06-29 07:22:26 -04:00
*
2019-09-05 09:32:58 -04:00
* @ return \OCA\Talk\Share\Helper\ShareAPIController
2025-02-04 16:40:00 -05:00
* @ throws ContainerExceptionInterface
2018-06-29 07:22:26 -04:00
*/
private function getRoomShareHelper () {
if ( ! $this -> appManager -> isEnabledForUser ( 'spreed' )) {
throw new QueryException ();
}
2020-12-09 07:19:14 -05:00
return $this -> serverContainer -> get ( '\OCA\Talk\Share\Helper\ShareAPIController' );
2018-06-29 07:22:26 -04:00
}
2018-10-29 05:03:52 -04:00
2020-12-03 10:03:35 -05:00
/**
* Returns the helper of ShareAPIHelper for deck shares .
*
* If the Deck application is not enabled or the helper is not available
2025-02-04 16:40:00 -05:00
* a ContainerExceptionInterface is thrown instead .
2020-12-03 10:03:35 -05:00
*
* @ return \OCA\Deck\Sharing\ShareAPIHelper
2025-02-04 16:40:00 -05:00
* @ throws ContainerExceptionInterface
2020-12-03 10:03:35 -05:00
*/
private function getDeckShareHelper () {
if ( ! $this -> appManager -> isEnabledForUser ( 'deck' )) {
throw new QueryException ();
}
2020-12-09 07:19:14 -05:00
return $this -> serverContainer -> get ( '\OCA\Deck\Sharing\ShareAPIHelper' );
2020-12-03 10:03:35 -05:00
}
2018-10-29 05:03:52 -04:00
2023-02-20 04:50:31 -05:00
/**
* Returns the helper of ShareAPIHelper for sciencemesh shares .
*
* If the sciencemesh application is not enabled or the helper is not available
2025-02-04 16:40:00 -05:00
* a ContainerExceptionInterface is thrown instead .
2023-02-20 04:50:31 -05:00
*
* @ return \OCA\Deck\Sharing\ShareAPIHelper
2025-02-04 16:40:00 -05:00
* @ throws ContainerExceptionInterface
2023-02-20 04:50:31 -05:00
*/
private function getSciencemeshShareHelper () {
if ( ! $this -> appManager -> isEnabledForUser ( 'sciencemesh' )) {
throw new QueryException ();
}
return $this -> serverContainer -> get ( '\OCA\ScienceMesh\Sharing\ShareAPIHelper' );
}
2019-06-25 16:34:38 -04:00
/**
* @ param string $viewer
* @ param Node $node
* @ param bool $reShares
*
* @ return IShare []
*/
private function getSharesFromNode ( string $viewer , $node , bool $reShares ) : array {
$providers = [
2020-04-29 10:43:39 -04:00
IShare :: TYPE_USER ,
IShare :: TYPE_GROUP ,
IShare :: TYPE_LINK ,
IShare :: TYPE_EMAIL ,
IShare :: TYPE_CIRCLE ,
2020-12-03 10:03:35 -05:00
IShare :: TYPE_ROOM ,
2023-02-20 04:50:31 -05:00
IShare :: TYPE_DECK ,
IShare :: TYPE_SCIENCEMESH
2019-06-25 16:34:38 -04:00
];
// Should we assume that the (currentUser) viewer is the owner of the node !?
$shares = [];
foreach ( $providers as $provider ) {
if ( ! $this -> shareManager -> shareProviderExists ( $provider )) {
continue ;
}
$providerShares =
$this -> shareManager -> getSharesBy ( $viewer , $provider , $node , $reShares , - 1 , 0 );
$shares = array_merge ( $shares , $providerShares );
}
if ( $this -> shareManager -> outgoingServer2ServerSharesAllowed ()) {
$federatedShares = $this -> shareManager -> getSharesBy (
2024-10-18 06:04:22 -04:00
$this -> userId , IShare :: TYPE_REMOTE , $node , $reShares , - 1 , 0
2019-06-25 16:34:38 -04:00
);
$shares = array_merge ( $shares , $federatedShares );
}
if ( $this -> shareManager -> outgoingServer2ServerGroupSharesAllowed ()) {
$federatedShares = $this -> shareManager -> getSharesBy (
2024-10-18 06:04:22 -04:00
$this -> userId , IShare :: TYPE_REMOTE_GROUP , $node , $reShares , - 1 , 0
2019-06-25 16:34:38 -04:00
);
$shares = array_merge ( $shares , $federatedShares );
}
return $shares ;
}
/**
* @ param Node $node
*
* @ throws SharingRightsException
*/
private function confirmSharingRights ( Node $node ) : void {
2024-10-18 06:04:22 -04:00
if ( ! $this -> hasResharingRights ( $this -> userId , $node )) {
2024-07-12 04:41:41 -04:00
throw new SharingRightsException ( $this -> l -> t ( 'No sharing rights on this item' ));
2019-06-25 16:34:38 -04:00
}
}
/**
* @ param string $viewer
* @ param Node $node
*
* @ return bool
*/
private function hasResharingRights ( $viewer , $node ) : bool {
2020-01-02 07:33:27 -05:00
if ( $viewer === $node -> getOwner () -> getUID ()) {
return true ;
}
2019-06-25 16:34:38 -04:00
foreach ([ $node , $node -> getParent ()] as $node ) {
$shares = $this -> getSharesFromNode ( $viewer , $node , true );
foreach ( $shares as $share ) {
try {
if ( $this -> shareProviderResharingRights ( $viewer , $share , $node )) {
return true ;
}
} catch ( InvalidPathException | NotFoundException $e ) {
}
}
}
return false ;
}
2018-10-29 05:03:52 -04:00
/**
* Returns if we can find resharing rights in an IShare object for a specific user .
*
2018-11-01 08:41:19 -04:00
* @ suppress PhanUndeclaredClassMethod
*
2018-10-29 05:03:52 -04:00
* @ param string $userId
* @ param IShare $share
2018-11-01 08:41:19 -04:00
* @ param Node $node
2019-06-25 16:34:38 -04:00
*
2018-10-29 05:03:52 -04:00
* @ return bool
2018-11-01 08:41:19 -04:00
* @ throws NotFoundException
2019-06-25 16:34:38 -04:00
* @ throws InvalidPathException
2018-10-29 05:03:52 -04:00
*/
2018-11-01 10:01:01 -04:00
private function shareProviderResharingRights ( string $userId , IShare $share , $node ) : bool {
2018-10-29 05:03:52 -04:00
if ( $share -> getShareOwner () === $userId ) {
return true ;
}
2018-11-01 08:41:19 -04:00
// we check that current user have parent resharing rights on the current file
2019-06-25 16:34:38 -04:00
if ( $node !== null && ( $node -> getPermissions () & Constants :: PERMISSION_SHARE ) !== 0 ) {
2018-11-01 08:41:19 -04:00
return true ;
}
2024-10-10 06:40:31 -04:00
if (( Constants :: PERMISSION_SHARE & $share -> getPermissions ()) === 0 ) {
2018-10-29 05:03:52 -04:00
return false ;
}
2020-05-28 19:41:06 -04:00
if ( $share -> getShareType () === IShare :: TYPE_USER && $share -> getSharedWith () === $userId ) {
2018-10-29 05:03:52 -04:00
return true ;
}
2020-05-28 19:41:06 -04:00
if ( $share -> getShareType () === IShare :: TYPE_GROUP && $this -> groupManager -> isInGroup ( $userId , $share -> getSharedWith ())) {
2018-10-29 05:03:52 -04:00
return true ;
}
2025-02-04 16:40:00 -05:00
if ( $share -> getShareType () === IShare :: TYPE_CIRCLE && \OCP\Server :: get ( IAppManager :: class ) -> isEnabledForUser ( 'circles' )
2019-08-06 04:22:32 -04:00
&& class_exists ( '\OCA\Circles\Api\v1\Circles' )) {
2023-06-02 12:38:40 -04:00
$hasCircleId = ( str_ends_with ( $share -> getSharedWith (), ']' ));
2018-10-30 04:58:43 -04:00
$shareWithStart = ( $hasCircleId ? strrpos ( $share -> getSharedWith (), '[' ) + 1 : 0 );
$shareWithLength = ( $hasCircleId ? - 1 : strpos ( $share -> getSharedWith (), ' ' ));
2020-11-13 04:58:54 -05:00
if ( $shareWithLength === false ) {
$sharedWith = substr ( $share -> getSharedWith (), $shareWithStart );
} else {
$sharedWith = substr ( $share -> getSharedWith (), $shareWithStart , $shareWithLength );
2018-10-30 04:58:43 -04:00
}
try {
2024-10-10 06:40:31 -04:00
$member = Circles :: getMember ( $sharedWith , $userId , 1 );
2018-10-30 05:02:38 -04:00
if ( $member -> getLevel () >= 4 ) {
2018-10-30 04:58:43 -04:00
return true ;
}
2018-10-30 05:02:38 -04:00
return false ;
2025-02-04 16:40:00 -05:00
} catch ( ContainerExceptionInterface $e ) {
2018-10-30 04:58:43 -04:00
return false ;
}
}
2018-10-29 05:03:52 -04:00
return false ;
}
2019-08-26 07:11:09 -04:00
2019-10-25 04:45:49 -04:00
/**
* Get all the shares for the current user
*
* @ param Node | null $path
* @ param boolean $reshares
2020-08-14 09:10:48 -04:00
* @ return IShare []
2019-10-25 04:45:49 -04:00
*/
private function getAllShares ( ? Node $path = null , bool $reshares = false ) {
// Get all shares
2024-10-18 06:04:22 -04:00
$userShares = $this -> shareManager -> getSharesBy ( $this -> userId , IShare :: TYPE_USER , $path , $reshares , - 1 , 0 );
$groupShares = $this -> shareManager -> getSharesBy ( $this -> userId , IShare :: TYPE_GROUP , $path , $reshares , - 1 , 0 );
$linkShares = $this -> shareManager -> getSharesBy ( $this -> userId , IShare :: TYPE_LINK , $path , $reshares , - 1 , 0 );
2019-10-25 04:45:49 -04:00
// EMAIL SHARES
2024-10-18 06:04:22 -04:00
$mailShares = $this -> shareManager -> getSharesBy ( $this -> userId , IShare :: TYPE_EMAIL , $path , $reshares , - 1 , 0 );
2019-10-25 04:45:49 -04:00
2024-08-06 08:48:07 -04:00
// TEAM SHARES
2024-10-18 06:04:22 -04:00
$circleShares = $this -> shareManager -> getSharesBy ( $this -> userId , IShare :: TYPE_CIRCLE , $path , $reshares , - 1 , 0 );
2019-10-25 04:45:49 -04:00
// TALK SHARES
2024-10-18 06:04:22 -04:00
$roomShares = $this -> shareManager -> getSharesBy ( $this -> userId , IShare :: TYPE_ROOM , $path , $reshares , - 1 , 0 );
2019-10-25 04:45:49 -04:00
2023-02-20 04:50:31 -05:00
// DECK SHARES
2024-10-18 06:04:22 -04:00
$deckShares = $this -> shareManager -> getSharesBy ( $this -> userId , IShare :: TYPE_DECK , $path , $reshares , - 1 , 0 );
2020-12-03 10:03:35 -05:00
2023-02-20 04:50:31 -05:00
// SCIENCEMESH SHARES
2024-10-18 06:04:22 -04:00
$sciencemeshShares = $this -> shareManager -> getSharesBy ( $this -> userId , IShare :: TYPE_SCIENCEMESH , $path , $reshares , - 1 , 0 );
2023-02-20 04:50:31 -05:00
2019-10-25 04:45:49 -04:00
// FEDERATION
if ( $this -> shareManager -> outgoingServer2ServerSharesAllowed ()) {
2024-10-18 06:04:22 -04:00
$federatedShares = $this -> shareManager -> getSharesBy ( $this -> userId , IShare :: TYPE_REMOTE , $path , $reshares , - 1 , 0 );
2019-10-25 04:45:49 -04:00
} else {
$federatedShares = [];
}
if ( $this -> shareManager -> outgoingServer2ServerGroupSharesAllowed ()) {
2024-10-18 06:04:22 -04:00
$federatedGroupShares = $this -> shareManager -> getSharesBy ( $this -> userId , IShare :: TYPE_REMOTE_GROUP , $path , $reshares , - 1 , 0 );
2019-10-25 04:45:49 -04:00
} else {
$federatedGroupShares = [];
}
2023-02-20 04:50:31 -05:00
return array_merge ( $userShares , $groupShares , $linkShares , $mailShares , $circleShares , $roomShares , $deckShares , $sciencemeshShares , $federatedShares , $federatedGroupShares );
2019-10-25 04:45:49 -04:00
}
2019-06-25 16:34:38 -04:00
/**
* merging already formatted shares .
* We ' ll make an associative array to easily detect duplicate Ids .
* Keys _needs_ to be removed after all shares are retrieved and merged .
*
* @ param array $shares
* @ param array $newShares
*/
private function mergeFormattedShares ( array & $shares , array $newShares ) {
foreach ( $newShares as $newShare ) {
if ( ! array_key_exists ( $newShare [ 'id' ], $shares )) {
$shares [ $newShare [ 'id' ]] = $newShare ;
}
}
}
2022-05-18 08:54:27 -04:00
/**
* @ param IShare $share
2022-05-25 03:55:22 -04:00
* @ param string | null $attributesString
2022-05-18 08:54:27 -04:00
* @ return IShare modified share
*/
2022-05-25 03:55:22 -04:00
private function setShareAttributes ( IShare $share , ? string $attributesString ) {
$newShareAttributes = null ;
if ( $attributesString !== null ) {
$newShareAttributes = $this -> shareManager -> newShare () -> newAttributes ();
$formattedShareAttributes = \json_decode ( $attributesString , true );
if ( is_array ( $formattedShareAttributes )) {
foreach ( $formattedShareAttributes as $formattedAttr ) {
$newShareAttributes -> setAttribute (
$formattedAttr [ 'scope' ],
$formattedAttr [ 'key' ],
2024-07-05 08:27:49 -04:00
$formattedAttr [ 'value' ],
2022-05-25 03:55:22 -04:00
);
}
} else {
2024-07-12 04:41:41 -04:00
throw new OCSBadRequestException ( $this -> l -> t ( 'Invalid share attributes provided: "%s"' , [ $attributesString ]));
2022-05-18 08:54:27 -04:00
}
}
$share -> setAttributes ( $newShareAttributes );
return $share ;
}
2022-07-15 11:11:54 -04:00
private function checkInheritedAttributes ( IShare $share ) : void {
2022-10-11 08:00:15 -04:00
if ( ! $share -> getSharedBy ()) {
return ; // Probably in a test
}
2025-01-19 05:36:24 -05:00
$canDownload = false ;
$hideDownload = true ;
2022-10-10 10:09:14 -04:00
$userFolder = $this -> rootFolder -> getUserFolder ( $share -> getSharedBy ());
2025-01-19 05:36:24 -05:00
$nodes = $userFolder -> getById ( $share -> getNodeId ());
foreach ( $nodes as $node ) {
// Owner always can download it - so allow it and break
if ( $node -> getOwner () ? -> getUID () === $share -> getSharedBy ()) {
$canDownload = true ;
$hideDownload = false ;
break ;
2022-07-15 11:11:54 -04:00
}
2025-01-19 05:36:24 -05:00
if ( $node -> getStorage () -> instanceOfStorage ( SharedStorage :: class )) {
$storage = $node -> getStorage ();
if ( $storage instanceof Wrapper ) {
$storage = $storage -> getInstanceOfStorage ( SharedStorage :: class );
if ( $storage === null ) {
throw new \RuntimeException ( 'Should not happen, instanceOfStorage but getInstanceOfStorage return null' );
}
} else {
throw new \RuntimeException ( 'Should not happen, instanceOfStorage but not a wrapper' );
2022-10-10 10:09:14 -04:00
}
2025-01-19 05:36:24 -05:00
/** @var SharedStorage $storage */
$originalShare = $storage -> getShare ();
$inheritedAttributes = $originalShare -> getAttributes ();
// hide if hidden and also the current share enforces hide (can only be false if one share is false or user is owner)
$hideDownload = $hideDownload && $originalShare -> getHideDownload ();
// allow download if already allowed by previous share or when the current share allows downloading
$canDownload = $canDownload || $inheritedAttributes === null || $inheritedAttributes -> getAttribute ( 'permissions' , 'download' ) !== false ;
}
}
if ( $hideDownload || ! $canDownload ) {
$share -> setHideDownload ( true );
if ( ! $canDownload ) {
$attributes = $share -> getAttributes () ? ? $share -> newAttributes ();
$attributes -> setAttribute ( 'permissions' , 'download' , false );
$share -> setAttributes ( $attributes );
2022-07-15 11:11:54 -04:00
}
}
2024-06-20 08:02:53 -04:00
}
2024-07-05 03:47:40 -04:00
/**
2024-07-09 05:09:01 -04:00
* Send a mail notification again for a share .
* The mail_send option must be enabled for the given share .
2024-07-09 09:38:33 -04:00
* @ param string $id the share ID
2024-07-12 09:11:10 -04:00
* @ param string $password the password to check against . Necessary for password protected shares .
2024-07-09 09:38:33 -04:00
* @ throws OCSNotFoundException Share not found
* @ throws OCSForbiddenException You are not allowed to send mail notifications
* @ throws OCSBadRequestException Invalid request or wrong password
* @ throws OCSException Error while sending mail notification
2024-09-24 09:53:13 -04:00
* @ return DataResponse < Http :: STATUS_OK , list < empty > , array {} >
2024-08-23 09:10:27 -04:00
*
2024-07-09 09:38:33 -04:00
* 200 : The email notification was sent successfully
2024-07-05 03:47:40 -04:00
*/
#[NoAdminRequired]
2025-02-19 10:10:19 -05:00
#[UserRateLimit(limit: 10, period: 600)]
2024-07-09 05:09:01 -04:00
public function sendShareEmail ( string $id , $password = '' ) : DataResponse {
2024-06-20 08:02:53 -04:00
try {
2024-07-05 03:47:40 -04:00
$share = $this -> getShareById ( $id );
2022-07-15 11:11:54 -04:00
2024-07-05 08:02:53 -04:00
if ( ! $this -> canAccessShare ( $share , false )) {
throw new OCSNotFoundException ( $this -> l -> t ( 'Wrong share ID, share does not exist' ));
}
2024-07-25 07:14:46 -04:00
2024-07-05 08:02:53 -04:00
if ( ! $this -> canEditShare ( $share )) {
2024-07-12 04:41:41 -04:00
throw new OCSForbiddenException ( $this -> l -> t ( 'You are not allowed to send mail notifications' ));
2024-07-05 08:02:53 -04:00
}
// For mail and link shares, the user must be
// the owner of the share, not only the file owner.
if ( $share -> getShareType () === IShare :: TYPE_EMAIL
2024-07-09 05:09:01 -04:00
|| $share -> getShareType () === IShare :: TYPE_LINK ) {
2024-10-18 06:04:22 -04:00
if ( $share -> getSharedBy () !== $this -> userId ) {
2024-07-12 04:41:41 -04:00
throw new OCSForbiddenException ( $this -> l -> t ( 'You are not allowed to send mail notifications' ));
2024-07-05 08:02:53 -04:00
}
}
2024-06-20 08:02:53 -04:00
try {
2024-07-05 03:47:40 -04:00
$provider = $this -> factory -> getProviderForType ( $share -> getShareType ());
if ( ! ( $provider instanceof IShareProviderWithNotification )) {
throw new OCSBadRequestException ( $this -> l -> t ( 'No mail notification configured for this share type' ));
}
2024-07-05 08:02:53 -04:00
// Circumvent the password encrypted data by
// setting the password clear. We're not storing
// the password clear, it is just a temporary
// object manipulation. The password will stay
// encrypted in the database.
2024-07-09 05:09:01 -04:00
if ( $share -> getPassword () !== null && $share -> getPassword () !== $password ) {
2024-07-05 08:02:53 -04:00
if ( ! $this -> shareManager -> checkPassword ( $share , $password )) {
throw new OCSBadRequestException ( $this -> l -> t ( 'Wrong password' ));
}
$share = $share -> setPassword ( $password );
}
2024-07-05 03:47:40 -04:00
$provider -> sendMailNotification ( $share );
2024-07-09 09:38:33 -04:00
return new DataResponse ();
2024-06-20 08:02:53 -04:00
} catch ( Exception $e ) {
2024-10-22 02:20:04 -04:00
$this -> logger -> error ( $e -> getMessage (), [ 'exception' => $e ]);
2024-06-20 08:02:53 -04:00
throw new OCSException ( $this -> l -> t ( 'Error while sending mail notification' ));
}
2024-07-25 07:14:46 -04:00
2024-06-20 08:02:53 -04:00
} catch ( ShareNotFound $e ) {
throw new OCSNotFoundException ( $this -> l -> t ( 'Wrong share ID, share does not exist' ));
}
2022-07-15 11:11:54 -04:00
}
2024-12-16 18:53:12 -05:00
/**
* Get a unique share token
*
* @ throws OCSException Failed to generate a unique token
*
* @ return DataResponse < Http :: STATUS_OK , array { token : string }, array {} >
*
* 200 : Token generated successfully
*/
#[ApiRoute(verb: 'GET', url: '/api/v1/token')]
#[NoAdminRequired]
public function generateToken () : DataResponse {
try {
$token = $this -> shareManager -> generateToken ();
return new DataResponse ([
'token' => $token ,
]);
} catch ( ShareTokenException $e ) {
throw new OCSException ( $this -> l -> t ( 'Failed to generate a unique token' ));
}
}
2015-10-30 08:10:08 -04:00
}