2013-10-28 23:22:06 +04:00
< ? php
2015-03-26 13:44:34 +03:00
/**
* @ author Bart Visscher < bartv @ thisnet . nl >
2016-05-26 20:56:05 +03:00
* @ author Björn Schießle < bjoern @ schiessle . org >
2015-03-26 13:44:34 +03:00
* @ author Joas Schilling < nickvergessen @ owncloud . com >
* @ author Jörn Friedrich Dreyer < jfd @ butonic . de >
2016-05-26 20:56:05 +03:00
* @ author Lukas Reschke < lukas @ statuscode . ch >
2015-03-26 13:44:34 +03:00
* @ author Morris Jobke < hey @ morrisjobke . de >
* @ author Robin Appelman < icewind @ owncloud . com >
2015-10-26 15:54:55 +03:00
* @ author Roeland Jago Douma < rullzer @ owncloud . com >
2015-03-26 13:44:34 +03:00
* @ author Vincent Petry < pvince81 @ owncloud . com >
*
2016-01-12 17:02:16 +03:00
* @ copyright Copyright ( c ) 2016 , ownCloud , Inc .
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 />
*
*/
2013-10-28 23:22:06 +04:00
namespace OCA\Files_Sharing ;
2015-12-10 16:14:54 +03:00
use OC\Files\Filesystem ;
2016-02-18 11:57:29 +03:00
use OC\Files\View ;
2015-06-15 15:10:10 +03:00
use OCP\Files\NotFoundException ;
2016-02-18 11:57:29 +03:00
use OCP\User ;
2015-06-15 15:10:10 +03:00
2013-10-28 23:22:06 +04:00
class Helper {
2014-06-25 17:20:52 +04:00
public static function registerHooks () {
2016-05-02 16:16:20 +03:00
\OCP\Util :: connectHook ( 'OC_Filesystem' , 'post_rename' , '\OCA\Files_Sharing\Updater' , 'renameHook' );
2015-03-18 17:26:04 +03:00
\OCP\Util :: connectHook ( 'OC_Filesystem' , 'post_delete' , '\OCA\Files_Sharing\Hooks' , 'unshareChildren' );
2016-05-02 16:16:20 +03:00
\OCP\Util :: connectHook ( 'OC_Appconfig' , 'post_set_value' , '\OCA\Files_Sharing\Maintainer' , 'configChangeHook' );
2014-06-25 17:20:52 +04:00
2015-01-21 02:11:15 +03:00
\OCP\Util :: connectHook ( 'OC_User' , 'post_deleteUser' , '\OCA\Files_Sharing\Hooks' , 'deleteUser' );
2014-06-25 17:20:52 +04:00
}
2013-10-28 23:22:06 +04:00
/**
* Sets up the filesystem and user for public sharing
* @ param string $token string share token
* @ param string $relativePath optional path relative to the share
* @ param string $password optional password
2015-06-15 15:10:10 +03:00
* @ return array
2013-10-28 23:22:06 +04:00
*/
public static function setupFromToken ( $token , $relativePath = null , $password = null ) {
\OC_User :: setIncognitoMode ( true );
2014-06-16 18:09:56 +04:00
$linkItem = \OCP\Share :: getShareByToken ( $token , ! $password );
2013-10-28 23:22:06 +04:00
if ( $linkItem === false || ( $linkItem [ 'item_type' ] !== 'file' && $linkItem [ 'item_type' ] !== 'folder' )) {
\OC_Response :: setStatus ( 404 );
2015-04-09 13:36:10 +03:00
\OCP\Util :: writeLog ( 'core-preview' , 'Passed token parameter is not valid' , \OCP\Util :: DEBUG );
2013-10-28 23:22:06 +04:00
exit ;
}
if ( ! isset ( $linkItem [ 'uid_owner' ]) || ! isset ( $linkItem [ 'file_source' ])) {
\OC_Response :: setStatus ( 500 );
2015-04-09 13:36:10 +03:00
\OCP\Util :: writeLog ( 'core-preview' , 'Passed token seems to be valid, but it does not contain all necessary information . ("' . $token . '")' , \OCP\Util :: WARN );
2013-10-28 23:22:06 +04:00
exit ;
}
$rootLinkItem = \OCP\Share :: resolveReShare ( $linkItem );
$path = null ;
if ( isset ( $rootLinkItem [ 'uid_owner' ])) {
\OCP\JSON :: checkUserExists ( $rootLinkItem [ 'uid_owner' ]);
\OC_Util :: tearDownFS ();
\OC_Util :: setupFS ( $rootLinkItem [ 'uid_owner' ]);
}
2015-06-15 15:10:10 +03:00
try {
2016-02-18 11:57:29 +03:00
$path = Filesystem :: getPath ( $linkItem [ 'file_source' ]);
2015-06-15 15:10:10 +03:00
} catch ( NotFoundException $e ) {
2013-10-28 23:22:06 +04:00
\OCP\Util :: writeLog ( 'share' , 'could not resolve linkItem' , \OCP\Util :: DEBUG );
\OC_Response :: setStatus ( 404 );
\OCP\JSON :: error ( array ( 'success' => false ));
exit ();
}
if ( ! isset ( $linkItem [ 'item_type' ])) {
\OCP\Util :: writeLog ( 'share' , 'No item type set for share id: ' . $linkItem [ 'id' ], \OCP\Util :: ERROR );
\OC_Response :: setStatus ( 404 );
\OCP\JSON :: error ( array ( 'success' => false ));
exit ();
}
2014-12-04 21:51:04 +03:00
if ( isset ( $linkItem [ 'share_with' ]) && ( int ) $linkItem [ 'share_type' ] === \OCP\Share :: SHARE_TYPE_LINK ) {
2013-10-28 23:22:06 +04:00
if ( ! self :: authenticate ( $linkItem , $password )) {
\OC_Response :: setStatus ( 403 );
\OCP\JSON :: error ( array ( 'success' => false ));
exit ();
}
}
$basePath = $path ;
2016-02-18 11:57:29 +03:00
if ( $relativePath !== null && Filesystem :: isReadable ( $basePath . $relativePath )) {
$path .= Filesystem :: normalizePath ( $relativePath );
2013-10-28 23:22:06 +04:00
}
return array (
'linkItem' => $linkItem ,
'basePath' => $basePath ,
'realPath' => $path
);
}
/**
* Authenticate link item with the given password
* or with the session if no password was given .
* @ param array $linkItem link item array
* @ param string $password optional password
*
2014-04-14 19:49:27 +04:00
* @ return boolean true if authorized , false otherwise
2013-10-28 23:22:06 +04:00
*/
2014-10-15 13:58:44 +04:00
public static function authenticate ( $linkItem , $password = null ) {
2013-10-28 23:22:06 +04:00
if ( $password !== null ) {
if ( $linkItem [ 'share_type' ] == \OCP\Share :: SHARE_TYPE_LINK ) {
// Check Password
2014-11-17 15:10:15 +03:00
$newHash = '' ;
if ( \OC :: $server -> getHasher () -> verify ( $password , $linkItem [ 'share_with' ], $newHash )) {
2013-10-28 23:22:06 +04:00
// Save item id in session for future requests
2016-05-31 07:53:28 +03:00
\OC :: $server -> getSession () -> set ( 'public_link_authenticated' , ( string ) $linkItem [ 'id' ]);
2014-11-17 15:10:15 +03:00
/**
* FIXME : Migrate old hashes to new hash format
* Due to the fact that there is no reasonable functionality to update the password
* of an existing share no migration is yet performed there .
* The only possibility is to update the existing share which will result in a new
* share ID and is a major hack .
*
* In the future the migration should be performed once there is a proper method
* to update the share ' s password . ( for example `$share->updatePassword($password)`
*
* @ link https :// github . com / owncloud / core / issues / 10671
*/
if ( ! empty ( $newHash )) {
}
} else {
return false ;
2013-10-28 23:22:06 +04:00
}
} else {
\OCP\Util :: writeLog ( 'share' , 'Unknown share type ' . $linkItem [ 'share_type' ]
. ' for share id ' . $linkItem [ 'id' ], \OCP\Util :: ERROR );
return false ;
}
}
else {
// not authenticated ?
2014-07-16 21:40:22 +04:00
if ( ! \OC :: $server -> getSession () -> exists ( 'public_link_authenticated' )
2016-05-31 07:53:28 +03:00
|| \OC :: $server -> getSession () -> get ( 'public_link_authenticated' ) !== ( string ) $linkItem [ 'id' ]) {
2013-10-28 23:22:06 +04:00
return false ;
}
}
return true ;
}
2014-04-14 19:08:46 +04:00
public static function getSharesFromItem ( $target ) {
$result = array ();
2016-02-18 11:57:29 +03:00
$owner = Filesystem :: getOwner ( $target );
Filesystem :: initMountPoints ( $owner );
$info = Filesystem :: getFileInfo ( $target );
$ownerView = new View ( '/' . $owner . '/files' );
if ( $owner != User :: getUser () ) {
2014-04-14 19:08:46 +04:00
$path = $ownerView -> getPath ( $info [ 'fileid' ]);
} else {
$path = $target ;
}
$ids = array ();
2014-05-07 19:37:49 +04:00
while ( $path !== dirname ( $path )) {
2014-04-14 19:08:46 +04:00
$info = $ownerView -> getFileInfo ( $path );
2014-05-07 13:47:52 +04:00
if ( $info instanceof \OC\Files\FileInfo ) {
$ids [] = $info [ 'fileid' ];
} else {
\OCP\Util :: writeLog ( 'sharing' , 'No fileinfo available for: ' . $path , \OCP\Util :: WARN );
}
2014-04-14 19:08:46 +04:00
$path = dirname ( $path );
}
if ( ! empty ( $ids )) {
$idList = array_chunk ( $ids , 99 , true );
foreach ( $idList as $subList ) {
$statement = " SELECT `share_with`, `share_type`, `file_target` FROM `*PREFIX*share` WHERE `file_source` IN ( " . implode ( ',' , $subList ) . " ) AND `share_type` IN (0, 1, 2) " ;
$query = \OCP\DB :: prepare ( $statement );
$r = $query -> execute ();
$result = array_merge ( $result , $r -> fetchAll ());
}
}
return $result ;
}
2014-04-16 18:41:23 +04:00
2016-02-18 11:57:29 +03:00
/**
* get the UID of the owner of the file and the path to the file relative to
* owners files folder
*
* @ param $filename
* @ return array
* @ throws \OC\User\NoUserException
*/
2014-04-16 18:41:23 +04:00
public static function getUidAndFilename ( $filename ) {
2016-02-18 11:57:29 +03:00
$uid = Filesystem :: getOwner ( $filename );
$userManager = \OC :: $server -> getUserManager ();
// if the user with the UID doesn't exists, e.g. because the UID points
// to a remote user with a federated cloud ID we use the current logged-in
// user. We need a valid local user to create the share
if ( ! $userManager -> userExists ( $uid )) {
$uid = User :: getUser ();
}
Filesystem :: initMountPoints ( $uid );
if ( $uid != User :: getUser () ) {
$info = Filesystem :: getFileInfo ( $filename );
$ownerView = new View ( '/' . $uid . '/files' );
try {
$filename = $ownerView -> getPath ( $info [ 'fileid' ]);
} catch ( NotFoundException $e ) {
$filename = null ;
}
}
return [ $uid , $filename ];
2014-04-16 18:41:23 +04:00
}
/**
2014-05-19 19:50:53 +04:00
* Format a path to be relative to the / user / files / directory
2014-04-16 18:41:23 +04:00
* @ param string $path the absolute path
* @ return string e . g . turns '/admin/files/test.txt' into 'test.txt'
*/
public static function stripUserFilesPath ( $path ) {
$trimmed = ltrim ( $path , '/' );
$split = explode ( '/' , $trimmed );
// it is not a file relative to data/user/files
if ( count ( $split ) < 3 || $split [ 1 ] !== 'files' ) {
return false ;
}
$sliced = array_slice ( $split , 2 );
$relPath = implode ( '/' , $sliced );
return $relPath ;
}
2014-04-30 18:56:09 +04:00
/**
* check if file name already exists and generate unique target
*
* @ param string $path
* @ param array $excludeList
2016-02-18 11:57:29 +03:00
* @ param View $view
2014-04-30 18:56:09 +04:00
* @ return string $path
*/
public static function generateUniqueTarget ( $path , $excludeList , $view ) {
$pathinfo = pathinfo ( $path );
$ext = ( isset ( $pathinfo [ 'extension' ])) ? '.' . $pathinfo [ 'extension' ] : '' ;
$name = $pathinfo [ 'filename' ];
$dir = $pathinfo [ 'dirname' ];
$i = 2 ;
while ( $view -> file_exists ( $path ) || in_array ( $path , $excludeList )) {
2016-02-18 11:57:29 +03:00
$path = Filesystem :: normalizePath ( $dir . '/' . $name . ' (' . $i . ')' . $ext );
2014-04-30 18:56:09 +04:00
$i ++ ;
}
return $path ;
}
2014-06-12 21:49:52 +04:00
2014-08-13 14:55:14 +04:00
/**
* get default share folder
*
* @ return string
*/
public static function getShareFolder () {
2014-12-17 13:12:37 +03:00
$shareFolder = \OC :: $server -> getConfig () -> getSystemValue ( 'share_folder' , '/' );
2016-02-18 11:57:29 +03:00
$shareFolder = Filesystem :: normalizePath ( $shareFolder );
2015-03-26 23:56:44 +03:00
2016-02-18 11:57:29 +03:00
if ( ! Filesystem :: file_exists ( $shareFolder )) {
2015-03-26 23:56:44 +03:00
$dir = '' ;
$subdirs = explode ( '/' , $shareFolder );
foreach ( $subdirs as $subdir ) {
$dir = $dir . '/' . $subdir ;
2016-02-18 11:57:29 +03:00
if ( ! Filesystem :: is_dir ( $dir )) {
Filesystem :: mkdir ( $dir );
2015-03-26 23:56:44 +03:00
}
}
}
return $shareFolder ;
2014-08-13 14:55:14 +04:00
}
/**
* set default share folder
*
* @ param string $shareFolder
*/
public static function setShareFolder ( $shareFolder ) {
2014-12-17 13:12:37 +03:00
\OC :: $server -> getConfig () -> setSystemValue ( 'share_folder' , $shareFolder );
2014-08-13 14:55:14 +04:00
}
2013-10-28 23:22:06 +04:00
}