2012-09-07 12:09:41 +00:00
< ? php
/**
* ownCloud
*
* @ author Michael Gapczynski
* @ copyright 2012 Michael Gapczynski mtgap @ owncloud . com
2014-03-18 20:15:11 +00:00
* @ copyright 2014 Vincent Petry < pvince81 @ owncloud . com >
2014-03-21 14:22:48 +00:00
* @ copyright 2014 Robin McCorkell < rmccorkell @ karoshi . org . uk >
2012-09-07 12:09:41 +00:00
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation ; either
* version 3 of the License , or any later version .
*
* This library 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 along with this library . If not , see < http :// www . gnu . org / licenses />.
*/
/**
2014-03-19 11:20:48 +00:00
* Class to configure mount . json globally and for users
2014-03-18 20:15:11 +00:00
*/
2012-09-07 12:09:41 +00:00
class OC_Mount_Config {
2014-03-19 11:20:48 +00:00
// TODO: make this class non-static and give it a proper namespace
2012-09-07 12:09:41 +00:00
const MOUNT_TYPE_GLOBAL = 'global' ;
const MOUNT_TYPE_GROUP = 'group' ;
const MOUNT_TYPE_USER = 'user' ;
2014-05-09 19:59:56 +00:00
const MOUNT_TYPE_PERSONAL = 'personal' ;
2012-09-07 12:09:41 +00:00
2014-03-18 17:29:08 +00:00
// whether to skip backend test (for unit tests, as this static class is not mockable)
public static $skipTest = false ;
2013-03-08 17:15:20 +00:00
private static $backends = array ();
2014-04-07 18:18:57 +00:00
/**
* @ param string $class
* @ param array $definition
* @ return bool
*/
2013-03-08 17:15:20 +00:00
public static function registerBackend ( $class , $definition ) {
if ( ! isset ( $definition [ 'backend' ])) {
return false ;
}
OC_Mount_Config :: $backends [ $class ] = $definition ;
return true ;
}
2014-04-07 18:18:57 +00:00
/**
* Setup backends
*
* @ return array of previously registered backends
*/
public static function setUp ( $backends = array ()) {
$backup = self :: $backends ;
self :: $backends = $backends ;
return $backup ;
}
2012-09-07 12:09:41 +00:00
/**
* Get details on each of the external storage backends , used for the mount config UI
* If a custom UI is needed , add the key 'custom' and a javascript file with that name will be loaded
* If the configuration parameter should be secret , add a '*' to the beginning of the value
* If the configuration parameter is a boolean , add a '!' to the beginning of the value
* If the configuration parameter is optional , add a '&' to the beginning of the value
2013-04-18 20:20:52 +00:00
* If the configuration parameter is hidden , add a '#' to the beginning of the value
2014-04-07 18:18:57 +00:00
* @ return array
2012-09-07 12:09:41 +00:00
*/
public static function getBackends () {
2013-03-08 17:15:20 +00:00
$sortFunc = function ( $a , $b ) {
return strcasecmp ( $a [ 'backend' ], $b [ 'backend' ]);
};
2014-04-07 18:18:57 +00:00
$backEnds = array ();
2013-03-08 17:15:20 +00:00
foreach ( OC_Mount_Config :: $backends as $class => $backend ) {
if ( isset ( $backend [ 'has_dependencies' ]) and $backend [ 'has_dependencies' ] === true ) {
2013-05-25 15:10:20 +00:00
if ( ! method_exists ( $class , 'checkDependencies' )) {
2014-04-07 18:18:57 +00:00
\OCP\Util :: writeLog ( 'files_external' ,
" Backend class $class has dependencies but doesn't provide method checkDependencies() " ,
\OCP\Util :: DEBUG );
2013-05-25 15:10:20 +00:00
continue ;
} elseif ( $class :: checkDependencies () !== true ) {
2013-03-08 17:15:20 +00:00
continue ;
}
2013-08-15 10:00:02 +00:00
}
2014-04-07 18:18:57 +00:00
$backEnds [ $class ] = $backend ;
2013-08-15 10:00:02 +00:00
}
2013-02-22 16:21:57 +00:00
2014-04-07 18:18:57 +00:00
uasort ( $backEnds , $sortFunc );
2013-04-12 13:51:58 +00:00
2014-04-07 18:18:57 +00:00
return $backEnds ;
2012-09-07 12:09:41 +00:00
}
2014-03-19 11:20:48 +00:00
/**
2014-03-19 13:23:36 +00:00
* Hook that mounts the given user ' s visible mount points
2014-03-19 11:20:48 +00:00
* @ param array $data
*/
public static function initMountPointsHook ( $data ) {
2014-03-19 13:23:36 +00:00
$mountPoints = self :: getAbsoluteMountPoints ( $data [ 'user' ]);
2014-05-21 23:40:42 +00:00
$loader = \OC\Files\Filesystem :: getLoader ();
$manager = \OC\Files\Filesystem :: getMountManager ();
2014-03-20 11:52:09 +00:00
foreach ( $mountPoints as $mountPoint => $options ) {
2014-06-24 12:36:57 +00:00
if ( isset ( $options [ 'options' ][ 'objectstore' ])) {
$objectClass = $options [ 'options' ][ 'objectstore' ][ 'class' ];
$options [ 'options' ][ 'objectstore' ] = new $objectClass ( $options [ 'options' ][ 'objectstore' ]);
}
2014-07-01 11:32:57 +00:00
if ( isset ( $options [ 'personal' ]) && $options [ 'personal' ]) {
2014-05-21 23:40:42 +00:00
$mount = new \OCA\Files_External\PersonalMount ( $options [ 'class' ], $mountPoint , $options [ 'options' ], $loader );
} else {
$mount = new \OC\Files\Mount\Mount ( $options [ 'class' ], $mountPoint , $options [ 'options' ], $loader );
}
$manager -> addMount ( $mount );
2014-03-19 13:23:36 +00:00
}
2014-09-29 11:46:27 +00:00
if ( $data [ 'user' ]) {
$user = \OC :: $server -> getUserManager () -> get ( $data [ 'user' ]);
$userView = new \OC\Files\View ( '/' . $user -> getUID () . '/files' );
$changePropagator = new \OC\Files\Cache\ChangePropagator ( $userView );
$etagPropagator = new \OCA\Files_External\EtagPropagator ( $user , $changePropagator , \OC :: $server -> getConfig ());
$etagPropagator -> propagateDirtyMountPoints ();
\OCP\Util :: connectHook (
\OC\Files\Filesystem :: CLASSNAME ,
\OC\Files\Filesystem :: signal_create_mount ,
$etagPropagator , 'updateHook' );
\OCP\Util :: connectHook (
\OC\Files\Filesystem :: CLASSNAME ,
\OC\Files\Filesystem :: signal_delete_mount ,
$etagPropagator , 'updateHook' );
}
2014-03-19 13:23:36 +00:00
}
/**
* Returns the mount points for the given user .
* The mount point is relative to the data directory .
*
* @ param string $user user
* @ return array of mount point string as key , mountpoint config as value
*/
public static function getAbsoluteMountPoints ( $user ) {
2014-03-21 14:22:48 +00:00
$mountPoints = array ();
2014-03-19 11:20:48 +00:00
$datadir = \OC_Config :: getValue ( " datadirectory " , \OC :: $SERVERROOT . " /data " );
$mount_file = \OC_Config :: getValue ( " mount_file " , $datadir . " /mount.json " );
2014-03-28 14:24:38 +00:00
$backends = self :: getBackends ();
2014-03-19 11:20:48 +00:00
//move config file to it's new position
if ( is_file ( \OC :: $SERVERROOT . '/config/mount.json' )) {
rename ( \OC :: $SERVERROOT . '/config/mount.json' , $mount_file );
}
// Load system mount points
2014-04-21 20:41:45 +00:00
$mountConfig = self :: readData ();
2014-05-09 19:59:56 +00:00
// Global mount points (is this redundant?)
2014-03-19 11:20:48 +00:00
if ( isset ( $mountConfig [ self :: MOUNT_TYPE_GLOBAL ])) {
foreach ( $mountConfig [ self :: MOUNT_TYPE_GLOBAL ] as $mountPoint => $options ) {
2014-05-21 23:40:42 +00:00
$options [ 'personal' ] = false ;
2014-03-19 11:20:48 +00:00
$options [ 'options' ] = self :: decryptPasswords ( $options [ 'options' ]);
2014-03-28 14:24:38 +00:00
if ( ! isset ( $options [ 'priority' ])) {
$options [ 'priority' ] = $backends [ $options [ 'class' ]][ 'priority' ];
}
2014-05-21 21:29:16 +00:00
// Override if priority greater
2014-03-28 14:24:38 +00:00
if ( ( ! isset ( $mountPoints [ $mountPoint ]))
|| ( $options [ 'priority' ] >= $mountPoints [ $mountPoint ][ 'priority' ]) ) {
2014-05-09 19:59:56 +00:00
$options [ 'priority_type' ] = self :: MOUNT_TYPE_GLOBAL ;
2014-06-30 10:33:11 +00:00
$options [ 'backend' ] = $backends [ $options [ 'class' ]][ 'backend' ];
2014-03-28 14:24:38 +00:00
$mountPoints [ $mountPoint ] = $options ;
}
2014-03-19 11:20:48 +00:00
}
}
2014-05-09 19:59:56 +00:00
// All user mount points
2014-03-28 15:22:35 +00:00
if ( isset ( $mountConfig [ self :: MOUNT_TYPE_USER ]) && isset ( $mountConfig [ self :: MOUNT_TYPE_USER ][ 'all' ])) {
$mounts = $mountConfig [ self :: MOUNT_TYPE_USER ][ 'all' ];
foreach ( $mounts as $mountPoint => $options ) {
$mountPoint = self :: setUserVars ( $user , $mountPoint );
foreach ( $options as & $option ) {
$option = self :: setUserVars ( $user , $option );
}
2014-08-29 08:08:46 +00:00
$options [ 'personal' ] = false ;
2014-03-28 15:22:35 +00:00
$options [ 'options' ] = self :: decryptPasswords ( $options [ 'options' ]);
if ( ! isset ( $options [ 'priority' ])) {
$options [ 'priority' ] = $backends [ $options [ 'class' ]][ 'priority' ];
}
2014-05-21 21:29:16 +00:00
// Override if priority greater
2014-03-28 15:22:35 +00:00
if ( ( ! isset ( $mountPoints [ $mountPoint ]))
2014-05-09 19:59:56 +00:00
|| ( $options [ 'priority' ] >= $mountPoints [ $mountPoint ][ 'priority' ]) ) {
$options [ 'priority_type' ] = self :: MOUNT_TYPE_GLOBAL ;
2014-06-30 10:33:11 +00:00
$options [ 'backend' ] = $backends [ $options [ 'class' ]][ 'backend' ];
2014-03-28 15:22:35 +00:00
$mountPoints [ $mountPoint ] = $options ;
}
}
}
2014-05-09 19:59:56 +00:00
// Group mount points
2014-03-19 11:20:48 +00:00
if ( isset ( $mountConfig [ self :: MOUNT_TYPE_GROUP ])) {
foreach ( $mountConfig [ self :: MOUNT_TYPE_GROUP ] as $group => $mounts ) {
if ( \OC_Group :: inGroup ( $user , $group )) {
foreach ( $mounts as $mountPoint => $options ) {
$mountPoint = self :: setUserVars ( $user , $mountPoint );
foreach ( $options as & $option ) {
$option = self :: setUserVars ( $user , $option );
}
2014-05-21 23:40:42 +00:00
$options [ 'personal' ] = false ;
2014-03-19 11:20:48 +00:00
$options [ 'options' ] = self :: decryptPasswords ( $options [ 'options' ]);
2014-03-28 14:24:38 +00:00
if ( ! isset ( $options [ 'priority' ])) {
$options [ 'priority' ] = $backends [ $options [ 'class' ]][ 'priority' ];
}
2014-05-21 21:29:16 +00:00
// Override if priority greater or if priority type different
2014-03-28 14:24:38 +00:00
if ( ( ! isset ( $mountPoints [ $mountPoint ]))
|| ( $options [ 'priority' ] >= $mountPoints [ $mountPoint ][ 'priority' ])
2014-05-09 19:59:56 +00:00
|| ( $mountPoints [ $mountPoint ][ 'priority_type' ] !== self :: MOUNT_TYPE_GROUP ) ) {
$options [ 'priority_type' ] = self :: MOUNT_TYPE_GROUP ;
2014-06-30 10:33:11 +00:00
$options [ 'backend' ] = $backends [ $options [ 'class' ]][ 'backend' ];
2014-03-28 14:24:38 +00:00
$mountPoints [ $mountPoint ] = $options ;
}
2014-03-19 11:20:48 +00:00
}
}
}
}
2014-05-09 19:59:56 +00:00
// User mount points
2014-03-19 11:20:48 +00:00
if ( isset ( $mountConfig [ self :: MOUNT_TYPE_USER ])) {
foreach ( $mountConfig [ self :: MOUNT_TYPE_USER ] as $mountUser => $mounts ) {
2014-03-28 15:22:35 +00:00
if ( strtolower ( $mountUser ) === strtolower ( $user )) {
2014-03-19 11:20:48 +00:00
foreach ( $mounts as $mountPoint => $options ) {
$mountPoint = self :: setUserVars ( $user , $mountPoint );
foreach ( $options as & $option ) {
$option = self :: setUserVars ( $user , $option );
}
2014-05-21 23:40:42 +00:00
$options [ 'personal' ] = false ;
2014-03-19 11:20:48 +00:00
$options [ 'options' ] = self :: decryptPasswords ( $options [ 'options' ]);
2014-03-28 14:24:38 +00:00
if ( ! isset ( $options [ 'priority' ])) {
$options [ 'priority' ] = $backends [ $options [ 'class' ]][ 'priority' ];
}
2014-05-21 21:29:16 +00:00
// Override if priority greater or if priority type different
2014-03-28 14:24:38 +00:00
if ( ( ! isset ( $mountPoints [ $mountPoint ]))
|| ( $options [ 'priority' ] >= $mountPoints [ $mountPoint ][ 'priority' ])
2014-05-09 19:59:56 +00:00
|| ( $mountPoints [ $mountPoint ][ 'priority_type' ] !== self :: MOUNT_TYPE_USER ) ) {
$options [ 'priority_type' ] = self :: MOUNT_TYPE_USER ;
2014-06-30 10:33:11 +00:00
$options [ 'backend' ] = $backends [ $options [ 'class' ]][ 'backend' ];
2014-03-28 14:24:38 +00:00
$mountPoints [ $mountPoint ] = $options ;
}
2014-03-19 11:20:48 +00:00
}
}
}
}
2014-08-01 15:15:46 +00:00
$personalBackends = self :: getPersonalBackends ();
2014-03-19 11:20:48 +00:00
// Load personal mount points
2014-04-21 20:41:45 +00:00
$mountConfig = self :: readData ( $user );
2014-03-19 11:20:48 +00:00
if ( isset ( $mountConfig [ self :: MOUNT_TYPE_USER ][ $user ])) {
foreach ( $mountConfig [ self :: MOUNT_TYPE_USER ][ $user ] as $mountPoint => $options ) {
2014-08-01 15:15:46 +00:00
if ( isset ( $personalBackends [ $options [ 'class' ]])) {
$options [ 'personal' ] = true ;
$options [ 'options' ] = self :: decryptPasswords ( $options [ 'options' ]);
2014-03-28 14:24:38 +00:00
2014-08-01 15:15:46 +00:00
// Always override previous config
$options [ 'priority_type' ] = self :: MOUNT_TYPE_PERSONAL ;
$options [ 'backend' ] = $backends [ $options [ 'class' ]][ 'backend' ];
$mountPoints [ $mountPoint ] = $options ;
}
2014-03-19 11:20:48 +00:00
}
}
2014-03-19 13:23:36 +00:00
return $mountPoints ;
2014-03-19 11:20:48 +00:00
}
/**
* fill in the correct values for $user
*
* @ param string $user
* @ param string $input
* @ return string
*/
private static function setUserVars ( $user , $input ) {
return str_replace ( '$user' , $user , $input );
}
2014-02-18 15:36:02 +00:00
/**
* Get details on each of the external storage backends , used for the mount config UI
* Some backends are not available as a personal backend , f . e . Local and such that have
* been disabled by the admin .
*
* If a custom UI is needed , add the key 'custom' and a javascript file with that name will be loaded
* If the configuration parameter should be secret , add a '*' to the beginning of the value
* If the configuration parameter is a boolean , add a '!' to the beginning of the value
* If the configuration parameter is optional , add a '&' to the beginning of the value
* If the configuration parameter is hidden , add a '#' to the beginning of the value
* @ return array
*/
public static function getPersonalBackends () {
2014-04-13 09:01:50 +00:00
// Check whether the user has permissions to add personal storage backends
// return an empty array if this is not the case
if ( OCP\Config :: getAppValue ( 'files_external' , 'allow_user_mounting' , 'yes' ) !== 'yes' ) {
return array ();
}
2014-04-07 18:18:57 +00:00
$backEnds = self :: getBackends ();
2014-02-18 15:36:02 +00:00
// Remove local storage and other disabled storages
2014-04-07 18:18:57 +00:00
unset ( $backEnds [ '\OC\Files\Storage\Local' ]);
2014-02-18 15:36:02 +00:00
2014-04-07 18:18:57 +00:00
$allowedBackEnds = explode ( ',' , OCP\Config :: getAppValue ( 'files_external' , 'user_mounting_backends' , '' ));
foreach ( $backEnds as $backend => $null ) {
if ( ! in_array ( $backend , $allowedBackEnds )) {
unset ( $backEnds [ $backend ]);
2014-02-18 15:36:02 +00:00
}
}
2014-04-07 18:18:57 +00:00
return $backEnds ;
2014-02-18 15:36:02 +00:00
}
2012-09-07 12:09:41 +00:00
/**
* Get the system mount points
* The returned array is not in the same format as getUserMountPoints ()
* @ return array
*/
public static function getSystemMountPoints () {
2014-04-21 20:41:45 +00:00
$mountPoints = self :: readData ();
2012-09-07 12:09:41 +00:00
$backends = self :: getBackends ();
$system = array ();
if ( isset ( $mountPoints [ self :: MOUNT_TYPE_GROUP ])) {
foreach ( $mountPoints [ self :: MOUNT_TYPE_GROUP ] as $group => $mounts ) {
foreach ( $mounts as $mountPoint => $mount ) {
2013-01-03 17:07:04 +00:00
// Update old classes to new namespace
if ( strpos ( $mount [ 'class' ], 'OC_Filestorage_' ) !== false ) {
2013-01-03 17:13:45 +00:00
$mount [ 'class' ] = '\OC\Files\Storage\\' . substr ( $mount [ 'class' ], 15 );
2013-01-03 17:07:04 +00:00
}
2014-03-18 20:15:11 +00:00
$mount [ 'options' ] = self :: decryptPasswords ( $mount [ 'options' ]);
2014-03-28 14:24:38 +00:00
if ( ! isset ( $mount [ 'priority' ])) {
$mount [ 'priority' ] = $backends [ $mount [ 'class' ]][ 'priority' ];
}
2012-09-07 12:09:41 +00:00
// Remove '/$user/files/' from mount point
$mountPoint = substr ( $mountPoint , 13 );
2014-03-26 11:10:17 +00:00
$config = array (
'class' => $mount [ 'class' ],
'mountpoint' => $mountPoint ,
'backend' => $backends [ $mount [ 'class' ]][ 'backend' ],
2014-03-28 14:24:38 +00:00
'priority' => $mount [ 'priority' ],
2014-03-26 11:10:17 +00:00
'options' => $mount [ 'options' ],
'applicable' => array ( 'groups' => array ( $group ), 'users' => array ()),
2014-03-26 11:04:13 +00:00
'status' => self :: getBackendStatus ( $mount [ 'class' ], $mount [ 'options' ], false )
2014-03-26 11:10:17 +00:00
);
$hash = self :: makeConfigHash ( $config );
// If an existing config exists (with same class, mountpoint and options)
if ( isset ( $system [ $hash ])) {
// add the groups into that config
$system [ $hash ][ 'applicable' ][ 'groups' ]
= array_merge ( $system [ $hash ][ 'applicable' ][ 'groups' ], array ( $group ));
2012-09-07 12:09:41 +00:00
} else {
2014-03-26 11:10:17 +00:00
$system [ $hash ] = $config ;
2012-09-07 12:09:41 +00:00
}
}
}
}
if ( isset ( $mountPoints [ self :: MOUNT_TYPE_USER ])) {
foreach ( $mountPoints [ self :: MOUNT_TYPE_USER ] as $user => $mounts ) {
foreach ( $mounts as $mountPoint => $mount ) {
2013-01-03 17:07:04 +00:00
// Update old classes to new namespace
if ( strpos ( $mount [ 'class' ], 'OC_Filestorage_' ) !== false ) {
2013-01-03 17:13:45 +00:00
$mount [ 'class' ] = '\OC\Files\Storage\\' . substr ( $mount [ 'class' ], 15 );
2013-01-03 17:07:04 +00:00
}
2014-03-18 20:15:11 +00:00
$mount [ 'options' ] = self :: decryptPasswords ( $mount [ 'options' ]);
2014-03-28 14:24:38 +00:00
if ( ! isset ( $mount [ 'priority' ])) {
$mount [ 'priority' ] = $backends [ $mount [ 'class' ]][ 'priority' ];
}
2012-09-07 12:09:41 +00:00
// Remove '/$user/files/' from mount point
$mountPoint = substr ( $mountPoint , 13 );
2014-03-26 11:10:17 +00:00
$config = array (
'class' => $mount [ 'class' ],
'mountpoint' => $mountPoint ,
'backend' => $backends [ $mount [ 'class' ]][ 'backend' ],
2014-03-28 14:24:38 +00:00
'priority' => $mount [ 'priority' ],
2014-03-26 11:10:17 +00:00
'options' => $mount [ 'options' ],
'applicable' => array ( 'groups' => array (), 'users' => array ( $user )),
2014-03-26 11:22:47 +00:00
'status' => self :: getBackendStatus ( $mount [ 'class' ], $mount [ 'options' ], false )
2014-03-26 11:10:17 +00:00
);
$hash = self :: makeConfigHash ( $config );
// If an existing config exists (with same class, mountpoint and options)
if ( isset ( $system [ $hash ])) {
// add the users into that config
$system [ $hash ][ 'applicable' ][ 'users' ]
= array_merge ( $system [ $hash ][ 'applicable' ][ 'users' ], array ( $user ));
2012-09-07 12:09:41 +00:00
} else {
2014-03-26 11:10:17 +00:00
$system [ $hash ] = $config ;
2012-09-07 12:09:41 +00:00
}
}
}
}
2014-03-26 11:10:17 +00:00
return array_values ( $system );
2012-09-07 12:09:41 +00:00
}
/**
* Get the personal mount points of the current user
* The returned array is not in the same format as getUserMountPoints ()
* @ return array
*/
public static function getPersonalMountPoints () {
2014-04-21 20:41:45 +00:00
$mountPoints = self :: readData ( OCP\User :: getUser ());
2014-04-07 18:18:57 +00:00
$backEnds = self :: getBackends ();
2012-09-07 12:09:41 +00:00
$uid = OCP\User :: getUser ();
$personal = array ();
if ( isset ( $mountPoints [ self :: MOUNT_TYPE_USER ][ $uid ])) {
foreach ( $mountPoints [ self :: MOUNT_TYPE_USER ][ $uid ] as $mountPoint => $mount ) {
2013-01-03 17:07:04 +00:00
// Update old classes to new namespace
if ( strpos ( $mount [ 'class' ], 'OC_Filestorage_' ) !== false ) {
2013-01-03 17:13:45 +00:00
$mount [ 'class' ] = '\OC\Files\Storage\\' . substr ( $mount [ 'class' ], 15 );
2013-01-03 17:07:04 +00:00
}
2014-03-18 20:15:11 +00:00
$mount [ 'options' ] = self :: decryptPasswords ( $mount [ 'options' ]);
2014-03-26 11:10:17 +00:00
$personal [] = array (
2012-12-24 18:45:52 +00:00
'class' => $mount [ 'class' ],
2014-03-26 11:10:17 +00:00
// Remove '/uid/files/' from mount point
'mountpoint' => substr ( $mountPoint , strlen ( $uid ) + 8 ),
2014-04-07 18:18:57 +00:00
'backend' => $backEnds [ $mount [ 'class' ]][ 'backend' ],
2014-03-26 11:10:17 +00:00
'options' => $mount [ 'options' ],
2014-03-26 11:04:13 +00:00
'status' => self :: getBackendStatus ( $mount [ 'class' ], $mount [ 'options' ], true )
2012-12-24 18:45:52 +00:00
);
2012-09-07 12:09:41 +00:00
}
}
return $personal ;
}
2014-03-19 11:20:48 +00:00
/**
* Test connecting using the given backend configuration
* @ param string $class backend class name
* @ param array $options backend configuration options
* @ return bool true if the connection succeeded , false otherwise
*/
2014-03-26 11:04:13 +00:00
private static function getBackendStatus ( $class , $options , $isPersonal ) {
2014-03-18 17:29:08 +00:00
if ( self :: $skipTest ) {
return true ;
}
2012-12-24 18:45:52 +00:00
foreach ( $options as & $option ) {
2014-03-19 11:20:48 +00:00
$option = self :: setUserVars ( OCP\User :: getUser (), $option );
2012-12-24 18:45:52 +00:00
}
if ( class_exists ( $class )) {
try {
2012-12-28 17:00:48 +00:00
$storage = new $class ( $options );
2014-03-26 11:04:13 +00:00
return $storage -> test ( $isPersonal );
2012-12-24 18:45:52 +00:00
} catch ( Exception $exception ) {
2013-12-02 15:55:43 +00:00
\OCP\Util :: logException ( 'files_external' , $exception );
2012-12-24 18:45:52 +00:00
return false ;
}
}
return false ;
}
2012-09-07 12:09:41 +00:00
/**
* Add a mount point to the filesystem
2014-02-08 10:47:55 +00:00
* @ param string $mountPoint Mount point
* @ param string $class Backend class
2014-05-15 12:19:32 +00:00
* @ param array $classOptions Backend parameters for the class
2014-02-08 10:47:55 +00:00
* @ param string $mountType MOUNT_TYPE_GROUP | MOUNT_TYPE_USER
* @ param string $applicable User or group to apply mount to
2014-05-15 12:19:32 +00:00
* @ param bool $isPersonal Personal or system mount point i . e . is this being called from the personal or admin page
2014-05-14 19:32:19 +00:00
* @ param int | null $priority Mount point priority , null for default
2014-02-08 10:47:55 +00:00
* @ return boolean
2012-09-07 12:09:41 +00:00
*/
2012-11-30 15:27:11 +00:00
public static function addMountPoint ( $mountPoint ,
$class ,
$classOptions ,
$mountType ,
$applicable ,
2014-05-14 19:32:19 +00:00
$isPersonal = false ,
$priority = null ) {
2014-02-19 18:08:28 +00:00
$backends = self :: getBackends ();
2013-11-21 16:21:51 +00:00
$mountPoint = OC\Files\Filesystem :: normalizePath ( $mountPoint );
2014-09-28 14:32:27 +00:00
$relMountPoint = $mountPoint ;
2014-04-14 08:15:43 +00:00
if ( $mountPoint === '' || $mountPoint === '/' ) {
// can't mount at root folder
2013-11-21 16:21:51 +00:00
return false ;
}
2014-02-19 18:08:28 +00:00
if ( ! isset ( $backends [ $class ])) {
// invalid backend
return false ;
2014-02-18 15:36:02 +00:00
}
2012-09-07 12:09:41 +00:00
if ( $isPersonal ) {
// Verify that the mount point applies for the current user
2014-02-18 15:36:02 +00:00
// Prevent non-admin users from mounting local storage and other disabled backends
$allowed_backends = self :: getPersonalBackends ();
2014-03-18 16:54:14 +00:00
if ( $applicable != OCP\User :: getUser () || ! isset ( $allowed_backends [ $class ])) {
2012-09-07 12:09:41 +00:00
return false ;
}
$mountPoint = '/' . $applicable . '/files/' . ltrim ( $mountPoint , '/' );
} else {
$mountPoint = '/$user/files/' . ltrim ( $mountPoint , '/' );
}
2014-03-18 20:15:11 +00:00
$mount = array ( $applicable => array (
$mountPoint => array (
'class' => $class ,
'options' => self :: encryptPasswords ( $classOptions ))
)
);
2014-05-14 19:32:19 +00:00
if ( ! $isPersonal && ! is_null ( $priority )) {
$mount [ $applicable ][ $mountPoint ][ 'priority' ] = $priority ;
2014-03-28 14:24:38 +00:00
}
2014-05-12 23:14:30 +00:00
2014-04-21 20:41:45 +00:00
$mountPoints = self :: readData ( $isPersonal ? OCP\User :: getUser () : NULL );
2014-09-25 18:17:52 +00:00
// who else loves multi-dimensional array ?
$isNew = ! isset ( $mountPoints [ $mountType ]) ||
! isset ( $mountPoints [ $mountType ][ $applicable ]) ||
! isset ( $mountPoints [ $mountType ][ $applicable ][ $mountPoint ]);
2014-05-12 23:14:30 +00:00
$mountPoints = self :: mergeMountPoints ( $mountPoints , $mount , $mountType );
2014-05-14 19:32:19 +00:00
// Set default priority if none set
if ( ! isset ( $mountPoints [ $mountType ][ $applicable ][ $mountPoint ][ 'priority' ])) {
2014-05-21 21:31:18 +00:00
if ( isset ( $backends [ $class ][ 'priority' ])) {
$mountPoints [ $mountType ][ $applicable ][ $mountPoint ][ 'priority' ]
= $backends [ $class ][ 'priority' ];
} else {
$mountPoints [ $mountType ][ $applicable ][ $mountPoint ][ 'priority' ]
= 100 ;
}
2014-05-14 19:32:19 +00:00
}
2014-04-21 20:41:45 +00:00
self :: writeData ( $isPersonal ? OCP\User :: getUser () : NULL , $mountPoints );
2014-05-12 23:14:30 +00:00
2014-09-25 18:17:52 +00:00
$result = self :: getBackendStatus ( $class , $classOptions , $isPersonal );
if ( $result && $isNew ) {
\OC_Hook :: emit (
\OC\Files\Filesystem :: CLASSNAME ,
2014-09-26 10:51:25 +00:00
\OC\Files\Filesystem :: signal_create_mount ,
2014-09-25 18:17:52 +00:00
array (
2014-09-28 14:32:27 +00:00
\OC\Files\Filesystem :: signal_param_path => $relMountPoint ,
2014-09-26 10:51:25 +00:00
\OC\Files\Filesystem :: signal_param_mount_type => $mountType ,
\OC\Files\Filesystem :: signal_param_users => $applicable ,
2014-09-25 18:17:52 +00:00
)
);
}
return $result ;
2012-09-07 12:09:41 +00:00
}
/**
*
2014-05-15 12:19:32 +00:00
* @ param string $mountPoint Mount point
* @ param string $mountType MOUNT_TYPE_GROUP | MOUNT_TYPE_USER
* @ param string $applicable User or group to remove mount from
* @ param bool $isPersonal Personal or system mount point
2012-09-07 12:09:41 +00:00
* @ return bool
*/
public static function removeMountPoint ( $mountPoint , $mountType , $applicable , $isPersonal = false ) {
// Verify that the mount point applies for the current user
2014-09-28 14:32:27 +00:00
$relMountPoints = $mountPoint ;
2012-09-07 12:09:41 +00:00
if ( $isPersonal ) {
if ( $applicable != OCP\User :: getUser ()) {
return false ;
}
$mountPoint = '/' . $applicable . '/files/' . ltrim ( $mountPoint , '/' );
} else {
$mountPoint = '/$user/files/' . ltrim ( $mountPoint , '/' );
}
2014-05-21 23:53:33 +00:00
$mountPoint = \OC\Files\Filesystem :: normalizePath ( $mountPoint );
2014-04-21 20:41:45 +00:00
$mountPoints = self :: readData ( $isPersonal ? OCP\User :: getUser () : NULL );
2012-09-07 12:09:41 +00:00
// Remove mount point
unset ( $mountPoints [ $mountType ][ $applicable ][ $mountPoint ]);
// Unset parent arrays if empty
if ( empty ( $mountPoints [ $mountType ][ $applicable ])) {
unset ( $mountPoints [ $mountType ][ $applicable ]);
if ( empty ( $mountPoints [ $mountType ])) {
unset ( $mountPoints [ $mountType ]);
}
}
2014-04-21 20:41:45 +00:00
self :: writeData ( $isPersonal ? OCP\User :: getUser () : NULL , $mountPoints );
2014-09-25 18:17:52 +00:00
\OC_Hook :: emit (
\OC\Files\Filesystem :: CLASSNAME ,
2014-09-26 10:51:25 +00:00
\OC\Files\Filesystem :: signal_delete_mount ,
2014-09-25 18:17:52 +00:00
array (
2014-09-28 14:32:27 +00:00
\OC\Files\Filesystem :: signal_param_path => $relMountPoints ,
2014-09-26 10:51:25 +00:00
\OC\Files\Filesystem :: signal_param_mount_type => $mountType ,
\OC\Files\Filesystem :: signal_param_users => $applicable ,
2014-09-25 18:17:52 +00:00
)
);
2012-09-07 12:09:41 +00:00
return true ;
}
2014-05-21 23:40:42 +00:00
/**
*
* @ param string $mountPoint Mount point
* @ param string $target The new mount point
* @ param string $mountType MOUNT_TYPE_GROUP | MOUNT_TYPE_USER
* @ return bool
*/
public static function movePersonalMountPoint ( $mountPoint , $target , $mountType ) {
$mountPoint = rtrim ( $mountPoint , '/' );
$user = OCP\User :: getUser ();
$mountPoints = self :: readData ( $user );
if ( ! isset ( $mountPoints [ $mountType ][ $user ][ $mountPoint ])) {
return false ;
}
$mountPoints [ $mountType ][ $user ][ $target ] = $mountPoints [ $mountType ][ $user ][ $mountPoint ];
// Remove old mount point
unset ( $mountPoints [ $mountType ][ $user ][ $mountPoint ]);
self :: writeData ( $user , $mountPoints );
return true ;
}
2012-09-07 12:09:41 +00:00
/**
* Read the mount points in the config file into an array
2014-04-21 20:41:45 +00:00
* @ param string | null $user If not null , personal for $user , otherwise system
2012-09-07 12:09:41 +00:00
* @ return array
*/
2014-04-21 20:41:45 +00:00
private static function readData ( $user = NULL ) {
2013-02-16 00:30:44 +00:00
$parser = new \OC\ArrayParser ();
2014-04-21 20:41:45 +00:00
if ( isset ( $user )) {
$phpFile = OC_User :: getHome ( $user ) . '/mount.php' ;
$jsonFile = OC_User :: getHome ( $user ) . '/mount.json' ;
2012-09-07 12:09:41 +00:00
} else {
2013-02-16 00:50:40 +00:00
$phpFile = OC :: $SERVERROOT . '/config/mount.php' ;
2014-02-24 09:35:24 +00:00
$datadir = \OC_Config :: getValue ( 'datadirectory' , \OC :: $SERVERROOT . '/data/' );
$jsonFile = \OC_Config :: getValue ( 'mount_file' , $datadir . '/mount.json' );
2012-09-07 12:09:41 +00:00
}
2013-02-16 00:50:40 +00:00
if ( is_file ( $jsonFile )) {
$mountPoints = json_decode ( file_get_contents ( $jsonFile ), true );
if ( is_array ( $mountPoints )) {
return $mountPoints ;
}
} elseif ( is_file ( $phpFile )) {
$mountPoints = $parser -> parsePHP ( file_get_contents ( $phpFile ));
2012-09-07 12:09:41 +00:00
if ( is_array ( $mountPoints )) {
return $mountPoints ;
}
}
return array ();
}
/**
* Write the mount points to the config file
2014-04-21 20:41:45 +00:00
* @ param string | null $user If not null , personal for $user , otherwise system
* @ param array $data Mount points
2012-09-07 12:09:41 +00:00
*/
2014-04-21 20:41:45 +00:00
private static function writeData ( $user , $data ) {
if ( isset ( $user )) {
$file = OC_User :: getHome ( $user ) . '/mount.json' ;
2012-09-07 12:09:41 +00:00
} else {
2014-02-24 09:35:24 +00:00
$datadir = \OC_Config :: getValue ( 'datadirectory' , \OC :: $SERVERROOT . '/data/' );
$file = \OC_Config :: getValue ( 'mount_file' , $datadir . '/mount.json' );
2012-09-07 12:09:41 +00:00
}
2014-03-26 10:29:04 +00:00
$options = 0 ;
if ( defined ( 'JSON_PRETTY_PRINT' )) {
// only for PHP >= 5.4
$options = JSON_PRETTY_PRINT ;
}
$content = json_encode ( $data , $options );
2012-09-07 12:09:41 +00:00
@ file_put_contents ( $file , $content );
2013-04-06 10:21:21 +00:00
@ chmod ( $file , 0640 );
2012-09-07 12:09:41 +00:00
}
2012-12-10 20:10:28 +00:00
/**
* check dependencies
*/
public static function checkDependencies () {
2013-08-02 13:44:56 +00:00
$dependencies = array ();
2013-03-08 17:15:20 +00:00
foreach ( OC_Mount_Config :: $backends as $class => $backend ) {
if ( isset ( $backend [ 'has_dependencies' ]) and $backend [ 'has_dependencies' ] === true ) {
$result = $class :: checkDependencies ();
2013-08-02 13:44:56 +00:00
if ( $result !== true ) {
2014-04-07 18:18:57 +00:00
if ( ! is_array ( $result )) {
$result = array ( $result );
}
2013-08-02 13:44:56 +00:00
foreach ( $result as $key => $value ) {
if ( is_numeric ( $key )) {
OC_Mount_Config :: addDependency ( $dependencies , $value , $backend [ 'backend' ]);
} else {
OC_Mount_Config :: addDependency ( $dependencies , $key , $backend [ 'backend' ], $value );
}
}
2013-03-08 17:15:20 +00:00
}
2013-08-15 10:00:02 +00:00
}
2013-02-14 16:57:19 +00:00
}
2012-12-10 20:10:28 +00:00
2013-08-02 13:44:56 +00:00
if ( count ( $dependencies ) > 0 ) {
return OC_Mount_Config :: generateDependencyMessage ( $dependencies );
2013-05-30 15:37:47 +00:00
}
return '' ;
}
2013-08-02 13:44:56 +00:00
private static function addDependency ( & $dependencies , $module , $backend , $message = null ) {
if ( ! isset ( $dependencies [ $module ])) {
$dependencies [ $module ] = array ();
}
if ( $message === null ) {
$dependencies [ $module ][] = $backend ;
} else {
$dependencies [ $module ][] = array ( 'backend' => $backend , 'message' => $message );
}
}
private static function generateDependencyMessage ( $dependencies ) {
$l = new \OC_L10N ( 'files_external' );
$dependencyMessage = '' ;
foreach ( $dependencies as $module => $backends ) {
$dependencyGroup = array ();
foreach ( $backends as $backend ) {
if ( is_array ( $backend )) {
$dependencyMessage .= '<br />' . $l -> t ( '<b>Note:</b> ' ) . $backend [ 'message' ];
} else {
$dependencyGroup [] = $backend ;
2013-05-30 15:37:47 +00:00
}
}
2014-10-23 21:27:15 +00:00
$dependencyGroupCount = count ( $dependencyGroup );
if ( $dependencyGroupCount > 0 ) {
2013-08-02 13:44:56 +00:00
$backends = '' ;
2014-10-23 21:27:15 +00:00
for ( $i = 0 ; $i < $dependencyGroupCount ; $i ++ ) {
if ( $i > 0 && $i === $dependencyGroupCount - 1 ) {
2013-08-02 13:44:56 +00:00
$backends .= $l -> t ( ' and ' );
} elseif ( $i > 0 ) {
$backends .= ', ' ;
}
$backends .= '<i>' . $dependencyGroup [ $i ] . '</i>' ;
}
$dependencyMessage .= '<br />' . OC_Mount_Config :: getSingleDependencyMessage ( $l , $module , $backends );
2013-05-30 15:37:47 +00:00
}
}
2013-08-02 13:44:56 +00:00
return $dependencyMessage ;
}
2013-05-30 15:37:47 +00:00
2013-08-02 13:44:56 +00:00
/**
* Returns a dependency missing message
2014-05-13 11:29:25 +00:00
* @ param OC_L10N $l
* @ param string $module
* @ param string $backend
2013-08-02 13:44:56 +00:00
* @ return string
*/
2014-10-24 12:13:40 +00:00
private static function getSingleDependencyMessage ( OC_L10N $l , $module , $backend ) {
2013-08-02 13:44:56 +00:00
switch ( strtolower ( $module )) {
case 'curl' :
return $l -> t ( '<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.' , $backend );
case 'ftp' :
return $l -> t ( '<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.' , $backend );
default :
return $l -> t ( '<b>Note:</b> "%s" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it.' , array ( $module , $backend ));
}
2012-12-10 20:10:28 +00:00
}
2014-03-18 20:15:11 +00:00
/**
* Encrypt passwords in the given config options
* @ param array $options mount options
* @ return array updated options
*/
private static function encryptPasswords ( $options ) {
if ( isset ( $options [ 'password' ])) {
2014-03-19 10:42:22 +00:00
$options [ 'password_encrypted' ] = self :: encryptPassword ( $options [ 'password' ]);
2014-03-19 16:56:36 +00:00
// do not unset the password, we want to keep the keys order
// on load... because that's how the UI currently works
$options [ 'password' ] = '' ;
2014-03-18 20:15:11 +00:00
}
return $options ;
}
/**
* Decrypt passwords in the given config options
* @ param array $options mount options
* @ return array updated options
*/
private static function decryptPasswords ( $options ) {
// note: legacy options might still have the unencrypted password in the "password" field
if ( isset ( $options [ 'password_encrypted' ])) {
2014-03-19 10:42:22 +00:00
$options [ 'password' ] = self :: decryptPassword ( $options [ 'password_encrypted' ]);
2014-03-18 20:15:11 +00:00
unset ( $options [ 'password_encrypted' ]);
}
return $options ;
}
2014-03-19 10:42:22 +00:00
/**
* Encrypt a single password
* @ param string $password plain text password
2014-05-13 11:29:25 +00:00
* @ return string encrypted password
2014-03-19 10:42:22 +00:00
*/
private static function encryptPassword ( $password ) {
$cipher = self :: getCipher ();
$iv = \OCP\Util :: generateRandomBytes ( 16 );
$cipher -> setIV ( $iv );
return base64_encode ( $iv . $cipher -> encrypt ( $password ));
}
/**
* Decrypts a single password
* @ param string $encryptedPassword encrypted password
2014-05-13 11:29:25 +00:00
* @ return string plain text password
2014-03-19 10:42:22 +00:00
*/
private static function decryptPassword ( $encryptedPassword ) {
$cipher = self :: getCipher ();
$binaryPassword = base64_decode ( $encryptedPassword );
$iv = substr ( $binaryPassword , 0 , 16 );
$cipher -> setIV ( $iv );
$binaryPassword = substr ( $binaryPassword , 16 );
return $cipher -> decrypt ( $binaryPassword );
}
2014-05-12 23:14:30 +00:00
/**
* Merges mount points
* @ param array $data Existing mount points
* @ param array $mountPoint New mount point
* @ param string $mountType
* @ return array
*/
private static function mergeMountPoints ( $data , $mountPoint , $mountType ) {
$applicable = key ( $mountPoint );
2014-05-14 19:32:19 +00:00
$mountPath = key ( $mountPoint [ $applicable ]);
2014-05-12 23:14:30 +00:00
if ( isset ( $data [ $mountType ])) {
if ( isset ( $data [ $mountType ][ $applicable ])) {
2014-05-14 21:34:38 +00:00
// Merge priorities
if ( isset ( $data [ $mountType ][ $applicable ][ $mountPath ])
&& isset ( $data [ $mountType ][ $applicable ][ $mountPath ][ 'priority' ])
&& ! isset ( $mountPoint [ $applicable ][ $mountPath ][ 'priority' ])) {
$mountPoint [ $applicable ][ $mountPath ][ 'priority' ]
= $data [ $mountType ][ $applicable ][ $mountPath ][ 'priority' ];
}
2014-05-12 23:14:30 +00:00
$data [ $mountType ][ $applicable ]
= array_merge ( $data [ $mountType ][ $applicable ], $mountPoint [ $applicable ]);
} else {
$data [ $mountType ] = array_merge ( $data [ $mountType ], $mountPoint );
}
} else {
$data [ $mountType ] = $mountPoint ;
}
return $data ;
}
2014-03-18 20:15:11 +00:00
/**
* Returns the encryption cipher
*/
private static function getCipher () {
2014-03-20 12:21:34 +00:00
if ( ! class_exists ( 'Crypt_AES' , false )) {
include ( 'Crypt/AES.php' );
}
2014-03-19 10:42:22 +00:00
$cipher = new Crypt_AES ( CRYPT_AES_MODE_CBC );
$cipher -> setKey ( \OCP\Config :: getSystemValue ( 'passwordsalt' ));
return $cipher ;
2014-03-18 20:15:11 +00:00
}
2014-03-26 11:10:17 +00:00
/**
* Computes a hash based on the given configuration .
* This is mostly used to find out whether configurations
* are the same .
*/
private static function makeConfigHash ( $config ) {
$data = json_encode (
array (
'c' => $config [ 'class' ],
'm' => $config [ 'mountpoint' ],
'o' => $config [ 'options' ]
)
);
return hash ( 'md5' , $data );
}
2012-09-07 12:09:41 +00:00
}