2014-10-15 13:58:44 +04:00
< ? php
/**
2016-07-21 17:49:16 +03:00
* @ copyright Copyright ( c ) 2016 , ownCloud , Inc .
*
2016-05-26 20:56:05 +03:00
* @ author Arthur Schiwon < blizzz @ arthur - schiwon . de >
2016-07-21 17:49:16 +03:00
* @ author Bjoern Schiessle < bjoern @ schiessle . org >
2016-05-26 20:56:05 +03:00
* @ author Björn Schießle < bjoern @ schiessle . org >
2017-11-06 22:15:27 +03:00
* @ author Georg Ehrke < oc . list @ georgehrke . com >
2016-07-21 17:49:16 +03:00
* @ author Joas Schilling < coding @ schilljs . com >
2016-05-26 20:56:05 +03:00
* @ author Lukas Reschke < lukas @ statuscode . ch >
2017-11-06 17:56:42 +03:00
* @ author Maxence Lange < maxence @ pontapreta . net >
2015-03-26 13:44:34 +03:00
* @ author Morris Jobke < hey @ morrisjobke . de >
2016-05-26 20:56:05 +03:00
* @ author Piotr Filiciak < piotr @ filiciak . pl >
2016-07-21 19:13:36 +03:00
* @ author Robin Appelman < robin @ icewind . nl >
2016-07-21 17:49:16 +03:00
* @ author Roeland Jago Douma < roeland @ famdouma . nl >
2017-11-06 17:56:42 +03:00
* @ author Sascha Sambale < mastixmc @ gmail . com >
* @ author Thomas Müller < thomas . mueller @ tmit . eu >
2015-10-26 15:54:55 +03:00
* @ author Vincent Petry < pvince81 @ owncloud . com >
2015-03-26 13:44:34 +03: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 ,
* along with this program . If not , see < http :// www . gnu . org / licenses />
2014-10-15 13:58:44 +04:00
*
*/
2015-02-26 13:37:37 +03:00
2016-10-24 12:46:25 +03:00
namespace OCA\Files_Sharing\Controller ;
2014-10-15 13:58:44 +04:00
use OC_Files ;
use OC_Util ;
2016-04-18 19:17:08 +03:00
use OCA\FederatedFileSharing\FederatedShareProvider ;
2018-01-25 20:53:09 +03:00
use OCP\AppFramework\Http\Template\SimpleMenuAction ;
2018-04-05 12:09:19 +03:00
use OCP\AppFramework\Http\Template\ExternalShareMenuAction ;
use OCP\AppFramework\Http\Template\LinkMenuAction ;
2018-01-25 20:53:09 +03:00
use OCP\AppFramework\Http\Template\PublicTemplateResponse ;
2016-07-22 17:13:26 +03:00
use OCP\Defaults ;
use OCP\IL10N ;
2014-10-15 13:58:44 +04:00
use OCP\Template ;
use OCP\Share ;
use OCP\AppFramework\Controller ;
use OCP\IRequest ;
use OCP\AppFramework\Http\TemplateResponse ;
use OCP\AppFramework\Http\RedirectResponse ;
2015-03-24 13:21:58 +03:00
use OCP\AppFramework\Http\NotFoundResponse ;
2016-01-15 11:41:51 +03:00
use OCP\IURLGenerator ;
use OCP\IConfig ;
2014-10-15 13:58:44 +04:00
use OCP\ILogger ;
2016-01-15 11:41:51 +03:00
use OCP\IUserManager ;
use OCP\ISession ;
use OCP\IPreview ;
2016-11-16 14:09:41 +03:00
use OCA\Files_Sharing\Activity\Providers\Downloads ;
2015-09-30 14:32:20 +03:00
use \OCP\Files\NotFoundException ;
2016-01-15 13:49:50 +03:00
use OCP\Files\IRootFolder ;
2016-02-02 16:07:11 +03:00
use OCP\Share\Exceptions\ShareNotFound ;
2016-07-15 16:01:14 +03:00
use Symfony\Component\EventDispatcher\EventDispatcherInterface ;
2014-10-15 13:58:44 +04:00
/**
* Class ShareController
*
* @ package OCA\Files_Sharing\Controllers
*/
class ShareController extends Controller {
2016-01-15 11:41:51 +03:00
/** @var IConfig */
2014-10-15 13:58:44 +04:00
protected $config ;
2016-01-15 11:41:51 +03:00
/** @var IURLGenerator */
2014-10-15 13:58:44 +04:00
protected $urlGenerator ;
2016-01-15 11:41:51 +03:00
/** @var IUserManager */
2014-10-15 13:58:44 +04:00
protected $userManager ;
2016-01-15 11:41:51 +03:00
/** @var ILogger */
2014-10-15 13:58:44 +04:00
protected $logger ;
2016-07-18 14:34:18 +03:00
/** @var \OCP\Activity\IManager */
2014-12-22 14:35:50 +03:00
protected $activityManager ;
2016-07-18 14:34:18 +03:00
/** @var \OCP\Share\IManager */
2016-01-15 10:11:11 +03:00
protected $shareManager ;
2016-01-15 11:41:51 +03:00
/** @var ISession */
2016-01-15 10:11:11 +03:00
protected $session ;
2016-01-15 11:41:51 +03:00
/** @var IPreview */
2016-01-15 10:11:11 +03:00
protected $previewManager ;
2016-01-15 13:49:50 +03:00
/** @var IRootFolder */
protected $rootFolder ;
2016-04-18 19:17:08 +03:00
/** @var FederatedShareProvider */
protected $federatedShareProvider ;
2016-07-15 16:01:14 +03:00
/** @var EventDispatcherInterface */
protected $eventDispatcher ;
2016-07-22 17:13:26 +03:00
/** @var IL10N */
protected $l10n ;
/** @var Defaults */
protected $defaults ;
2014-10-15 13:58:44 +04:00
/**
* @ param string $appName
* @ param IRequest $request
2016-01-15 11:41:51 +03:00
* @ param IConfig $config
* @ param IURLGenerator $urlGenerator
* @ param IUserManager $userManager
2014-10-15 13:58:44 +04:00
* @ param ILogger $logger
2016-07-18 14:34:18 +03:00
* @ param \OCP\Activity\IManager $activityManager
2016-02-09 12:36:44 +03:00
* @ param \OCP\Share\IManager $shareManager
2016-01-15 11:41:51 +03:00
* @ param ISession $session
* @ param IPreview $previewManager
2016-01-20 12:14:03 +03:00
* @ param IRootFolder $rootFolder
2016-04-18 19:17:08 +03:00
* @ param FederatedShareProvider $federatedShareProvider
2016-07-15 16:01:14 +03:00
* @ param EventDispatcherInterface $eventDispatcher
2016-07-22 17:13:26 +03:00
* @ param IL10N $l10n
2017-04-07 23:42:43 +03:00
* @ param Defaults $defaults
2014-10-15 13:58:44 +04:00
*/
public function __construct ( $appName ,
IRequest $request ,
2016-01-15 11:41:51 +03:00
IConfig $config ,
IURLGenerator $urlGenerator ,
IUserManager $userManager ,
2014-12-22 14:35:50 +03:00
ILogger $logger ,
2016-01-15 11:41:51 +03:00
\OCP\Activity\IManager $activityManager ,
2016-02-09 12:36:44 +03:00
\OCP\Share\IManager $shareManager ,
2016-01-15 11:41:51 +03:00
ISession $session ,
2016-01-15 13:49:50 +03:00
IPreview $previewManager ,
2016-04-18 19:17:08 +03:00
IRootFolder $rootFolder ,
2016-07-15 16:01:14 +03:00
FederatedShareProvider $federatedShareProvider ,
2016-07-22 17:13:26 +03:00
EventDispatcherInterface $eventDispatcher ,
IL10N $l10n ,
2017-04-07 23:42:43 +03:00
Defaults $defaults ) {
2014-10-15 13:58:44 +04:00
parent :: __construct ( $appName , $request );
$this -> config = $config ;
$this -> urlGenerator = $urlGenerator ;
$this -> userManager = $userManager ;
$this -> logger = $logger ;
2014-12-22 14:35:50 +03:00
$this -> activityManager = $activityManager ;
2016-01-15 10:11:11 +03:00
$this -> shareManager = $shareManager ;
$this -> session = $session ;
$this -> previewManager = $previewManager ;
2016-01-15 13:49:50 +03:00
$this -> rootFolder = $rootFolder ;
2016-04-18 19:17:08 +03:00
$this -> federatedShareProvider = $federatedShareProvider ;
2016-07-15 16:01:14 +03:00
$this -> eventDispatcher = $eventDispatcher ;
2016-07-22 17:13:26 +03:00
$this -> l10n = $l10n ;
$this -> defaults = $defaults ;
2014-10-15 13:58:44 +04:00
}
/**
* @ PublicPage
* @ NoCSRFRequired
*
* @ param string $token
* @ return TemplateResponse | RedirectResponse
*/
public function showAuthenticate ( $token ) {
2016-01-15 10:11:11 +03:00
$share = $this -> shareManager -> getShareByToken ( $token );
2014-10-15 13:58:44 +04:00
2016-01-15 10:11:11 +03:00
if ( $this -> linkShareAuth ( $share )) {
2014-10-15 13:58:44 +04:00
return new RedirectResponse ( $this -> urlGenerator -> linkToRoute ( 'files_sharing.sharecontroller.showShare' , array ( 'token' => $token )));
}
return new TemplateResponse ( $this -> appName , 'authenticate' , array (), 'guest' );
}
/**
* @ PublicPage
2014-11-17 15:10:15 +03:00
* @ UseSession
2017-04-12 21:32:48 +03:00
* @ BruteForceProtection ( action = publicLinkAuth )
2014-10-15 13:58:44 +04:00
*
* Authenticates against password - protected shares
2015-12-07 15:05:27 +03:00
* @ param string $token
2018-02-28 19:05:55 +03:00
* @ param string $redirect
2014-10-15 13:58:44 +04:00
* @ param string $password
2016-07-18 14:34:18 +03:00
* @ return RedirectResponse | TemplateResponse | NotFoundResponse
2014-10-15 13:58:44 +04:00
*/
2018-03-01 15:12:24 +03:00
public function authenticate ( $token , $redirect , $password = '' ) {
2016-01-15 10:11:11 +03:00
// Check whether share exists
try {
$share = $this -> shareManager -> getShareByToken ( $token );
2016-02-02 16:07:11 +03:00
} catch ( ShareNotFound $e ) {
2015-03-24 13:21:58 +03:00
return new NotFoundResponse ();
2014-10-15 13:58:44 +04:00
}
2016-01-15 10:11:11 +03:00
$authenticate = $this -> linkShareAuth ( $share , $password );
2014-10-15 13:58:44 +04:00
2018-02-28 19:08:25 +03:00
// if download was requested before auth, redirect to download
2018-02-28 19:05:55 +03:00
if ( $authenticate === true && $redirect === 'download' ) {
2018-02-28 19:08:25 +03:00
return new RedirectResponse ( $this -> urlGenerator -> linkToRoute (
'files_sharing.sharecontroller.downloadShare' ,
array ( 'token' => $token ))
);
2018-02-28 19:05:55 +03:00
} else if ( $authenticate === true ) {
2018-02-28 19:08:25 +03:00
return new RedirectResponse ( $this -> urlGenerator -> linkToRoute (
'files_sharing.sharecontroller.showShare' ,
array ( 'token' => $token ))
);
2014-10-15 13:58:44 +04:00
}
2017-04-14 14:42:40 +03:00
$response = new TemplateResponse ( $this -> appName , 'authenticate' , array ( 'wrongpw' => true ), 'guest' );
$response -> throttle ();
return $response ;
2014-10-15 13:58:44 +04:00
}
2016-01-15 10:11:11 +03:00
/**
* Authenticate a link item with the given password .
* Or use the session if no password is provided .
*
* This is a modified version of Helper :: authenticate
* TODO : Try to merge back eventually with Helper :: authenticate
*
2016-01-27 14:13:53 +03:00
* @ param \OCP\Share\IShare $share
2016-01-15 10:11:11 +03:00
* @ param string | null $password
* @ return bool
*/
2016-01-27 14:13:53 +03:00
private function linkShareAuth ( \OCP\Share\IShare $share , $password = null ) {
2016-01-15 10:11:11 +03:00
if ( $password !== null ) {
if ( $this -> shareManager -> checkPassword ( $share , $password )) {
$this -> session -> set ( 'public_link_authenticated' , ( string ) $share -> getId ());
} else {
2016-02-09 02:34:10 +03:00
$this -> emitAccessShareHook ( $share , 403 , 'Wrong password' );
2016-01-15 10:11:11 +03:00
return false ;
}
} else {
// not authenticated ?
if ( ! $this -> session -> exists ( 'public_link_authenticated' )
|| $this -> session -> get ( 'public_link_authenticated' ) !== ( string ) $share -> getId ()) {
return false ;
}
}
return true ;
}
2016-02-09 02:34:10 +03:00
/**
* throws hooks when a share is attempted to be accessed
*
2016-02-09 12:36:44 +03:00
* @ param \OCP\Share\IShare | string $share the Share instance if available ,
2016-02-09 02:34:10 +03:00
* otherwise token
* @ param int $errorCode
* @ param string $errorMessage
2016-07-18 14:34:18 +03:00
* @ throws \OC\HintException
* @ throws \OC\ServerNotAvailableException
2016-02-09 02:34:10 +03:00
*/
protected function emitAccessShareHook ( $share , $errorCode = 200 , $errorMessage = '' ) {
$itemType = $itemSource = $uidOwner = '' ;
$token = $share ;
$exception = null ;
2016-02-09 12:36:44 +03:00
if ( $share instanceof \OCP\Share\IShare ) {
2016-02-09 02:34:10 +03:00
try {
$token = $share -> getToken ();
$uidOwner = $share -> getSharedBy ();
2016-02-09 12:36:44 +03:00
$itemType = $share -> getNodeType ();
$itemSource = $share -> getNodeId ();
2016-02-09 02:34:10 +03:00
} catch ( \Exception $e ) {
// we log what we know and pass on the exception afterwards
$exception = $e ;
}
}
2018-01-26 01:16:13 +03:00
\OC_Hook :: emit ( Share :: class , 'share_link_access' , [
2016-02-09 02:34:10 +03:00
'itemType' => $itemType ,
'itemSource' => $itemSource ,
'uidOwner' => $uidOwner ,
'token' => $token ,
'errorCode' => $errorCode ,
'errorMessage' => $errorMessage ,
]);
if ( ! is_null ( $exception )) {
throw $exception ;
}
}
2016-02-09 15:00:08 +03:00
/**
* Validate the permissions of the share
*
* @ param Share\IShare $share
* @ return bool
*/
private function validateShare ( \OCP\Share\IShare $share ) {
return $share -> getNode () -> isReadable () && $share -> getNode () -> isShareable ();
}
2014-10-15 13:58:44 +04:00
/**
* @ PublicPage
* @ NoCSRFRequired
*
* @ param string $token
* @ param string $path
2016-07-18 14:34:18 +03:00
* @ return TemplateResponse | RedirectResponse | NotFoundResponse
2015-09-30 14:32:20 +03:00
* @ throws NotFoundException
2016-06-08 16:38:11 +03:00
* @ throws \Exception
2014-10-15 13:58:44 +04:00
*/
public function showShare ( $token , $path = '' ) {
\OC_User :: setIncognitoMode ( true );
// Check whether share exists
2016-01-15 10:11:11 +03:00
try {
$share = $this -> shareManager -> getShareByToken ( $token );
2016-02-02 16:07:11 +03:00
} catch ( ShareNotFound $e ) {
2016-02-09 02:34:10 +03:00
$this -> emitAccessShareHook ( $token , 404 , 'Share not found' );
2015-03-24 13:21:58 +03:00
return new NotFoundResponse ();
2014-10-15 13:58:44 +04:00
}
// Share is password protected - check whether the user is permitted to access the share
2016-01-15 10:11:11 +03:00
if ( $share -> getPassword () !== null && ! $this -> linkShareAuth ( $share )) {
2014-10-15 13:58:44 +04:00
return new RedirectResponse ( $this -> urlGenerator -> linkToRoute ( 'files_sharing.sharecontroller.authenticate' ,
2018-02-28 19:05:55 +03:00
array ( 'token' => $token , 'redirect' => 'preview' )));
2014-10-15 13:58:44 +04:00
}
2016-02-09 15:00:08 +03:00
if ( ! $this -> validateShare ( $share )) {
throw new NotFoundException ();
}
2016-01-15 10:11:11 +03:00
// We can't get the path of a file share
2016-02-09 02:34:10 +03:00
try {
if ( $share -> getNode () instanceof \OCP\Files\File && $path !== '' ) {
$this -> emitAccessShareHook ( $share , 404 , 'Share not found' );
throw new NotFoundException ();
}
} catch ( \Exception $e ) {
$this -> emitAccessShareHook ( $share , 404 , 'Share not found' );
throw $e ;
2014-10-15 13:58:44 +04:00
}
2015-03-24 13:21:58 +03:00
$shareTmpl = [];
2016-02-03 10:25:57 +03:00
$shareTmpl [ 'displayName' ] = $this -> userManager -> get ( $share -> getShareOwner ()) -> getDisplayName ();
$shareTmpl [ 'owner' ] = $share -> getShareOwner ();
2016-01-27 22:51:26 +03:00
$shareTmpl [ 'filename' ] = $share -> getNode () -> getName ();
2016-01-15 10:11:11 +03:00
$shareTmpl [ 'directory_path' ] = $share -> getTarget ();
2016-01-27 22:51:26 +03:00
$shareTmpl [ 'mimetype' ] = $share -> getNode () -> getMimetype ();
$shareTmpl [ 'previewSupported' ] = $this -> previewManager -> isMimeSupported ( $share -> getNode () -> getMimetype ());
2016-01-15 10:11:11 +03:00
$shareTmpl [ 'dirToken' ] = $token ;
2014-10-15 13:58:44 +04:00
$shareTmpl [ 'sharingToken' ] = $token ;
2016-04-18 19:17:08 +03:00
$shareTmpl [ 'server2serversharing' ] = $this -> federatedShareProvider -> isOutgoingServer2serverShareEnabled ();
2016-01-15 10:11:11 +03:00
$shareTmpl [ 'protected' ] = $share -> getPassword () !== null ? 'true' : 'false' ;
2014-11-18 16:54:08 +03:00
$shareTmpl [ 'dir' ] = '' ;
2016-01-27 22:51:26 +03:00
$shareTmpl [ 'nonHumanFileSize' ] = $share -> getNode () -> getSize ();
$shareTmpl [ 'fileSize' ] = \OCP\Util :: humanFileSize ( $share -> getNode () -> getSize ());
2014-10-15 13:58:44 +04:00
// Show file list
2016-06-07 13:28:02 +03:00
$hideFileList = false ;
2016-01-27 22:51:26 +03:00
if ( $share -> getNode () instanceof \OCP\Files\Folder ) {
2016-07-06 00:35:32 +03:00
/** @var \OCP\Files\Folder $rootFolder */
$rootFolder = $share -> getNode ();
try {
$folderNode = $rootFolder -> get ( $path );
} catch ( \OCP\Files\NotFoundException $e ) {
$this -> emitAccessShareHook ( $share , 404 , 'Share not found' );
throw new NotFoundException ();
}
2016-07-06 00:15:41 +03:00
$shareTmpl [ 'dir' ] = $rootFolder -> getRelativePath ( $folderNode -> getPath ());
2016-01-19 12:17:29 +03:00
/*
* The OC_Util methods require a view . This just uses the node API
*/
2016-01-27 22:51:26 +03:00
$freeSpace = $share -> getNode () -> getStorage () -> free_space ( $share -> getNode () -> getInternalPath ());
2016-06-02 16:27:16 +03:00
if ( $freeSpace < \OCP\Files\FileInfo :: SPACE_UNLIMITED ) {
2016-01-19 12:17:29 +03:00
$freeSpace = max ( $freeSpace , 0 );
} else {
$freeSpace = ( INF > 0 ) ? INF : PHP_INT_MAX ; // work around https://bugs.php.net/bug.php?id=69188
}
2018-01-26 14:36:25 +03:00
$hideFileList = ! ( $share -> getPermissions () & \OCP\Constants :: PERMISSION_READ );
2016-09-19 22:29:48 +03:00
$maxUploadFilesize = $freeSpace ;
2016-01-19 12:17:29 +03:00
2014-10-15 13:58:44 +04:00
$folder = new Template ( 'files' , 'list' , '' );
2016-07-06 00:15:41 +03:00
$folder -> assign ( 'dir' , $rootFolder -> getRelativePath ( $folderNode -> getPath ()));
2016-01-15 10:11:11 +03:00
$folder -> assign ( 'dirToken' , $token );
2014-11-25 18:28:41 +03:00
$folder -> assign ( 'permissions' , \OCP\Constants :: PERMISSION_READ );
2014-10-15 13:58:44 +04:00
$folder -> assign ( 'isPublic' , true );
2016-06-07 13:28:02 +03:00
$folder -> assign ( 'hideFileList' , $hideFileList );
2014-10-15 13:58:44 +04:00
$folder -> assign ( 'publicUploadEnabled' , 'no' );
$folder -> assign ( 'uploadMaxFilesize' , $maxUploadFilesize );
2016-07-18 14:34:18 +03:00
$folder -> assign ( 'uploadMaxHumanFilesize' , \OCP\Util :: humanFileSize ( $maxUploadFilesize ));
2014-10-15 13:58:44 +04:00
$folder -> assign ( 'freeSpace' , $freeSpace );
$folder -> assign ( 'usedSpacePercent' , 0 );
$folder -> assign ( 'trash' , false );
$shareTmpl [ 'folder' ] = $folder -> fetchPage ();
}
2016-06-07 13:28:02 +03:00
$shareTmpl [ 'hideFileList' ] = $hideFileList ;
$shareTmpl [ 'shareOwner' ] = $this -> userManager -> get ( $share -> getShareOwner ()) -> getDisplayName ();
2016-07-22 17:13:26 +03:00
$shareTmpl [ 'downloadURL' ] = $this -> urlGenerator -> linkToRouteAbsolute ( 'files_sharing.sharecontroller.downloadShare' , [ 'token' => $token ]);
$shareTmpl [ 'shareUrl' ] = $this -> urlGenerator -> linkToRouteAbsolute ( 'files_sharing.sharecontroller.showShare' , [ 'token' => $token ]);
2015-01-17 14:11:52 +03:00
$shareTmpl [ 'maxSizeAnimateGif' ] = $this -> config -> getSystemValue ( 'max_filesize_animated_gifs_public_sharing' , 10 );
2015-06-09 17:33:26 +03:00
$shareTmpl [ 'previewEnabled' ] = $this -> config -> getSystemValue ( 'enable_previews' , true );
2016-05-24 13:34:37 +03:00
$shareTmpl [ 'previewMaxX' ] = $this -> config -> getSystemValue ( 'preview_max_x' , 1024 );
$shareTmpl [ 'previewMaxY' ] = $this -> config -> getSystemValue ( 'preview_max_y' , 1024 );
2016-09-08 10:13:59 +03:00
$shareTmpl [ 'disclaimer' ] = $this -> config -> getAppValue ( 'core' , 'shareapi_public_link_disclaimertext' , null );
2017-09-25 22:47:09 +03:00
$shareTmpl [ 'previewURL' ] = $shareTmpl [ 'downloadURL' ];
2017-10-31 23:00:36 +03:00
$ogPreview = '' ;
2016-07-22 17:13:26 +03:00
if ( $shareTmpl [ 'previewSupported' ]) {
2016-11-28 18:16:01 +03:00
$shareTmpl [ 'previewImage' ] = $this -> urlGenerator -> linkToRouteAbsolute ( 'files_sharing.PublicPreview.getPreview' ,
2016-07-22 17:13:26 +03:00
[ 'x' => 200 , 'y' => 200 , 'file' => $shareTmpl [ 'directory_path' ], 't' => $shareTmpl [ 'dirToken' ]]);
2017-10-31 23:00:36 +03:00
$ogPreview = $shareTmpl [ 'previewImage' ];
2017-09-25 22:47:09 +03:00
// We just have direct previews for image files
if ( $share -> getNode () -> getMimePart () === 'image' ) {
$shareTmpl [ 'previewURL' ] = $this -> urlGenerator -> linkToRouteAbsolute ( 'files_sharing.publicpreview.directLink' , [ 'token' => $token ]);
2018-02-12 12:42:18 +03:00
2017-10-31 23:00:36 +03:00
$ogPreview = $shareTmpl [ 'previewURL' ];
2018-02-12 12:42:18 +03:00
//Whatapp is kind of picky about their size requirements
if ( $this -> request -> isUserAgent ([ '/^WhatsApp/' ])) {
$ogPreview = $this -> urlGenerator -> linkToRouteAbsolute ( 'files_sharing.PublicPreview.getPreview' , [
't' => $token ,
'x' => 256 ,
'y' => 256 ,
'a' => true ,
]);
}
2017-09-25 22:47:09 +03:00
}
2016-07-22 17:13:26 +03:00
} else {
$shareTmpl [ 'previewImage' ] = $this -> urlGenerator -> getAbsoluteURL ( $this -> urlGenerator -> imagePath ( 'core' , 'favicon-fb.png' ));
2017-10-31 23:00:36 +03:00
$ogPreview = $shareTmpl [ 'previewImage' ];
2016-07-22 17:13:26 +03:00
}
2014-10-15 13:58:44 +04:00
2016-07-15 15:39:57 +03:00
// Load files we need
2016-07-18 14:34:18 +03:00
\OCP\Util :: addScript ( 'files' , 'file-upload' );
2017-03-21 18:35:31 +03:00
\OCP\Util :: addStyle ( 'files_sharing' , 'publicView' );
2016-07-18 14:34:18 +03:00
\OCP\Util :: addScript ( 'files_sharing' , 'public' );
\OCP\Util :: addScript ( 'files' , 'fileactions' );
\OCP\Util :: addScript ( 'files' , 'fileactionsmenu' );
\OCP\Util :: addScript ( 'files' , 'jquery.fileupload' );
\OCP\Util :: addScript ( 'files_sharing' , 'files_drop' );
2016-07-15 15:39:57 +03:00
if ( isset ( $shareTmpl [ 'folder' ])) {
// JS required for folders
2017-03-21 18:35:31 +03:00
\OCP\Util :: addStyle ( 'files' , 'merged' );
2016-07-18 14:34:18 +03:00
\OCP\Util :: addScript ( 'files' , 'filesummary' );
\OCP\Util :: addScript ( 'files' , 'breadcrumb' );
\OCP\Util :: addScript ( 'files' , 'fileinfomodel' );
\OCP\Util :: addScript ( 'files' , 'newfilemenu' );
\OCP\Util :: addScript ( 'files' , 'files' );
\OCP\Util :: addScript ( 'files' , 'filelist' );
\OCP\Util :: addScript ( 'files' , 'keyboardshortcuts' );
2016-07-15 15:39:57 +03:00
}
2016-07-22 17:13:26 +03:00
// OpenGraph Support: http://ogp.me/
2017-10-25 07:26:19 +03:00
\OCP\Util :: addHeader ( 'meta' , [ 'property' => " og:title " , 'content' => $shareTmpl [ 'filename' ]]);
\OCP\Util :: addHeader ( 'meta' , [ 'property' => " og:description " , 'content' => $this -> defaults -> getName () . ( $this -> defaults -> getSlogan () !== '' ? ' - ' . $this -> defaults -> getSlogan () : '' )]);
2016-07-22 17:13:26 +03:00
\OCP\Util :: addHeader ( 'meta' , [ 'property' => " og:site_name " , 'content' => $this -> defaults -> getName ()]);
\OCP\Util :: addHeader ( 'meta' , [ 'property' => " og:url " , 'content' => $shareTmpl [ 'shareUrl' ]]);
\OCP\Util :: addHeader ( 'meta' , [ 'property' => " og:type " , 'content' => " object " ]);
2017-10-31 23:00:36 +03:00
\OCP\Util :: addHeader ( 'meta' , [ 'property' => " og:image " , 'content' => $ogPreview ]);
2016-07-22 17:13:26 +03:00
2016-07-15 16:01:14 +03:00
$this -> eventDispatcher -> dispatch ( 'OCA\Files_Sharing::loadAdditionalScripts' );
2016-07-18 14:34:18 +03:00
$csp = new \OCP\AppFramework\Http\ContentSecurityPolicy ();
2015-03-10 12:06:15 +03:00
$csp -> addAllowedFrameDomain ( '\'self\'' );
2018-01-25 20:53:09 +03:00
$response = new PublicTemplateResponse ( $this -> appName , 'public' , $shareTmpl );
2018-02-09 13:34:34 +03:00
$response -> setHeaderTitle ( $shareTmpl [ 'filename' ]);
2018-01-25 20:53:09 +03:00
$response -> setHeaderDetails ( $this -> l10n -> t ( 'shared by %s' , [ $shareTmpl [ 'displayName' ]]));
$response -> setHeaderActions ([
new SimpleMenuAction ( 'download' , $this -> l10n -> t ( 'Download' ), 'icon-download-white' , $shareTmpl [ 'downloadURL' ], 0 ),
new SimpleMenuAction ( 'download' , $this -> l10n -> t ( 'Download' ), 'icon-download' , $shareTmpl [ 'downloadURL' ], 10 , $shareTmpl [ 'fileSize' ]),
new LinkMenuAction ( $this -> l10n -> t ( 'Direct link' ), 'icon-public' , $shareTmpl [ 'previewURL' ]),
new ExternalShareMenuAction ( $this -> l10n -> t ( 'Add to your Nextcloud' ), 'icon-external' , $shareTmpl [ 'owner' ], $shareTmpl [ 'displayName' ], $shareTmpl [ 'filename' ]),
]);
2015-03-10 12:06:15 +03:00
$response -> setContentSecurityPolicy ( $csp );
2016-02-09 02:34:10 +03:00
$this -> emitAccessShareHook ( $share );
2015-03-10 12:06:15 +03:00
return $response ;
2014-10-15 13:58:44 +04:00
}
/**
* @ PublicPage
* @ NoCSRFRequired
2014-11-24 17:02:49 +03:00
*
2014-10-15 13:58:44 +04:00
* @ param string $token
* @ param string $files
* @ param string $path
2015-10-08 12:21:17 +03:00
* @ param string $downloadStartSecret
2016-07-18 14:34:18 +03:00
* @ return void | \OCP\AppFramework\Http\Response
2016-06-08 16:38:11 +03:00
* @ throws NotFoundException
2014-10-15 13:58:44 +04:00
*/
2015-10-08 12:21:17 +03:00
public function downloadShare ( $token , $files = null , $path = '' , $downloadStartSecret = '' ) {
2014-10-15 13:58:44 +04:00
\OC_User :: setIncognitoMode ( true );
2016-01-15 13:49:50 +03:00
$share = $this -> shareManager -> getShareByToken ( $token );
2014-10-15 13:58:44 +04:00
2016-06-08 16:38:11 +03:00
if ( ! ( $share -> getPermissions () & \OCP\Constants :: PERMISSION_READ )) {
2016-07-18 14:34:18 +03:00
return new \OCP\AppFramework\Http\DataResponse ( 'Share is read-only' );
2016-06-08 16:38:11 +03:00
}
2014-10-15 13:58:44 +04:00
// Share is password protected - check whether the user is permitted to access the share
2016-01-15 13:49:50 +03:00
if ( $share -> getPassword () !== null && ! $this -> linkShareAuth ( $share )) {
return new RedirectResponse ( $this -> urlGenerator -> linkToRoute ( 'files_sharing.sharecontroller.authenticate' ,
2018-02-28 19:05:55 +03:00
[ 'token' => $token , 'redirect' => 'download' ]));
2014-10-15 13:58:44 +04:00
}
2015-02-17 17:08:16 +03:00
$files_list = null ;
if ( ! is_null ( $files )) { // download selected files
$files_list = json_decode ( $files );
// in case we get only a single file
if ( $files_list === null ) {
2016-01-15 13:49:50 +03:00
$files_list = [ $files ];
2015-02-17 17:08:16 +03:00
}
2017-10-30 23:06:35 +03:00
// Just in case $files is a single int like '1234'
if ( ! is_array ( $files_list )) {
$files_list = [ $files_list ];
}
2015-02-17 17:08:16 +03:00
}
2016-02-03 10:25:57 +03:00
$userFolder = $this -> rootFolder -> getUserFolder ( $share -> getShareOwner ());
2016-01-27 22:51:26 +03:00
$originalSharePath = $userFolder -> getRelativePath ( $share -> getNode () -> getPath ());
2016-01-15 13:49:50 +03:00
2016-02-09 15:00:08 +03:00
if ( ! $this -> validateShare ( $share )) {
throw new NotFoundException ();
}
2016-01-15 13:49:50 +03:00
// Single file share
2016-01-27 22:51:26 +03:00
if ( $share -> getNode () instanceof \OCP\Files\File ) {
2016-01-20 11:39:05 +03:00
// Single file download
2016-11-03 14:06:22 +03:00
$this -> singleFileDownloaded ( $share , $share -> getNode ());
2016-01-15 13:49:50 +03:00
}
// Directory share
else {
/** @var \OCP\Files\Folder $node */
2016-01-27 22:51:26 +03:00
$node = $share -> getNode ();
2016-01-15 13:49:50 +03:00
// Try to get the path
if ( $path !== '' ) {
try {
$node = $node -> get ( $path );
} catch ( NotFoundException $e ) {
2016-02-09 02:34:10 +03:00
$this -> emitAccessShareHook ( $share , 404 , 'Share not found' );
2016-01-15 13:49:50 +03:00
return new NotFoundResponse ();
}
}
2014-10-15 13:58:44 +04:00
2016-01-15 13:49:50 +03:00
$originalSharePath = $userFolder -> getRelativePath ( $node -> getPath ());
2014-10-15 13:58:44 +04:00
2016-01-15 13:49:50 +03:00
if ( $node instanceof \OCP\Files\File ) {
// Single file download
2016-11-03 14:06:22 +03:00
$this -> singleFileDownloaded ( $share , $share -> getNode ());
2015-02-17 17:08:16 +03:00
} else if ( ! empty ( $files_list )) {
2016-12-11 22:32:28 +03:00
$this -> fileListDownloaded ( $share , $files_list , $node );
2015-02-17 17:08:16 +03:00
} else {
// The folder is downloaded
2016-11-03 14:06:22 +03:00
$this -> singleFileDownloaded ( $share , $share -> getNode ());
2015-02-17 17:08:16 +03:00
}
}
2016-01-15 13:49:50 +03:00
/* FIXME: We should do this all nicely in OCP */
OC_Util :: tearDownFS ();
2016-02-03 10:25:57 +03:00
OC_Util :: setupFS ( $share -> getShareOwner ());
2016-01-15 13:49:50 +03:00
2015-10-08 12:21:17 +03:00
/**
* this sets a cookie to be able to recognize the start of the download
* the content must not be longer than 32 characters and must only contain
* alphanumeric characters
*/
if ( ! empty ( $downloadStartSecret )
&& ! isset ( $downloadStartSecret [ 32 ])
&& preg_match ( '!^[a-zA-Z0-9]+$!' , $downloadStartSecret ) === 1 ) {
// FIXME: set on the response once we use an actual app framework response
setcookie ( 'ocDownloadStarted' , $downloadStartSecret , time () + 20 , '/' );
}
2016-02-09 02:34:10 +03:00
$this -> emitAccessShareHook ( $share );
2017-05-10 15:16:22 +03:00
$server_params = array ( 'head' => $this -> request -> getMethod () === 'HEAD' );
2016-05-20 19:16:44 +03:00
/**
* Http range requests support
*/
if ( isset ( $_SERVER [ 'HTTP_RANGE' ])) {
$server_params [ 'range' ] = $this -> request -> getHeader ( 'Range' );
}
2015-02-17 17:08:16 +03:00
// download selected files
2016-03-07 13:37:49 +03:00
if ( ! is_null ( $files ) && $files !== '' ) {
2014-10-15 13:58:44 +04:00
// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
2014-11-25 12:17:31 +03:00
// after dispatching the request which results in a "Cannot modify header information" notice.
2016-05-20 19:16:44 +03:00
OC_Files :: get ( $originalSharePath , $files_list , $server_params );
2014-10-15 13:58:44 +04:00
exit ();
} else {
// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
// after dispatching the request which results in a "Cannot modify header information" notice.
2016-05-20 19:16:44 +03:00
OC_Files :: get ( dirname ( $originalSharePath ), basename ( $originalSharePath ), $server_params );
2014-10-15 13:58:44 +04:00
exit ();
}
}
2016-11-03 14:06:22 +03:00
/**
* create activity for every downloaded file
*
* @ param Share\IShare $share
* @ param array $files_list
2016-12-12 20:15:13 +03:00
* @ param \OCP\Files\Folder $node
2016-11-03 14:06:22 +03:00
*/
2016-12-11 22:32:28 +03:00
protected function fileListDownloaded ( Share\IShare $share , array $files_list , \OCP\Files\Folder $node ) {
2016-11-03 14:06:22 +03:00
foreach ( $files_list as $file ) {
2016-12-11 22:32:28 +03:00
$subNode = $node -> get ( $file );
2016-11-03 14:06:22 +03:00
$this -> singleFileDownloaded ( $share , $subNode );
}
}
/**
* create activity if a single file was downloaded from a link share
*
* @ param Share\IShare $share
*/
protected function singleFileDownloaded ( Share\IShare $share , \OCP\Files\Node $node ) {
$fileId = $node -> getId ();
$userFolder = $this -> rootFolder -> getUserFolder ( $share -> getSharedBy ());
$userNodeList = $userFolder -> getById ( $fileId );
$userNode = $userNodeList [ 0 ];
$ownerFolder = $this -> rootFolder -> getUserFolder ( $share -> getShareOwner ());
$userPath = $userFolder -> getRelativePath ( $userNode -> getPath ());
$ownerPath = $ownerFolder -> getRelativePath ( $node -> getPath ());
$parameters = [ $userPath ];
if ( $share -> getShareType () === \OCP\Share :: SHARE_TYPE_EMAIL ) {
if ( $node instanceof \OCP\Files\File ) {
2016-11-16 14:09:41 +03:00
$subject = Downloads :: SUBJECT_SHARED_FILE_BY_EMAIL_DOWNLOADED ;
2016-11-03 14:06:22 +03:00
} else {
2016-11-16 14:09:41 +03:00
$subject = Downloads :: SUBJECT_SHARED_FOLDER_BY_EMAIL_DOWNLOADED ;
2016-11-03 14:06:22 +03:00
}
$parameters [] = $share -> getSharedWith ();
} else {
if ( $node instanceof \OCP\Files\File ) {
2016-11-16 14:09:41 +03:00
$subject = Downloads :: SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED ;
2016-11-03 14:06:22 +03:00
} else {
2016-11-16 14:09:41 +03:00
$subject = Downloads :: SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED ;
2016-11-03 14:06:22 +03:00
}
}
$this -> publishActivity ( $subject , $parameters , $share -> getSharedBy (), $fileId , $userPath );
if ( $share -> getShareOwner () !== $share -> getSharedBy ()) {
$parameters [ 0 ] = $ownerPath ;
$this -> publishActivity ( $subject , $parameters , $share -> getShareOwner (), $fileId , $ownerPath );
}
}
/**
* publish activity
*
* @ param string $subject
* @ param array $parameters
* @ param string $affectedUser
* @ param int $fileId
* @ param string $filePath
*/
protected function publishActivity ( $subject ,
array $parameters ,
$affectedUser ,
$fileId ,
$filePath ) {
$event = $this -> activityManager -> generateEvent ();
$event -> setApp ( 'files_sharing' )
2016-11-16 14:09:41 +03:00
-> setType ( 'public_links' )
2016-11-03 14:06:22 +03:00
-> setSubject ( $subject , $parameters )
-> setAffectedUser ( $affectedUser )
-> setObject ( 'files' , $fileId , $filePath );
$this -> activityManager -> publish ( $event );
}
2014-10-15 13:58:44 +04:00
}