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 );
2019-12-03 13:57:53 -05:00
2015-10-30 08:10:08 -04:00
/**
2016-01-12 09:02:16 -05:00
* @ copyright Copyright ( c ) 2016 , ownCloud , Inc .
2016-07-21 10:49:16 -04:00
*
2017-11-06 09:56:42 -05:00
* @ author Bjoern Schiessle < bjoern @ schiessle . org >
2021-06-04 15:52:51 -04:00
* @ author castillo92 < 37965565 + castillo92 @ users . noreply . github . com >
2020-04-29 05:57:22 -04:00
* @ author Christoph Wurst < christoph @ winzerhof - wurst . at >
2019-12-03 13:57:53 -05:00
* @ author Daniel Calviño Sánchez < danxuliu @ gmail . com >
2020-08-24 08:54:25 -04:00
* @ author Daniel Kesselberg < mail @ danielkesselberg . de >
* @ author Gary Kim < gary @ garykim . dev >
* @ author Georg Ehrke < oc . list @ georgehrke . com >
2016-07-21 10:49:16 -04:00
* @ author Joas Schilling < coding @ schilljs . com >
2021-06-04 15:52:51 -04:00
* @ author John Molakvoæ < skjnldsv @ protonmail . com >
2020-01-13 08:23:49 -05:00
* @ author Julius Härtl < jus @ bitgrid . net >
2017-11-06 09:56:42 -05:00
* @ author Lukas Reschke < lukas @ statuscode . ch >
2019-12-03 13:57:53 -05:00
* @ author Maxence Lange < maxence @ artificial - owl . com >
2017-11-06 09:56:42 -05:00
* @ author Maxence Lange < maxence @ nextcloud . com >
* @ author Michael Jobst < mjobst + github @ tecratech . de >
2019-12-03 13:57:53 -05:00
* @ author Morris Jobke < hey @ morrisjobke . de >
2020-12-16 08:54:15 -05:00
* @ author Richard Steinmetz < richard @ steinmetz . cloud >
2017-11-06 09:56:42 -05:00
* @ author Robin Appelman < robin @ icewind . nl >
2016-07-21 10:49:16 -04:00
* @ author Roeland Jago Douma < roeland @ famdouma . nl >
2021-06-04 15:52:51 -04:00
* @ author Valdnet < 47037905 + Valdnet @ users . noreply . github . com >
2020-12-16 08:54:15 -05:00
* @ author Vincent Petry < vincent @ nextcloud . com >
2019-12-03 13:57:53 -05:00
* @ author waleczny < michal @ walczak . xyz >
2023-02-15 13:22:09 -05:00
* @ author Kate Döen < kate . doeen @ nextcloud . com >
2016-07-21 10:49:16 -04:00
*
2015-10-30 08:10:08 -04:00
* @ license AGPL - 3.0
*
* This code is free software : you can redistribute it and / or modify
* it under the terms of the GNU Affero General Public License , version 3 ,
* as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Affero General Public License for more details .
*
* You should have received a copy of the GNU Affero General Public License , version 3 ,
2019-12-03 13:57:53 -05:00
* along with this program . If not , see < http :// www . gnu . org / licenses />
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-03-23 11:29:10 -04:00
use OC\Files\FileInfo ;
2022-07-15 11:11:54 -04:00
use OC\Files\Storage\Wrapper\Wrapper ;
2023-06-28 06:27:55 -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 ;
2023-02-15 13:22:09 -05:00
use OCA\Files_Sharing\ResponseDefinitions ;
2022-06-13 10:38:34 -04:00
use OCA\Files_Sharing\SharedStorage ;
2018-07-10 07:01:31 -04:00
use OCP\App\IAppManager ;
2023-02-15 13:22:09 -05:00
use OCP\AppFramework\Http ;
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 ;
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 ;
2016-09-20 11:59:04 -04:00
use OCP\Files\Node ;
2016-02-16 10:04:17 -05:00
use OCP\Files\NotFoundException ;
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 ;
2018-06-29 07:22:26 -04:00
use OCP\IServerContainer ;
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 ;
2023-06-28 06:27:55 -04:00
use OCP\Server ;
2016-02-02 08:18:59 -05:00
use OCP\Share\Exceptions\GenericShareException ;
2019-11-22 14:52:10 -05:00
use OCP\Share\Exceptions\ShareNotFound ;
use OCP\Share\IManager ;
2016-09-07 12:38:08 -04:00
use OCP\Share\IShare ;
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 ;
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
2016-02-03 02:14:48 -05:00
/** @var IManager */
2015-10-30 08:10:08 -04:00
private $shareManager ;
2015-11-24 03:37:17 -05:00
/** @var IGroupManager */
2015-10-30 08:10:08 -04:00
private $groupManager ;
2015-11-24 03:37:17 -05:00
/** @var IUserManager */
2015-10-30 08:10:08 -04:00
private $userManager ;
2015-11-24 04:16:02 -05:00
/** @var IRootFolder */
private $rootFolder ;
2016-03-10 15:35:22 -05:00
/** @var IURLGenerator */
2015-11-24 03:37:17 -05:00
private $urlGenerator ;
2016-10-21 14:25:07 -04:00
/** @var string */
2015-11-24 03:37:17 -05:00
private $currentUser ;
2016-04-15 08:05:36 -04:00
/** @var IL10N */
private $l ;
2016-07-20 04:11:01 -04:00
/** @var \OCP\Files\Node */
private $lockedNode ;
2017-12-01 08:49:35 -05:00
/** @var IConfig */
private $config ;
2018-07-10 07:01:31 -04:00
/** @var IAppManager */
private $appManager ;
2018-06-29 07:22:26 -04:00
/** @var IServerContainer */
private $serverContainer ;
2020-08-05 04:37:20 -04:00
/** @var IUserStatusManager */
private $userStatusManager ;
2020-10-11 09:19:30 -04:00
/** @var IPreview */
private $previewManager ;
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 ,
IManager $shareManager ,
IGroupManager $groupManager ,
IUserManager $userManager ,
IRootFolder $rootFolder ,
IURLGenerator $urlGenerator ,
2018-10-04 07:04:58 -04:00
string $userId = null ,
2017-12-01 08:49:35 -05:00
IL10N $l10n ,
2018-07-10 07:01:31 -04:00
IConfig $config ,
2018-06-29 07:22:26 -04:00
IAppManager $appManager ,
2020-08-05 04:37:20 -04:00
IServerContainer $serverContainer ,
2020-10-11 09:19:30 -04:00
IUserStatusManager $userStatusManager ,
2024-01-08 18:46:26 -05:00
IPreview $previewManager ,
private IDateTimeZone $dateTimeZone ,
2015-11-24 03:37:17 -05:00
) {
2016-07-19 08:13:27 -04:00
parent :: __construct ( $appName , $request );
2015-10-30 08:10:08 -04:00
$this -> shareManager = $shareManager ;
$this -> userManager = $userManager ;
$this -> groupManager = $groupManager ;
$this -> request = $request ;
2015-11-24 04:16:02 -05:00
$this -> rootFolder = $rootFolder ;
2015-11-06 06:05:19 -05:00
$this -> urlGenerator = $urlGenerator ;
2016-10-21 14:25:07 -04:00
$this -> currentUser = $userId ;
2016-04-15 08:05:36 -04:00
$this -> l = $l10n ;
2017-12-01 08:49:35 -05:00
$this -> config = $config ;
2018-07-10 07:01:31 -04:00
$this -> appManager = $appManager ;
2018-06-29 07:22:26 -04:00
$this -> serverContainer = $serverContainer ;
2020-08-05 04:37:20 -04:00
$this -> userStatusManager = $userStatusManager ;
2020-10-11 09:19:30 -04:00
$this -> previewManager = $previewManager ;
2015-11-06 06:05:19 -05:00
}
/**
* Convert an IShare to an array for OCS output
*
2016-01-27 06:13:53 -05:00
* @ param \OCP\Share\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
*/
2020-04-29 10:43:39 -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 ) {
$isOwnShare = $shareOwner -> getUID () === $this -> currentUser ;
}
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
];
2016-10-21 14:25:07 -04:00
$userFolder = $this -> rootFolder -> getUserFolder ( $this -> currentUser );
2016-09-20 11:59:04 -04:00
if ( $recipientNode ) {
$node = $recipientNode ;
} else {
$nodes = $userFolder -> getById ( $share -> getNodeId ());
if ( empty ( $nodes )) {
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 ();
}
} else {
2019-11-18 17:33:26 -05:00
$node = reset ( $nodes );
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
}
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 ? (
2023-11-23 04:22:34 -05: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
// "name (type, owner) [id]", depending on the Circles app version.
$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 (), ' ' ));
2018-10-30 04:58:43 -04:00
if ( is_bool ( $shareWithLength )) {
$shareWithLength = - 1 ;
}
2018-03-15 23:23:46 -04:00
$result [ 'share_with' ] = substr ( $share -> getSharedWith (), $shareWithStart , $shareWithLength );
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 );
2020-04-10 08:19:56 -04:00
} catch ( QueryException $e ) {
}
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 );
2020-12-03 10:03:35 -05:00
} catch ( QueryException $e ) {
}
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 );
2023-02-20 04:50:31 -05:00
} catch ( QueryException $e ) {
}
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-11-23 04:22:34 -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 ) {
Server :: get ( LoggerInterface :: class ) -> error (
$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
/**
* @ param array $shares
* @ param array | null $updatedDisplayName
*
* @ return array
*/
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 {
$slaveService = Server :: get ( \OCA\GlobalSiteSelector\Service\SlaveService :: class );
} catch ( \Throwable $e ) {
Server :: get ( LoggerInterface :: class ) -> error (
$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
/**
2023-02-15 13:22:09 -05:00
* @ NoAdminRequired
*
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
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 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
*/
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 ) {
2022-09-21 02:28:03 -04:00
$share = Helper :: populateTags ([ $share ], 'file_source' , \OC :: $server -> getTagManager ());
} 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
}
/**
2023-02-15 13:22:09 -05:00
* @ NoAdminRequired
*
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
* @ return DataResponse < Http :: STATUS_OK , array < empty > , array {} >
* @ 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
*/
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 )) {
2016-10-25 04:18:42 -04:00
$this -> shareManager -> deleteFromSelf ( $share , $this -> currentUser );
} 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
/**
2016-07-19 08:13:27 -04:00
* @ NoAdminRequired
*
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
* @ param string | null $shareWith The entity this should be shared with
* @ param string $publicUpload If public uploading is allowed
* @ param string $password Password for the share
* @ param string | null $sendPasswordByTalk Send the password for the share over Talk
2024-01-08 18:46:26 -05:00
* @ param string $expireDate Expiry date of the share using user timezone at 00 : 00. It means date in UTC timezone 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
*
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
*/
2016-08-16 16:45:49 -04:00
public function createShare (
2018-04-23 14:31:57 -04:00
string $path = null ,
int $permissions = null ,
int $shareType = - 1 ,
string $shareWith = null ,
string $publicUpload = 'false' ,
string $password = '' ,
2018-07-10 07:01:31 -04:00
string $sendPasswordByTalk = null ,
2018-10-16 04:31:38 -04:00
string $expireDate = '' ,
2021-11-26 08:42:31 -05:00
string $note = '' ,
2022-05-25 03:55:22 -04:00
string $label = '' ,
string $attributes = null
2018-04-23 14:31:57 -04:00
) : DataResponse {
2015-12-15 03:54:50 -05:00
$share = $this -> shareManager -> newShare ();
2017-12-01 08:49:35 -05:00
if ( $permissions === null ) {
2022-11-16 09:25:10 -05:00
if ( $shareType === IShare :: TYPE_LINK
|| $shareType === IShare :: TYPE_EMAIL ) {
// to keep legacy default behaviour, we ignore the setting below for link shares
$permissions = Constants :: PERMISSION_READ ;
} else {
$permissions = ( int ) $this -> config -> getAppValue ( 'core' , 'shareapi_default_permissions' , ( string ) Constants :: PERMISSION_ALL );
}
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
}
2016-10-21 14:25:07 -04:00
$userFolder = $this -> rootFolder -> getUserFolder ( $this -> currentUser );
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 ) {
/** @var FileInfo $fileInfo */
$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
2017-12-01 08:49:35 -05:00
if ( $permissions < 0 || $permissions > Constants :: PERMISSION_ALL ) {
2021-04-27 06:38:28 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Invalid permissions' ));
2015-12-15 03:54:50 -05:00
}
// Shares always require read permissions
2017-12-01 08:49:35 -05:00
$permissions |= Constants :: PERMISSION_READ ;
2015-12-15 03:54:50 -05:00
2022-03-23 11:29:10 -04:00
if ( $node instanceof \OCP\Files\File ) {
2015-12-15 03:54:50 -05:00
// Single file shares should never have delete or create permissions
2017-12-01 08:49:35 -05:00
$permissions &= ~ Constants :: PERMISSION_DELETE ;
$permissions &= ~ 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 );
}
2022-10-11 08:00:15 -04:00
$share -> setSharedBy ( $this -> currentUser );
2022-07-15 11:11:54 -04:00
$this -> checkInheritedAttributes ( $share );
2022-07-15 08:52:04 -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 )) {
2016-07-20 03:55:43 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Please specify a valid user' ));
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
}
if ( $publicUpload === 'true' ) {
// Check if public upload is allowed
if ( ! $this -> shareManager -> shareApiLinkAllowPublicUpload ()) {
2016-07-20 04:41:09 -04:00
throw new OCSForbiddenException ( $this -> l -> t ( 'Public upload disabled by the administrator' ));
2015-12-15 03:54:50 -05:00
}
// Public upload can only be set for folders
2022-03-23 11:29:10 -04:00
if ( $node instanceof \OCP\Files\File ) {
2016-07-20 03:55:43 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Public upload is only possible for publicly shared folders' ));
2015-12-15 03:54:50 -05:00
}
2020-03-05 08:56:31 -05:00
$permissions = Constants :: PERMISSION_READ |
2017-12-01 08:49:35 -05:00
Constants :: PERMISSION_CREATE |
Constants :: PERMISSION_UPDATE |
2020-03-05 08:56:31 -05:00
Constants :: PERMISSION_DELETE ;
2015-12-15 03:54:50 -05:00
}
2020-04-29 10:43:39 -04:00
2020-05-06 15:39:49 -04:00
// TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
2022-10-17 06:37:46 -04:00
if ( $this -> shareManager -> outgoingServer2ServerSharesAllowed ()) {
2020-05-06 15:39:49 -04:00
$permissions |= Constants :: PERMISSION_SHARE ;
}
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 ) {
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
if ( ! empty ( $label )) {
$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 ) {
2021-04-16 02:56:20 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'Please specify a valid federated user ID' ));
2021-01-25 09:26:16 -05:00
}
2016-02-04 04:01:40 -05:00
$share -> setSharedWith ( $shareWith );
$share -> setPermissions ( $permissions );
2021-01-25 09:26:16 -05:00
if ( $expireDate !== '' ) {
try {
$expireDate = $this -> parseDate ( $expireDate );
$share -> setExpirationDate ( $expireDate );
} catch ( \Exception $e ) {
throw new OCSNotFoundException ( $this -> l -> t ( 'Invalid date, date format must be YYYY-MM-DD' ));
}
}
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 );
2021-01-25 09:26:16 -05:00
if ( $expireDate !== '' ) {
try {
$expireDate = $this -> parseDate ( $expireDate );
$share -> setExpirationDate ( $expireDate );
} catch ( \Exception $e ) {
throw new OCSNotFoundException ( $this -> l -> t ( 'Invalid date, date format must be YYYY-MM-DD' ));
}
}
2020-04-29 10:43:39 -04:00
} elseif ( $shareType === IShare :: TYPE_CIRCLE ) {
2017-07-11 07:21:24 -04:00
if ( ! \OC :: $server -> getAppManager () -> isEnabledForUser ( 'circles' ) || ! class_exists ( '\OCA\Circles\ShareByCircleProvider' )) {
2017-03-17 15:48:33 -04:00
throw new OCSNotFoundException ( $this -> l -> t ( 'You cannot share to a Circle if the app is not enabled' ));
}
2017-07-11 07:21:24 -04:00
$circle = \OCA\Circles\Api\v1\Circles :: detailsCircle ( $shareWith );
2017-03-17 15:48:33 -04:00
// Valid circle is required to share
if ( $circle === null ) {
throw new OCSNotFoundException ( $this -> l -> t ( 'Please specify a valid circle' ));
}
$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 {
$this -> getRoomShareHelper () -> createShare ( $share , $shareWith , $permissions , $expireDate );
} catch ( QueryException $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 {
$this -> getDeckShareHelper () -> createShare ( $share , $shareWith , $permissions , $expireDate );
} catch ( QueryException $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 {
$this -> getSciencemeshShareHelper () -> createShare ( $share , $shareWith , $permissions , $expireDate );
} catch ( QueryException $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
}
2023-04-27 10:26:24 -04:00
//Expire date
if ( $expireDate !== '' ) {
try {
$expireDate = $this -> parseDate ( $expireDate );
$share -> setExpirationDate ( $expireDate );
} catch ( \Exception $e ) {
throw new OCSNotFoundException ( $this -> l -> t ( 'Invalid date, date format must be YYYY-MM-DD' ));
}
}
2015-12-15 03:54:50 -05:00
$share -> setShareType ( $shareType );
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 );
2016-02-02 08:18:59 -05:00
} catch ( GenericShareException $e ) {
2021-03-15 07:00:41 -04:00
\OC :: $server -> getLogger () -> logException ( $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 );
2016-09-20 05:29:12 -04:00
} catch ( \Exception $e ) {
2021-03-15 07:00:41 -04:00
\OC :: $server -> getLogger () -> logException ( $e );
2018-01-17 09:21:56 -05:00
throw new OCSForbiddenException ( $e -> getMessage (), $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
*
2023-10-23 10:47:38 -04:00
* @ return 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 {
2020-04-29 10:43:39 -04:00
$userShares = $this -> shareManager -> getSharedWith ( $this -> currentUser , IShare :: TYPE_USER , $node , - 1 , 0 );
$groupShares = $this -> shareManager -> getSharedWith ( $this -> currentUser , IShare :: TYPE_GROUP , $node , - 1 , 0 );
$circleShares = $this -> shareManager -> getSharedWith ( $this -> currentUser , IShare :: TYPE_CIRCLE , $node , - 1 , 0 );
$roomShares = $this -> shareManager -> getSharedWith ( $this -> currentUser , IShare :: TYPE_ROOM , $node , - 1 , 0 );
2020-12-03 10:03:35 -05:00
$deckShares = $this -> shareManager -> getSharedWith ( $this -> currentUser , IShare :: TYPE_DECK , $node , - 1 , 0 );
2023-02-20 04:50:31 -05:00
$sciencemeshShares = $this -> shareManager -> getSharedWith ( $this -> currentUser , 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 ) {
2016-10-21 14:25:07 -04:00
return $share -> getShareOwner () !== $this -> currentUser ;
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 ) {
2017-08-22 12:46:47 -04:00
$formatted = Helper :: populateTags ( $formatted , 'file_source' , \OC :: $server -> getTagManager ());
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
/**
2019-06-25 16:34:38 -04:00
* @ param \OCP\Files\Node $folder
*
2023-10-23 10:47:38 -04:00
* @ return 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 {
2016-01-19 08:35:16 -05:00
if ( ! ( $folder instanceof \OCP\Files\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
2016-01-27 06:13:53 -05:00
/** @var \OCP\Share\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 ) {
if ( in_array ( $share -> getId (), $known ) || $share -> getSharedWith () === $this -> currentUser ) {
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 ;
if ( $share -> getSharedBy () === $this -> currentUser ) {
$miniFormatted [] = $format ;
}
if ( ! $resharingRight && $this -> shareProviderResharingRights ( $this -> currentUser , $share , $folder )) {
$resharingRight = true ;
}
} catch ( \Exception $e ) {
//Ignore this share
}
}
if ( ! $resharingRight ) {
$formatted = $miniFormatted ;
}
return $formatted ;
2016-01-19 08:35:16 -05:00
}
/**
2016-07-19 08:13:27 -04:00
* @ NoAdminRequired
*
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
*
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 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
*/
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 !== '' ) {
2016-10-21 14:25:07 -04:00
$userFolder = $this -> rootFolder -> getUserFolder ( $this -> currentUser );
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 (
$this -> currentUser ,
$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
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
*
2023-10-23 10:47:38 -04:00
* @ return 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 )
|| ( $share -> getSharedWith () === $this -> currentUser && $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
2018-11-01 10:01:01 -04:00
if ( $share -> getSharedBy () === $this -> currentUser ) {
$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
2019-11-26 14:28:08 -05:00
if ( ! $resharingRight && $this -> shareProviderResharingRights ( $this -> currentUser , $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 =
Helper :: populateTags ( $formatted , 'file_source' , \OC :: $server -> getTagManager ());
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
/**
* @ NoAdminRequired
*
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
*
2023-10-23 10:47:38 -04:00
* @ return DataResponse < Http :: STATUS_OK , 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
*/
public function getInheritedShares ( string $path ) : DataResponse {
// get Node from (string) path.
$userFolder = $this -> rootFolder -> getUserFolder ( $this -> currentUser );
try {
$node = $userFolder -> get ( $path );
$this -> lock ( $node );
} catch ( \OCP\Files\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 )) {
throw new SharingRightsException ( 'no sharing rights on this item' );
}
// 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 );
$nodes = $userFolder -> getById ( $node -> getId ());
$node = array_shift ( $nodes );
}
$basePath = $userFolder -> getPath ();
// generate node list for each parent folders
/** @var Node[] $nodes */
$nodes = [];
while ( $node -> getPath () !== $basePath ) {
$node = $node -> getParent ();
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
$currentUserFolder = $this -> rootFolder -> getUserFolder ( $this -> currentUser );
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
$currentUserNodes = $currentUserFolder -> getById ( $node -> getId ());
if ( ! empty ( $currentUserNodes )) {
$parent = array_pop ( $currentUserNodes );
}
$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 ;
}
2019-06-25 16:34:38 -04:00
2016-01-22 08:52:20 -05:00
/**
2016-07-19 08:13:27 -04:00
* @ NoAdminRequired
*
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
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
*/
2016-08-17 04:05:09 -04:00
public function updateShare (
2018-04-23 14:31:57 -04:00
string $id ,
int $permissions = null ,
string $password = null ,
2018-07-10 07:01:31 -04:00
string $sendPasswordByTalk = null ,
2018-04-23 14:31:57 -04:00
string $publicUpload = null ,
2018-07-12 08:55:50 -04:00
string $expireDate = null ,
2018-10-18 06:38:07 -04:00
string $note = null ,
2018-10-17 04:50:58 -04:00
string $label = null ,
2022-05-25 03:55:22 -04:00
string $hideDownload = null ,
string $attributes = 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 )) {
2018-12-05 05:27:38 -05:00
throw new OCSForbiddenException ( '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 &&
2022-05-25 03:55:22 -04:00
$attributes === 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
}
2022-10-10 10:09:14 -04:00
$this -> checkInheritedAttributes ( $share );
2022-07-15 11:11:54 -04:00
2019-08-06 04:22:32 -04:00
/**
2016-01-27 10:46:48 -05:00
* expirationdate , password and publicUpload only make sense for link shares
*/
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
/**
* We do not allow editing link shares that the current user
* doesn ' t own . This is confusing and lead to errors when
* someone else edit a password or expiration date without
* the share owner knowing about it .
* We only allow deletion
*/
if ( $share -> getSharedBy () !== $this -> currentUser ) {
throw new OCSForbiddenException ( 'You are not allowed to edit link shares that you don\'t own' );
}
2016-01-22 08:52:20 -05:00
2018-10-18 06:38:07 -04:00
// Update hide download state
if ( $hideDownload === 'true' ) {
$share -> setHideDownload ( true );
2020-04-10 04:35:09 -04:00
} elseif ( $hideDownload === 'false' ) {
2018-10-18 06:38:07 -04:00
$share -> setHideDownload ( false );
}
2016-01-27 14:32:04 -05:00
$newPermissions = null ;
if ( $publicUpload === 'true' ) {
2017-12-01 08:49:35 -05:00
$newPermissions = Constants :: PERMISSION_READ | Constants :: PERMISSION_CREATE | Constants :: PERMISSION_UPDATE | Constants :: PERMISSION_DELETE ;
2020-04-10 04:35:09 -04:00
} elseif ( $publicUpload === 'false' ) {
2017-12-01 08:49:35 -05:00
$newPermissions = Constants :: PERMISSION_READ ;
2016-01-22 08:52:20 -05:00
}
2016-01-27 14:32:04 -05:00
if ( $permissions !== null ) {
2021-01-11 06:57:03 -05:00
$newPermissions = $permissions ;
2017-12-01 08:49:35 -05:00
$newPermissions = $newPermissions & ~ Constants :: PERMISSION_SHARE ;
2016-01-27 14:32:04 -05:00
}
2016-01-22 08:52:20 -05:00
2022-02-02 10:10:52 -05:00
if ( $newPermissions !== null ) {
if ( ! $this -> hasPermission ( $newPermissions , Constants :: PERMISSION_READ ) && ! $this -> hasPermission ( $newPermissions , Constants :: PERMISSION_CREATE )) {
throw new OCSBadRequestException ( $this -> l -> t ( 'Share must at least have READ or CREATE permissions' ));
}
if ( ! $this -> hasPermission ( $newPermissions , Constants :: PERMISSION_READ ) && (
2023-11-23 04:22:34 -05:00
$this -> hasPermission ( $newPermissions , Constants :: PERMISSION_UPDATE ) || $this -> hasPermission ( $newPermissions , Constants :: PERMISSION_DELETE )
)) {
2022-02-17 09:03:53 -05:00
throw new OCSBadRequestException ( $this -> l -> t ( 'Share must have READ permission if UPDATE or DELETE permission is set' ));
2022-02-02 10:10:52 -05:00
}
2016-01-27 14:32:04 -05:00
}
2016-06-23 09:43:21 -04:00
if (
// legacy
2017-12-01 08:49:35 -05:00
$newPermissions === ( Constants :: PERMISSION_READ | Constants :: PERMISSION_CREATE | Constants :: PERMISSION_UPDATE ) ||
2016-06-23 09:43:21 -04:00
// correct
2017-12-01 08:49:35 -05:00
$newPermissions === ( Constants :: PERMISSION_READ | Constants :: PERMISSION_CREATE | Constants :: PERMISSION_UPDATE | Constants :: PERMISSION_DELETE )
2016-06-23 09:43:21 -04:00
) {
2016-01-27 14:32:04 -05:00
if ( ! $this -> shareManager -> shareApiLinkAllowPublicUpload ()) {
2016-07-20 04:41:09 -04:00
throw new OCSForbiddenException ( $this -> l -> t ( 'Public upload disabled by the administrator' ));
2016-01-27 14:32:04 -05:00
}
2016-01-28 07:17:16 -05:00
if ( ! ( $share -> getNode () instanceof \OCP\Files\Folder )) {
2016-07-20 04:41:09 -04:00
throw new OCSBadRequestException ( $this -> l -> t ( 'Public upload is only possible for publicly shared folders' ));
2016-01-27 14:32:04 -05:00
}
2016-06-23 09:43:21 -04:00
// normalize to correct public upload permissions
2022-09-07 07:51:38 -04:00
if ( $publicUpload === 'true' ) {
$newPermissions = Constants :: PERMISSION_READ | Constants :: PERMISSION_CREATE | Constants :: PERMISSION_UPDATE | Constants :: PERMISSION_DELETE ;
}
2016-01-27 14:32:04 -05:00
}
if ( $newPermissions !== null ) {
2020-05-06 15:39:49 -04:00
// TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
if (( $newPermissions & Constants :: PERMISSION_READ ) && $this -> shareManager -> outgoingServer2ServerSharesAllowed ()) {
$newPermissions |= Constants :: PERMISSION_SHARE ;
}
2016-01-27 14:32:04 -05:00
$share -> setPermissions ( $newPermissions );
2016-11-13 14:29:34 -05:00
$permissions = $newPermissions ;
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 );
}
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 {
$expireDate = $this -> parseDate ( $expireDate );
} catch ( \Exception $e ) {
throw new OCSBadRequestException ( $e -> getMessage (), $e );
2017-03-29 10:50:23 -04:00
}
2023-04-27 10:26:24 -04:00
$share -> setExpirationDate ( $expireDate );
2016-01-22 08:52:20 -05:00
}
try {
$share = $this -> shareManager -> updateShare ( $share );
2019-07-03 10:32:45 -04:00
} catch ( GenericShareException $e ) {
$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 ) {
2018-01-17 09:21:56 -05:00
throw new OCSBadRequestException ( $e -> getMessage (), $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
}
2020-01-07 02:53:33 -05:00
/**
* @ NoAdminRequired
2023-02-15 13:22:09 -05:00
*
* Get all shares that are still pending
*
2023-10-23 10:47:38 -04:00
* @ return DataResponse < Http :: STATUS_OK , Files_SharingShare [], array {} >
2023-09-19 08:12:17 -04:00
*
* 200 : Pending shares returned
2020-01-07 02:53:33 -05:00
*/
public function pendingShares () : DataResponse {
$pendingShares = [];
$shareTypes = [
IShare :: TYPE_USER ,
IShare :: TYPE_GROUP
];
foreach ( $shareTypes as $shareType ) {
$shares = $this -> shareManager -> getSharedWith ( $this -> currentUser , $shareType , null , - 1 , 0 );
foreach ( $shares as $share ) {
if ( $share -> getStatus () === IShare :: STATUS_PENDING || $share -> getStatus () === IShare :: STATUS_REJECTED ) {
$pendingShares [] = $share ;
}
}
}
2020-01-07 06:57:57 -05:00
$result = array_filter ( array_map ( function ( IShare $share ) {
$userFolder = $this -> rootFolder -> getUserFolder ( $share -> getSharedBy ());
$nodes = $userFolder -> getById ( $share -> getNodeId ());
if ( empty ( $nodes )) {
// fallback to guessing the path
$node = $userFolder -> get ( $share -> getTarget ());
if ( $node === null || $share -> getTarget () === '' ) {
return null ;
}
} else {
$node = $nodes [ 0 ];
}
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 ;
});
2020-01-07 02:53:33 -05:00
return new DataResponse ( $result );
}
2019-08-21 21:17:17 -04:00
/**
* @ NoAdminRequired
*
2023-02-15 13:22:09 -05:00
* Accept a share
*
* @ param string $id ID of the share
* @ return DataResponse < Http :: STATUS_OK , array < empty > , array {} >
* @ 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
*/
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 {
2019-09-04 10:50:52 -04:00
$this -> shareManager -> acceptShare ( $share , $this -> currentUser );
2019-08-21 21:17:17 -04:00
} catch ( GenericShareException $e ) {
$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 ) {
throw new OCSBadRequestException ( $e -> getMessage (), $e );
}
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
*
* @ param \OCP\Share\IShare $share the share to check
* @ param boolean $checkGroups check groups as well ?
* @ return boolean
* @ throws NotFoundException
*
2018-07-24 05:57:52 -04:00
* @ suppress PhanUndeclaredClassMethod
*/
2018-04-23 14:31:57 -04:00
protected function canAccessShare ( \OCP\Share\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
2019-08-06 04:22:32 -04:00
if ( $share -> getShareOwner () === $this -> currentUser
|| $share -> getSharedBy () === $this -> currentUser ) {
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
2019-08-06 04:22:32 -04:00
&& $share -> getSharedWith () === $this -> currentUser ) {
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?
$userFolder = $this -> rootFolder -> getUserFolder ( $this -> currentUser );
$files = $userFolder -> getById ( $share -> getNodeId ());
if ( ! empty ( $files ) && $this -> shareProviderResharingRights ( $this -> currentUser , $share , $files [ 0 ])) {
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 ());
2016-10-21 14:25:07 -04:00
$user = $this -> userManager -> get ( $this -> currentUser );
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 {
return $this -> getRoomShareHelper () -> canAccessShare ( $share , $this -> currentUser );
} catch ( QueryException $e ) {
return false ;
}
}
2020-12-03 10:03:35 -05:00
if ( $share -> getShareType () === IShare :: TYPE_DECK ) {
try {
return $this -> getDeckShareHelper () -> canAccessShare ( $share , $this -> currentUser );
} catch ( QueryException $e ) {
return false ;
}
}
2023-02-20 04:50:31 -05:00
if ( $share -> getShareType () === IShare :: TYPE_SCIENCEMESH ) {
try {
return $this -> getSciencemeshShareHelper () -> canAccessShare ( $share , $this -> currentUser );
} catch ( QueryException $e ) {
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
*
* @ param \OCP\Share\IShare $share the share to check
* @ return boolean
*/
protected function canEditShare ( \OCP\Share\IShare $share ) : bool {
// 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
if ( $share -> getShareOwner () === $this -> currentUser ||
$share -> getSharedBy () === $this -> currentUser
) {
return true ;
}
//! 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
*
* @ param \OCP\Share\IShare $share the share to check
* @ return boolean
*/
protected function canDeleteShare ( \OCP\Share\IShare $share ) : bool {
// 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 &&
2019-08-26 07:11:09 -04:00
$share -> getSharedWith () === $this -> currentUser
) {
return true ;
}
// The owner of the file and the creator of the share
// can always delete the share
if ( $share -> getShareOwner () === $this -> currentUser ||
$share -> getSharedBy () === $this -> currentUser
) {
return true ;
}
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 .
*
* @ param \OCP\Share\IShare $share the share to check
* @ return boolean
*
* @ suppress PhanUndeclaredClassMethod
*/
protected function canDeleteShareFromSelf ( \OCP\Share\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 ;
}
if ( $share -> getShareOwner () === $this -> currentUser ||
$share -> getSharedBy () === $this -> currentUser
) {
// 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 ());
$user = $this -> userManager -> get ( $this -> currentUser );
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 {
return $this -> getRoomShareHelper () -> canAccessShare ( $share , $this -> currentUser );
} catch ( QueryException $e ) {
return false ;
}
}
2020-12-03 10:03:35 -05:00
if ( $share -> getShareType () === IShare :: TYPE_DECK ) {
try {
return $this -> getDeckShareHelper () -> canAccessShare ( $share , $this -> currentUser );
} catch ( QueryException $e ) {
return false ;
}
}
2023-02-20 04:50:31 -05:00
if ( $share -> getShareType () === IShare :: TYPE_SCIENCEMESH ) {
try {
return $this -> getSciencemeshShareHelper () -> canAccessShare ( $share , $this -> currentUser );
} catch ( QueryException $e ) {
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 ) {
throw new \Exception ( 'Invalid date. Format must be YYYY-MM-DD' );
}
2024-02-07 06:06:12 -05:00
// Use server timezone to store the date
2024-01-08 18:46:26 -05:00
$date -> setTimezone ( new \DateTimeZone ( date_default_timezone_get ()));
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
* @ return \OCP\Share\IShare
* @ 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 {
Fix getting the information of group share as a sharee
When the receiver of a group share modifies it (for example, by moving
it to a different folder) the original share is not modified, but a
"ghost" share that keeps track of the changes made by that specific user
is used instead.
By default, the method "getShareById" in the share provider returns the
share from the point of view of the sharer, but it can be used too to
get the share from the point of view of a sharee by providing the
"recipient" parameter (and if the sharee is not found then the share is
returned from the point of view of the sharer).
The "ShareAPIController" always formats the share from the point of view
of the current user, but when getting the information of a specific
share the "recipient" parameter was not given, so it was always returned
from the point of view of the sharer, even if the current user was a
sharee. Now the "recipient" parameter is set to the current user, and
thus the information of the share is returned from the point of view of
the current user, be it the sharer or a sharee.
Note that this special behaviour of "getShareById" happens only with
group shares; with other types of shares the share is the same for the
sharer and the sharee, and thus the parameter is ignored; it was added
for them too just for consistency.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-06-28 06:34:04 -04:00
$share = $this -> shareManager -> getShareById ( 'ocinternal:' . $id , $this -> currentUser );
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 )) {
Fix getting the information of group share as a sharee
When the receiver of a group share modifies it (for example, by moving
it to a different folder) the original share is not modified, but a
"ghost" share that keeps track of the changes made by that specific user
is used instead.
By default, the method "getShareById" in the share provider returns the
share from the point of view of the sharer, but it can be used too to
get the share from the point of view of a sharee by providing the
"recipient" parameter (and if the sharee is not found then the share is
returned from the point of view of the sharer).
The "ShareAPIController" always formats the share from the point of view
of the current user, but when getting the information of a specific
share the "recipient" parameter was not given, so it was always returned
from the point of view of the sharer, even if the current user was a
sharee. Now the "recipient" parameter is set to the current user, and
thus the information of the share is returned from the point of view of
the current user, be it the sharer or a sharee.
Note that this special behaviour of "getShareById" happens only with
group shares; with other types of shares the share is the same for the
sharer and the sharee, and thus the parameter is ignored; it was added
for them too just for consistency.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-06-28 06:34:04 -04:00
$share = $this -> shareManager -> getShareById ( 'ocCircleShare:' . $id , $this -> currentUser );
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 )) {
Fix getting the information of group share as a sharee
When the receiver of a group share modifies it (for example, by moving
it to a different folder) the original share is not modified, but a
"ghost" share that keeps track of the changes made by that specific user
is used instead.
By default, the method "getShareById" in the share provider returns the
share from the point of view of the sharer, but it can be used too to
get the share from the point of view of a sharee by providing the
"recipient" parameter (and if the sharee is not found then the share is
returned from the point of view of the sharer).
The "ShareAPIController" always formats the share from the point of view
of the current user, but when getting the information of a specific
share the "recipient" parameter was not given, so it was always returned
from the point of view of the sharer, even if the current user was a
sharee. Now the "recipient" parameter is set to the current user, and
thus the information of the share is returned from the point of view of
the current user, be it the sharer or a sharee.
Note that this special behaviour of "getShareById" happens only with
group shares; with other types of shares the share is the same for the
sharer and the sharee, and thus the parameter is ignored; it was added
for them too just for consistency.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-06-28 06:34:04 -04:00
$share = $this -> shareManager -> getShareById ( 'ocMailShare:' . $id , $this -> currentUser );
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 {
$share = $this -> shareManager -> getShareById ( 'ocRoomShare:' . $id , $this -> currentUser );
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 )) {
$share = $this -> shareManager -> getShareById ( 'deck:' . $id , $this -> currentUser );
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 )) {
$share = $this -> shareManager -> getShareById ( 'sciencemesh:' . $id , $this -> currentUser );
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
}
Fix getting the information of group share as a sharee
When the receiver of a group share modifies it (for example, by moving
it to a different folder) the original share is not modified, but a
"ghost" share that keeps track of the changes made by that specific user
is used instead.
By default, the method "getShareById" in the share provider returns the
share from the point of view of the sharer, but it can be used too to
get the share from the point of view of a sharee by providing the
"recipient" parameter (and if the sharee is not found then the share is
returned from the point of view of the sharer).
The "ShareAPIController" always formats the share from the point of view
of the current user, but when getting the information of a specific
share the "recipient" parameter was not given, so it was always returned
from the point of view of the sharer, even if the current user was a
sharee. Now the "recipient" parameter is set to the current user, and
thus the information of the share is returned from the point of view of
the current user, be it the sharer or a sharee.
Note that this special behaviour of "getShareById" happens only with
group shares; with other types of shares the share is the same for the
sharer and the sharee, and thus the parameter is ignored; it was added
for them too just for consistency.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-06-28 06:34:04 -04:00
$share = $this -> shareManager -> getShareById ( 'ocFederatedSharing:' . $id , $this -> currentUser );
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
*
2016-07-20 04:11:01 -04:00
* @ param \OCP\Files\Node $node
2018-04-23 14:31:57 -04:00
* @ throws LockedException
2016-07-20 04:11:01 -04:00
*/
private function lock ( \OCP\Files\Node $node ) {
$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
* a QueryException is thrown instead .
*
2019-09-05 09:32:58 -04:00
* @ return \OCA\Talk\Share\Helper\ShareAPIController
2018-06-29 07:22:26 -04:00
* @ throws QueryException
*/
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
* a QueryException is thrown instead .
*
* @ return \OCA\Deck\Sharing\ShareAPIHelper
* @ throws QueryException
*/
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
* a QueryException is thrown instead .
*
* @ return \OCA\Deck\Sharing\ShareAPIHelper
* @ throws QueryException
*/
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 (
2020-04-29 10:43:39 -04:00
$this -> currentUser , 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 (
2020-04-29 10:43:39 -04:00
$this -> currentUser , 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 {
if ( ! $this -> hasResharingRights ( $this -> currentUser , $node )) {
throw new SharingRightsException ( 'no sharing rights on this item' );
}
}
/**
* @ 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 ;
}
2018-10-29 05:03:52 -04:00
if (( \OCP\Constants :: PERMISSION_SHARE & $share -> getPermissions ()) === 0 ) {
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 ;
}
2020-05-28 19:41:06 -04:00
if ( $share -> getShareType () === IShare :: TYPE_CIRCLE && \OC :: $server -> getAppManager () -> 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 {
$member = \OCA\Circles\Api\v1\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 ;
2018-10-30 04:58:43 -04:00
} catch ( QueryException $e ) {
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
2020-04-29 10:43:39 -04:00
$userShares = $this -> shareManager -> getSharesBy ( $this -> currentUser , IShare :: TYPE_USER , $path , $reshares , - 1 , 0 );
$groupShares = $this -> shareManager -> getSharesBy ( $this -> currentUser , IShare :: TYPE_GROUP , $path , $reshares , - 1 , 0 );
$linkShares = $this -> shareManager -> getSharesBy ( $this -> currentUser , IShare :: TYPE_LINK , $path , $reshares , - 1 , 0 );
2019-10-25 04:45:49 -04:00
// EMAIL SHARES
2020-04-29 10:43:39 -04:00
$mailShares = $this -> shareManager -> getSharesBy ( $this -> currentUser , IShare :: TYPE_EMAIL , $path , $reshares , - 1 , 0 );
2019-10-25 04:45:49 -04:00
// CIRCLE SHARES
2020-04-29 10:43:39 -04:00
$circleShares = $this -> shareManager -> getSharesBy ( $this -> currentUser , IShare :: TYPE_CIRCLE , $path , $reshares , - 1 , 0 );
2019-10-25 04:45:49 -04:00
// TALK SHARES
2020-04-29 10:43:39 -04:00
$roomShares = $this -> shareManager -> getSharesBy ( $this -> currentUser , 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
2020-12-03 10:03:35 -05:00
$deckShares = $this -> shareManager -> getSharesBy ( $this -> currentUser , IShare :: TYPE_DECK , $path , $reshares , - 1 , 0 );
2023-02-20 04:50:31 -05:00
// SCIENCEMESH SHARES
$sciencemeshShares = $this -> shareManager -> getSharesBy ( $this -> currentUser , IShare :: TYPE_SCIENCEMESH , $path , $reshares , - 1 , 0 );
2019-10-25 04:45:49 -04:00
// FEDERATION
if ( $this -> shareManager -> outgoingServer2ServerSharesAllowed ()) {
2020-04-29 10:43:39 -04:00
$federatedShares = $this -> shareManager -> getSharesBy ( $this -> currentUser , IShare :: TYPE_REMOTE , $path , $reshares , - 1 , 0 );
2019-10-25 04:45:49 -04:00
} else {
$federatedShares = [];
}
if ( $this -> shareManager -> outgoingServer2ServerGroupSharesAllowed ()) {
2020-04-29 10:43:39 -04:00
$federatedGroupShares = $this -> shareManager -> getSharesBy ( $this -> currentUser , 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' ],
is_string ( $formattedAttr [ 'enabled' ]) ? ( bool ) \json_decode ( $formattedAttr [ 'enabled' ]) : $formattedAttr [ 'enabled' ]
);
}
} else {
throw new OCSBadRequestException ( 'Invalid share attributes provided: \"' . $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
}
2022-10-10 10:09:14 -04:00
$userFolder = $this -> rootFolder -> getUserFolder ( $share -> getSharedBy ());
$nodes = $userFolder -> getById ( $share -> getNodeId ());
if ( empty ( $nodes )) {
2022-10-11 08:00:15 -04:00
return ;
2022-10-10 10:09:14 -04:00
}
$node = $nodes [ 0 ];
if ( $node -> getStorage () -> instanceOfStorage ( SharedStorage :: class )) {
$storage = $node -> getStorage ();
2022-07-15 11:11:54 -04:00
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' );
}
/** @var \OCA\Files_Sharing\SharedStorage $storage */
$inheritedAttributes = $storage -> getShare () -> getAttributes ();
if ( $inheritedAttributes !== null && $inheritedAttributes -> getAttribute ( 'permissions' , 'download' ) === false ) {
$share -> setHideDownload ( true );
2022-10-10 10:09:14 -04:00
$attributes = $share -> getAttributes ();
if ( $attributes ) {
$attributes -> setAttribute ( 'permissions' , 'download' , false );
$share -> setAttributes ( $attributes );
}
2022-07-15 11:11:54 -04:00
}
}
}
2015-10-30 08:10:08 -04:00
}