2012-09-07 16:09:41 +04:00
< ? php
/**
2015-03-26 13:44:34 +03:00
* @ author Bart Visscher < bartv @ thisnet . nl >
* @ author Björn Schießle < schiessle @ owncloud . com >
* @ author Frank Karlitschek < frank @ owncloud . org >
* @ author Joas Schilling < nickvergessen @ owncloud . com >
* @ author Jörn Friedrich Dreyer < jfd @ butonic . de >
* @ author Lukas Reschke < lukas @ owncloud . com >
* @ author Michael Gapczynski < GapczynskiM @ gmail . com >
* @ author Morris Jobke < hey @ morrisjobke . de >
* @ author Philipp Kapfer < philipp . kapfer @ gmx . at >
* @ author Robin Appelman < icewind @ owncloud . com >
* @ author Robin McCorkell < rmccorkell @ karoshi . org . uk >
* @ author Thomas Müller < thomas . mueller @ tmit . eu >
* @ author Vincent Petry < pvince81 @ owncloud . com >
2014-12-11 19:35:11 +03:00
*
2015-03-26 13:44:34 +03:00
* @ copyright Copyright ( c ) 2015 , ownCloud , Inc .
* @ license AGPL - 3.0
2014-12-11 19:35:11 +03:00
*
2015-03-26 13:44:34 +03:00
* 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 .
2014-12-11 19:35:11 +03:00
*
2015-03-26 13:44:34 +03:00
* This program is distributed in the hope that it will be useful ,
2014-12-11 19:35:11 +03:00
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
2015-03-26 13:44:34 +03:00
* 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-12-11 19:35:11 +03:00
*
2015-02-26 13:37:37 +03:00
*/
2015-08-03 07:39:53 +03:00
use phpseclib\Crypt\AES ;
2015-08-11 20:45:07 +03:00
use \OCP\AppFramework\IAppContainer ;
use \OCA\Files_External\Lib\BackendConfig ;
use \OCA\Files_External\Service\BackendService ;
2015-08-03 07:39:53 +03:00
2015-02-26 13:37:37 +03:00
/**
* Class to configure mount . json globally and for users
2014-03-19 00:15:11 +04:00
*/
2012-09-07 16:09:41 +04:00
class OC_Mount_Config {
2014-03-19 15:20:48 +04:00
// TODO: make this class non-static and give it a proper namespace
2012-09-07 16:09:41 +04:00
const MOUNT_TYPE_GLOBAL = 'global' ;
const MOUNT_TYPE_GROUP = 'group' ;
const MOUNT_TYPE_USER = 'user' ;
2014-05-09 23:59:56 +04:00
const MOUNT_TYPE_PERSONAL = 'personal' ;
2012-09-07 16:09:41 +04:00
2014-10-31 13:41:07 +03:00
// getBackendStatus return types
const STATUS_SUCCESS = 0 ;
const STATUS_ERROR = 1 ;
2014-03-18 21:29:08 +04:00
// whether to skip backend test (for unit tests, as this static class is not mockable)
public static $skipTest = false ;
2015-08-11 20:45:07 +03:00
/** @var IAppContainer */
private static $appContainer ;
2013-03-08 21:15:20 +04:00
2014-04-07 22:18:57 +04:00
/**
2015-08-11 20:45:07 +03:00
* Teach OC_Mount_Config about the AppFramework
2014-04-07 22:18:57 +04:00
*
2015-08-11 20:45:07 +03:00
* @ param IAppContainer $appContainer
2014-04-07 22:18:57 +04:00
*/
2015-08-11 20:45:07 +03:00
public static function initApp ( IAppContainer $appContainer ) {
self :: $appContainer = $appContainer ;
2014-04-07 22:18:57 +04:00
}
2015-08-11 20:45:07 +03:00
/*
2014-03-19 17:23:36 +04:00
* Hook that mounts the given user ' s visible mount points
2014-12-11 19:35:11 +03:00
*
2014-03-19 15:20:48 +04:00
* @ param array $data
*/
public static function initMountPointsHook ( $data ) {
2014-12-11 19:35:11 +03:00
self :: addStorageIdToConfig ( null );
2014-09-29 15:46:27 +04:00
if ( $data [ 'user' ]) {
2014-12-11 19:35:11 +03:00
self :: addStorageIdToConfig ( $data [ 'user' ]);
2014-09-29 15:46:27 +04:00
$user = \OC :: $server -> getUserManager () -> get ( $data [ 'user' ]);
2014-11-14 14:45:36 +03:00
if ( ! $user ) {
2015-07-02 14:00:21 +03:00
\OCP\Util :: writeLog (
'files_external' ,
2014-11-14 14:45:36 +03:00
'Cannot init external mount points for non-existant user "' . $data [ 'user' ] . '".' ,
2015-07-02 14:00:21 +03:00
\OCP\Util :: WARN
2014-11-14 14:45:36 +03:00
);
return ;
}
2014-09-29 15:46:27 +04:00
$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 17:23:36 +04:00
}
/**
* Returns the mount points for the given user .
* The mount point is relative to the data directory .
2015-08-11 20:45:07 +03:00
* TODO : Move me into StoragesService
2014-03-19 17:23:36 +04:00
*
* @ param string $user user
* @ return array of mount point string as key , mountpoint config as value
*/
public static function getAbsoluteMountPoints ( $user ) {
2014-03-21 18:22:48 +04:00
$mountPoints = array ();
2015-08-11 20:45:07 +03:00
$backendService = self :: $appContainer -> query ( 'OCA\Files_External\Service\BackendService' );
2014-03-28 18:24:38 +04:00
2014-03-19 15:20:48 +04:00
// Load system mount points
2014-04-22 00:41:45 +04:00
$mountConfig = self :: readData ();
2014-05-09 23:59:56 +04:00
// Global mount points (is this redundant?)
2014-03-19 15:20:48 +04:00
if ( isset ( $mountConfig [ self :: MOUNT_TYPE_GLOBAL ])) {
foreach ( $mountConfig [ self :: MOUNT_TYPE_GLOBAL ] as $mountPoint => $options ) {
2015-08-12 22:03:11 +03:00
if ( ! isset ( $options [ 'backend' ])) {
$options [ 'backend' ] = $options [ 'class' ];
}
$backend = $backendService -> getBackend ( $options [ 'backend' ]);
2014-05-22 03:40:42 +04:00
$options [ 'personal' ] = false ;
2014-03-19 15:20:48 +04:00
$options [ 'options' ] = self :: decryptPasswords ( $options [ 'options' ]);
2014-03-28 18:24:38 +04:00
if ( ! isset ( $options [ 'priority' ])) {
2015-08-11 20:45:07 +03:00
$options [ 'priority' ] = $backend -> getPriority ();
2014-03-28 18:24:38 +04:00
}
Authentication mechanisms for external storage backends
A backend can now specify generic authentication schemes that it
supports, instead of specifying the parameters for its authentication
method directly. This allows multiple authentication mechanisms to be
implemented for a single scheme, providing altered functionality.
This commit introduces the backend framework for this feature, and so at
this point the UI will be broken as the frontend does not specify the
required information.
Terminology:
- authentication scheme
Parameter interface for the authentication method. A backend
supporting the 'password' scheme accepts two parameters, 'user' and
'password'.
- authentication mechanism
Specific mechanism implementing a scheme. Basic mechanisms may
forward configuration options directly to the backend, more advanced
ones may lookup parameters or retrieve them from the session
New dropdown selector for external storage configurations to select the
authentication mechanism to be used.
Authentication mechanisms can have visibilities, just like backends.
The API was extended too to make it easier to add/remove visibilities.
In addition, the concept of 'allowed visibility' has been introduced, so
a backend/auth mechanism can force a maximum visibility level (e.g.
Local storage type) that cannot be overridden by configuration in the
web UI.
An authentication mechanism is a fully instantiated implementation. This
allows an implementation to have dependencies injected into it, e.g. an
\OCP\IDB for database operations.
When a StorageConfig is being prepared for mounting, the authentication
mechanism implementation has manipulateStorage() called,
which inserts the relevant authentication method options into the
storage ready for mounting.
2015-08-12 12:54:03 +03:00
if ( ! isset ( $options [ 'authMechanism' ])) {
2015-08-12 22:03:11 +03:00
$options [ 'authMechanism' ] = $backend -> getLegacyAuthMechanism ( $options [ 'options' ]) -> getIdentifier ();
Authentication mechanisms for external storage backends
A backend can now specify generic authentication schemes that it
supports, instead of specifying the parameters for its authentication
method directly. This allows multiple authentication mechanisms to be
implemented for a single scheme, providing altered functionality.
This commit introduces the backend framework for this feature, and so at
this point the UI will be broken as the frontend does not specify the
required information.
Terminology:
- authentication scheme
Parameter interface for the authentication method. A backend
supporting the 'password' scheme accepts two parameters, 'user' and
'password'.
- authentication mechanism
Specific mechanism implementing a scheme. Basic mechanisms may
forward configuration options directly to the backend, more advanced
ones may lookup parameters or retrieve them from the session
New dropdown selector for external storage configurations to select the
authentication mechanism to be used.
Authentication mechanisms can have visibilities, just like backends.
The API was extended too to make it easier to add/remove visibilities.
In addition, the concept of 'allowed visibility' has been introduced, so
a backend/auth mechanism can force a maximum visibility level (e.g.
Local storage type) that cannot be overridden by configuration in the
web UI.
An authentication mechanism is a fully instantiated implementation. This
allows an implementation to have dependencies injected into it, e.g. an
\OCP\IDB for database operations.
When a StorageConfig is being prepared for mounting, the authentication
mechanism implementation has manipulateStorage() called,
which inserts the relevant authentication method options into the
storage ready for mounting.
2015-08-12 12:54:03 +03:00
}
2015-08-11 20:45:07 +03:00
2014-05-22 01:29:16 +04:00
// Override if priority greater
2014-12-11 19:35:11 +03:00
if (( ! isset ( $mountPoints [ $mountPoint ]))
|| ( $options [ 'priority' ] >= $mountPoints [ $mountPoint ][ 'priority' ])
) {
2014-05-09 23:59:56 +04:00
$options [ 'priority_type' ] = self :: MOUNT_TYPE_GLOBAL ;
2015-08-11 20:45:07 +03:00
$options [ 'backend' ] = $backend -> getText ();
2014-03-28 18:24:38 +04:00
$mountPoints [ $mountPoint ] = $options ;
}
2014-03-19 15:20:48 +04:00
}
}
2014-05-09 23:59:56 +04:00
// All user mount points
2014-03-28 19:22:35 +04: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 );
}
2015-08-12 22:03:11 +03:00
if ( ! isset ( $options [ 'backend' ])) {
$options [ 'backend' ] = $options [ 'class' ];
}
$backend = $backendService -> getBackend ( $options [ 'backend' ]);
2014-08-29 12:08:46 +04:00
$options [ 'personal' ] = false ;
2014-03-28 19:22:35 +04:00
$options [ 'options' ] = self :: decryptPasswords ( $options [ 'options' ]);
if ( ! isset ( $options [ 'priority' ])) {
2015-08-11 20:45:07 +03:00
$options [ 'priority' ] = $backend -> getPriority ();
2014-03-28 19:22:35 +04:00
}
Authentication mechanisms for external storage backends
A backend can now specify generic authentication schemes that it
supports, instead of specifying the parameters for its authentication
method directly. This allows multiple authentication mechanisms to be
implemented for a single scheme, providing altered functionality.
This commit introduces the backend framework for this feature, and so at
this point the UI will be broken as the frontend does not specify the
required information.
Terminology:
- authentication scheme
Parameter interface for the authentication method. A backend
supporting the 'password' scheme accepts two parameters, 'user' and
'password'.
- authentication mechanism
Specific mechanism implementing a scheme. Basic mechanisms may
forward configuration options directly to the backend, more advanced
ones may lookup parameters or retrieve them from the session
New dropdown selector for external storage configurations to select the
authentication mechanism to be used.
Authentication mechanisms can have visibilities, just like backends.
The API was extended too to make it easier to add/remove visibilities.
In addition, the concept of 'allowed visibility' has been introduced, so
a backend/auth mechanism can force a maximum visibility level (e.g.
Local storage type) that cannot be overridden by configuration in the
web UI.
An authentication mechanism is a fully instantiated implementation. This
allows an implementation to have dependencies injected into it, e.g. an
\OCP\IDB for database operations.
When a StorageConfig is being prepared for mounting, the authentication
mechanism implementation has manipulateStorage() called,
which inserts the relevant authentication method options into the
storage ready for mounting.
2015-08-12 12:54:03 +03:00
if ( ! isset ( $options [ 'authMechanism' ])) {
2015-08-12 22:03:11 +03:00
$options [ 'authMechanism' ] = $backend -> getLegacyAuthMechanism ( $options [ 'options' ]) -> getIdentifier ();
Authentication mechanisms for external storage backends
A backend can now specify generic authentication schemes that it
supports, instead of specifying the parameters for its authentication
method directly. This allows multiple authentication mechanisms to be
implemented for a single scheme, providing altered functionality.
This commit introduces the backend framework for this feature, and so at
this point the UI will be broken as the frontend does not specify the
required information.
Terminology:
- authentication scheme
Parameter interface for the authentication method. A backend
supporting the 'password' scheme accepts two parameters, 'user' and
'password'.
- authentication mechanism
Specific mechanism implementing a scheme. Basic mechanisms may
forward configuration options directly to the backend, more advanced
ones may lookup parameters or retrieve them from the session
New dropdown selector for external storage configurations to select the
authentication mechanism to be used.
Authentication mechanisms can have visibilities, just like backends.
The API was extended too to make it easier to add/remove visibilities.
In addition, the concept of 'allowed visibility' has been introduced, so
a backend/auth mechanism can force a maximum visibility level (e.g.
Local storage type) that cannot be overridden by configuration in the
web UI.
An authentication mechanism is a fully instantiated implementation. This
allows an implementation to have dependencies injected into it, e.g. an
\OCP\IDB for database operations.
When a StorageConfig is being prepared for mounting, the authentication
mechanism implementation has manipulateStorage() called,
which inserts the relevant authentication method options into the
storage ready for mounting.
2015-08-12 12:54:03 +03:00
}
2014-03-28 19:22:35 +04:00
2014-05-22 01:29:16 +04:00
// Override if priority greater
2014-12-11 19:35:11 +03:00
if (( ! isset ( $mountPoints [ $mountPoint ]))
|| ( $options [ 'priority' ] >= $mountPoints [ $mountPoint ][ 'priority' ])
) {
2014-05-09 23:59:56 +04:00
$options [ 'priority_type' ] = self :: MOUNT_TYPE_GLOBAL ;
2015-08-11 20:45:07 +03:00
$options [ 'backend' ] = $backend -> getText ();
2014-03-28 19:22:35 +04:00
$mountPoints [ $mountPoint ] = $options ;
}
}
}
2014-05-09 23:59:56 +04:00
// Group mount points
2014-03-19 15:20:48 +04:00
if ( isset ( $mountConfig [ self :: MOUNT_TYPE_GROUP ])) {
foreach ( $mountConfig [ self :: MOUNT_TYPE_GROUP ] as $group => $mounts ) {
2015-07-02 14:00:21 +03:00
if ( \OC_Group :: inGroup ( $user , $group )) {
2014-03-19 15:20:48 +04:00
foreach ( $mounts as $mountPoint => $options ) {
$mountPoint = self :: setUserVars ( $user , $mountPoint );
foreach ( $options as & $option ) {
$option = self :: setUserVars ( $user , $option );
}
2015-08-12 22:03:11 +03:00
if ( ! isset ( $options [ 'backend' ])) {
$options [ 'backend' ] = $options [ 'class' ];
}
$backend = $backendService -> getBackend ( $options [ 'backend' ]);
2014-05-22 03:40:42 +04:00
$options [ 'personal' ] = false ;
2014-03-19 15:20:48 +04:00
$options [ 'options' ] = self :: decryptPasswords ( $options [ 'options' ]);
2014-03-28 18:24:38 +04:00
if ( ! isset ( $options [ 'priority' ])) {
2015-08-11 20:45:07 +03:00
$options [ 'priority' ] = $backend -> getPriority ();
2014-03-28 18:24:38 +04:00
}
Authentication mechanisms for external storage backends
A backend can now specify generic authentication schemes that it
supports, instead of specifying the parameters for its authentication
method directly. This allows multiple authentication mechanisms to be
implemented for a single scheme, providing altered functionality.
This commit introduces the backend framework for this feature, and so at
this point the UI will be broken as the frontend does not specify the
required information.
Terminology:
- authentication scheme
Parameter interface for the authentication method. A backend
supporting the 'password' scheme accepts two parameters, 'user' and
'password'.
- authentication mechanism
Specific mechanism implementing a scheme. Basic mechanisms may
forward configuration options directly to the backend, more advanced
ones may lookup parameters or retrieve them from the session
New dropdown selector for external storage configurations to select the
authentication mechanism to be used.
Authentication mechanisms can have visibilities, just like backends.
The API was extended too to make it easier to add/remove visibilities.
In addition, the concept of 'allowed visibility' has been introduced, so
a backend/auth mechanism can force a maximum visibility level (e.g.
Local storage type) that cannot be overridden by configuration in the
web UI.
An authentication mechanism is a fully instantiated implementation. This
allows an implementation to have dependencies injected into it, e.g. an
\OCP\IDB for database operations.
When a StorageConfig is being prepared for mounting, the authentication
mechanism implementation has manipulateStorage() called,
which inserts the relevant authentication method options into the
storage ready for mounting.
2015-08-12 12:54:03 +03:00
if ( ! isset ( $options [ 'authMechanism' ])) {
2015-08-12 22:03:11 +03:00
$options [ 'authMechanism' ] = $backend -> getLegacyAuthMechanism ( $options [ 'options' ]) -> getIdentifier ();
Authentication mechanisms for external storage backends
A backend can now specify generic authentication schemes that it
supports, instead of specifying the parameters for its authentication
method directly. This allows multiple authentication mechanisms to be
implemented for a single scheme, providing altered functionality.
This commit introduces the backend framework for this feature, and so at
this point the UI will be broken as the frontend does not specify the
required information.
Terminology:
- authentication scheme
Parameter interface for the authentication method. A backend
supporting the 'password' scheme accepts two parameters, 'user' and
'password'.
- authentication mechanism
Specific mechanism implementing a scheme. Basic mechanisms may
forward configuration options directly to the backend, more advanced
ones may lookup parameters or retrieve them from the session
New dropdown selector for external storage configurations to select the
authentication mechanism to be used.
Authentication mechanisms can have visibilities, just like backends.
The API was extended too to make it easier to add/remove visibilities.
In addition, the concept of 'allowed visibility' has been introduced, so
a backend/auth mechanism can force a maximum visibility level (e.g.
Local storage type) that cannot be overridden by configuration in the
web UI.
An authentication mechanism is a fully instantiated implementation. This
allows an implementation to have dependencies injected into it, e.g. an
\OCP\IDB for database operations.
When a StorageConfig is being prepared for mounting, the authentication
mechanism implementation has manipulateStorage() called,
which inserts the relevant authentication method options into the
storage ready for mounting.
2015-08-12 12:54:03 +03:00
}
2014-03-28 18:24:38 +04:00
2014-05-22 01:29:16 +04:00
// Override if priority greater or if priority type different
2014-12-11 19:35:11 +03:00
if (( ! isset ( $mountPoints [ $mountPoint ]))
2014-03-28 18:24:38 +04:00
|| ( $options [ 'priority' ] >= $mountPoints [ $mountPoint ][ 'priority' ])
2014-12-11 19:35:11 +03:00
|| ( $mountPoints [ $mountPoint ][ 'priority_type' ] !== self :: MOUNT_TYPE_GROUP )
) {
2014-05-09 23:59:56 +04:00
$options [ 'priority_type' ] = self :: MOUNT_TYPE_GROUP ;
2015-08-11 20:45:07 +03:00
$options [ 'backend' ] = $backend -> getText ();
2014-03-28 18:24:38 +04:00
$mountPoints [ $mountPoint ] = $options ;
}
2014-03-19 15:20:48 +04:00
}
}
}
}
2014-05-09 23:59:56 +04:00
// User mount points
2014-03-19 15:20:48 +04:00
if ( isset ( $mountConfig [ self :: MOUNT_TYPE_USER ])) {
foreach ( $mountConfig [ self :: MOUNT_TYPE_USER ] as $mountUser => $mounts ) {
2014-03-28 19:22:35 +04:00
if ( strtolower ( $mountUser ) === strtolower ( $user )) {
2014-03-19 15:20:48 +04:00
foreach ( $mounts as $mountPoint => $options ) {
$mountPoint = self :: setUserVars ( $user , $mountPoint );
foreach ( $options as & $option ) {
$option = self :: setUserVars ( $user , $option );
}
2015-08-12 22:03:11 +03:00
if ( ! isset ( $options [ 'backend' ])) {
$options [ 'backend' ] = $options [ 'class' ];
}
$backend = $backendService -> getBackend ( $options [ 'backend' ]);
2014-05-22 03:40:42 +04:00
$options [ 'personal' ] = false ;
2014-03-19 15:20:48 +04:00
$options [ 'options' ] = self :: decryptPasswords ( $options [ 'options' ]);
2014-03-28 18:24:38 +04:00
if ( ! isset ( $options [ 'priority' ])) {
2015-08-11 20:45:07 +03:00
$options [ 'priority' ] = $backend -> getPriority ();
2014-03-28 18:24:38 +04:00
}
Authentication mechanisms for external storage backends
A backend can now specify generic authentication schemes that it
supports, instead of specifying the parameters for its authentication
method directly. This allows multiple authentication mechanisms to be
implemented for a single scheme, providing altered functionality.
This commit introduces the backend framework for this feature, and so at
this point the UI will be broken as the frontend does not specify the
required information.
Terminology:
- authentication scheme
Parameter interface for the authentication method. A backend
supporting the 'password' scheme accepts two parameters, 'user' and
'password'.
- authentication mechanism
Specific mechanism implementing a scheme. Basic mechanisms may
forward configuration options directly to the backend, more advanced
ones may lookup parameters or retrieve them from the session
New dropdown selector for external storage configurations to select the
authentication mechanism to be used.
Authentication mechanisms can have visibilities, just like backends.
The API was extended too to make it easier to add/remove visibilities.
In addition, the concept of 'allowed visibility' has been introduced, so
a backend/auth mechanism can force a maximum visibility level (e.g.
Local storage type) that cannot be overridden by configuration in the
web UI.
An authentication mechanism is a fully instantiated implementation. This
allows an implementation to have dependencies injected into it, e.g. an
\OCP\IDB for database operations.
When a StorageConfig is being prepared for mounting, the authentication
mechanism implementation has manipulateStorage() called,
which inserts the relevant authentication method options into the
storage ready for mounting.
2015-08-12 12:54:03 +03:00
if ( ! isset ( $options [ 'authMechanism' ])) {
2015-08-12 22:03:11 +03:00
$options [ 'authMechanism' ] = $backend -> getLegacyAuthMechanism ( $options [ 'options' ]) -> getIdentifier ();
Authentication mechanisms for external storage backends
A backend can now specify generic authentication schemes that it
supports, instead of specifying the parameters for its authentication
method directly. This allows multiple authentication mechanisms to be
implemented for a single scheme, providing altered functionality.
This commit introduces the backend framework for this feature, and so at
this point the UI will be broken as the frontend does not specify the
required information.
Terminology:
- authentication scheme
Parameter interface for the authentication method. A backend
supporting the 'password' scheme accepts two parameters, 'user' and
'password'.
- authentication mechanism
Specific mechanism implementing a scheme. Basic mechanisms may
forward configuration options directly to the backend, more advanced
ones may lookup parameters or retrieve them from the session
New dropdown selector for external storage configurations to select the
authentication mechanism to be used.
Authentication mechanisms can have visibilities, just like backends.
The API was extended too to make it easier to add/remove visibilities.
In addition, the concept of 'allowed visibility' has been introduced, so
a backend/auth mechanism can force a maximum visibility level (e.g.
Local storage type) that cannot be overridden by configuration in the
web UI.
An authentication mechanism is a fully instantiated implementation. This
allows an implementation to have dependencies injected into it, e.g. an
\OCP\IDB for database operations.
When a StorageConfig is being prepared for mounting, the authentication
mechanism implementation has manipulateStorage() called,
which inserts the relevant authentication method options into the
storage ready for mounting.
2015-08-12 12:54:03 +03:00
}
2014-03-28 18:24:38 +04:00
2014-05-22 01:29:16 +04:00
// Override if priority greater or if priority type different
2014-12-11 19:35:11 +03:00
if (( ! isset ( $mountPoints [ $mountPoint ]))
2014-03-28 18:24:38 +04:00
|| ( $options [ 'priority' ] >= $mountPoints [ $mountPoint ][ 'priority' ])
2014-12-11 19:35:11 +03:00
|| ( $mountPoints [ $mountPoint ][ 'priority_type' ] !== self :: MOUNT_TYPE_USER )
) {
2014-05-09 23:59:56 +04:00
$options [ 'priority_type' ] = self :: MOUNT_TYPE_USER ;
2015-08-11 20:45:07 +03:00
$options [ 'backend' ] = $backend -> getText ();
2014-03-28 18:24:38 +04:00
$mountPoints [ $mountPoint ] = $options ;
}
2014-03-19 15:20:48 +04:00
}
}
}
}
// Load personal mount points
2014-04-22 00:41:45 +04:00
$mountConfig = self :: readData ( $user );
2014-03-19 15:20:48 +04:00
if ( isset ( $mountConfig [ self :: MOUNT_TYPE_USER ][ $user ])) {
foreach ( $mountConfig [ self :: MOUNT_TYPE_USER ][ $user ] as $mountPoint => $options ) {
2015-08-12 22:03:11 +03:00
if ( ! isset ( $options [ 'backend' ])) {
$options [ 'backend' ] = $options [ 'class' ];
}
$backend = $backendService -> getBackend ( $options [ 'backend' ]);
2015-08-11 20:45:07 +03:00
if ( $backend -> isVisibleFor ( BackendService :: VISIBILITY_PERSONAL )) {
2014-08-01 19:15:46 +04:00
$options [ 'personal' ] = true ;
$options [ 'options' ] = self :: decryptPasswords ( $options [ 'options' ]);
Authentication mechanisms for external storage backends
A backend can now specify generic authentication schemes that it
supports, instead of specifying the parameters for its authentication
method directly. This allows multiple authentication mechanisms to be
implemented for a single scheme, providing altered functionality.
This commit introduces the backend framework for this feature, and so at
this point the UI will be broken as the frontend does not specify the
required information.
Terminology:
- authentication scheme
Parameter interface for the authentication method. A backend
supporting the 'password' scheme accepts two parameters, 'user' and
'password'.
- authentication mechanism
Specific mechanism implementing a scheme. Basic mechanisms may
forward configuration options directly to the backend, more advanced
ones may lookup parameters or retrieve them from the session
New dropdown selector for external storage configurations to select the
authentication mechanism to be used.
Authentication mechanisms can have visibilities, just like backends.
The API was extended too to make it easier to add/remove visibilities.
In addition, the concept of 'allowed visibility' has been introduced, so
a backend/auth mechanism can force a maximum visibility level (e.g.
Local storage type) that cannot be overridden by configuration in the
web UI.
An authentication mechanism is a fully instantiated implementation. This
allows an implementation to have dependencies injected into it, e.g. an
\OCP\IDB for database operations.
When a StorageConfig is being prepared for mounting, the authentication
mechanism implementation has manipulateStorage() called,
which inserts the relevant authentication method options into the
storage ready for mounting.
2015-08-12 12:54:03 +03:00
if ( ! isset ( $options [ 'authMechanism' ])) {
2015-08-12 22:03:11 +03:00
$options [ 'authMechanism' ] = $backend -> getLegacyAuthMechanism ( $options [ 'options' ]) -> getIdentifier ();
Authentication mechanisms for external storage backends
A backend can now specify generic authentication schemes that it
supports, instead of specifying the parameters for its authentication
method directly. This allows multiple authentication mechanisms to be
implemented for a single scheme, providing altered functionality.
This commit introduces the backend framework for this feature, and so at
this point the UI will be broken as the frontend does not specify the
required information.
Terminology:
- authentication scheme
Parameter interface for the authentication method. A backend
supporting the 'password' scheme accepts two parameters, 'user' and
'password'.
- authentication mechanism
Specific mechanism implementing a scheme. Basic mechanisms may
forward configuration options directly to the backend, more advanced
ones may lookup parameters or retrieve them from the session
New dropdown selector for external storage configurations to select the
authentication mechanism to be used.
Authentication mechanisms can have visibilities, just like backends.
The API was extended too to make it easier to add/remove visibilities.
In addition, the concept of 'allowed visibility' has been introduced, so
a backend/auth mechanism can force a maximum visibility level (e.g.
Local storage type) that cannot be overridden by configuration in the
web UI.
An authentication mechanism is a fully instantiated implementation. This
allows an implementation to have dependencies injected into it, e.g. an
\OCP\IDB for database operations.
When a StorageConfig is being prepared for mounting, the authentication
mechanism implementation has manipulateStorage() called,
which inserts the relevant authentication method options into the
storage ready for mounting.
2015-08-12 12:54:03 +03:00
}
2014-03-28 18:24:38 +04:00
2014-08-01 19:15:46 +04:00
// Always override previous config
$options [ 'priority_type' ] = self :: MOUNT_TYPE_PERSONAL ;
2015-08-11 20:45:07 +03:00
$options [ 'backend' ] = $backend -> getText ();
2014-08-01 19:15:46 +04:00
$mountPoints [ $mountPoint ] = $options ;
}
2014-03-19 15:20:48 +04:00
}
}
2014-03-19 17:23:36 +04:00
return $mountPoints ;
2014-03-19 15:20:48 +04:00
}
/**
* fill in the correct values for $user
*
2015-03-26 21:24:37 +03:00
* @ param string $user user value
* @ param string | array $input
2014-03-19 15:20:48 +04:00
* @ return string
*/
private static function setUserVars ( $user , $input ) {
2015-03-26 21:24:37 +03:00
if ( is_array ( $input )) {
foreach ( $input as & $value ) {
if ( is_string ( $value )) {
$value = str_replace ( '$user' , $user , $value );
}
}
} else {
$input = str_replace ( '$user' , $user , $input );
}
return $input ;
2014-03-19 15:20:48 +04:00
}
2012-09-07 16:09:41 +04:00
/**
2014-12-11 19:35:11 +03:00
* Get the system mount points
* The returned array is not in the same format as getUserMountPoints ()
*
* @ return array
*/
2012-09-07 16:09:41 +04:00
public static function getSystemMountPoints () {
2014-04-22 00:41:45 +04:00
$mountPoints = self :: readData ();
2015-08-11 20:45:07 +03:00
$backendService = self :: $appContainer -> query ( '\OCA\Files_External\Service\BackendService' );
2012-09-07 16:09:41 +04:00
$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 21:07:04 +04:00
// Update old classes to new namespace
if ( strpos ( $mount [ 'class' ], 'OC_Filestorage_' ) !== false ) {
2014-12-11 19:35:11 +03:00
$mount [ 'class' ] = '\OC\Files\Storage\\' . substr ( $mount [ 'class' ], 15 );
2013-01-03 21:07:04 +04:00
}
2015-08-11 20:45:07 +03:00
$backend = $backendService -> getBackend ( $mount [ 'class' ]);
2014-03-19 00:15:11 +04:00
$mount [ 'options' ] = self :: decryptPasswords ( $mount [ 'options' ]);
2014-03-28 18:24:38 +04:00
if ( ! isset ( $mount [ 'priority' ])) {
2015-08-11 20:45:07 +03:00
$mount [ 'priority' ] = $backend -> getPriority ();
2014-03-28 18:24:38 +04:00
}
2012-09-07 16:09:41 +04:00
// Remove '/$user/files/' from mount point
$mountPoint = substr ( $mountPoint , 13 );
2014-03-26 15:10:17 +04:00
$config = array (
'class' => $mount [ 'class' ],
'mountpoint' => $mountPoint ,
2015-08-11 20:45:07 +03:00
'backend' => $backend -> getText (),
2014-03-28 18:24:38 +04:00
'priority' => $mount [ 'priority' ],
2014-03-26 15:10:17 +04:00
'options' => $mount [ 'options' ],
2015-03-20 12:48:14 +03:00
'applicable' => array ( 'groups' => array ( $group ), 'users' => array ())
2014-03-26 15:10:17 +04:00
);
2015-03-13 19:43:38 +03:00
if ( isset ( $mount [ 'id' ])) {
$config [ 'id' ] = ( int ) $mount [ 'id' ];
}
if ( isset ( $mount [ 'storage_id' ])) {
$config [ 'storage_id' ] = ( int ) $mount [ 'storage_id' ];
}
2015-03-13 14:49:11 +03:00
if ( isset ( $mount [ 'mountOptions' ])) {
$config [ 'mountOptions' ] = $mount [ 'mountOptions' ];
}
2014-03-26 15:10:17 +04: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 16:09:41 +04:00
} else {
2014-03-26 15:10:17 +04:00
$system [ $hash ] = $config ;
2012-09-07 16:09:41 +04: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 21:07:04 +04:00
// Update old classes to new namespace
if ( strpos ( $mount [ 'class' ], 'OC_Filestorage_' ) !== false ) {
2014-12-11 19:35:11 +03:00
$mount [ 'class' ] = '\OC\Files\Storage\\' . substr ( $mount [ 'class' ], 15 );
2013-01-03 21:07:04 +04:00
}
2015-08-11 20:45:07 +03:00
$backend = $backendService -> getBackend ( $mount [ 'class' ]);
2014-03-19 00:15:11 +04:00
$mount [ 'options' ] = self :: decryptPasswords ( $mount [ 'options' ]);
2014-03-28 18:24:38 +04:00
if ( ! isset ( $mount [ 'priority' ])) {
2015-08-11 20:45:07 +03:00
$mount [ 'priority' ] = $backend -> getPriority ();
2014-03-28 18:24:38 +04:00
}
2012-09-07 16:09:41 +04:00
// Remove '/$user/files/' from mount point
$mountPoint = substr ( $mountPoint , 13 );
2014-03-26 15:10:17 +04:00
$config = array (
'class' => $mount [ 'class' ],
'mountpoint' => $mountPoint ,
2015-08-11 20:45:07 +03:00
'backend' => $backend -> getText (),
2014-03-28 18:24:38 +04:00
'priority' => $mount [ 'priority' ],
2014-03-26 15:10:17 +04:00
'options' => $mount [ 'options' ],
2015-03-20 12:48:14 +03:00
'applicable' => array ( 'groups' => array (), 'users' => array ( $user ))
2014-03-26 15:10:17 +04:00
);
2015-03-13 19:43:38 +03:00
if ( isset ( $mount [ 'id' ])) {
$config [ 'id' ] = ( int ) $mount [ 'id' ];
}
if ( isset ( $mount [ 'storage_id' ])) {
$config [ 'storage_id' ] = ( int ) $mount [ 'storage_id' ];
}
2015-03-13 14:49:11 +03:00
if ( isset ( $mount [ 'mountOptions' ])) {
$config [ 'mountOptions' ] = $mount [ 'mountOptions' ];
}
2014-03-26 15:10:17 +04: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 16:09:41 +04:00
} else {
2014-03-26 15:10:17 +04:00
$system [ $hash ] = $config ;
2012-09-07 16:09:41 +04:00
}
}
}
}
2014-03-26 15:10:17 +04:00
return array_values ( $system );
2012-09-07 16:09:41 +04:00
}
/**
2014-12-11 19:35:11 +03:00
* Get the personal mount points of the current user
* The returned array is not in the same format as getUserMountPoints ()
*
* @ return array
*/
2012-09-07 16:09:41 +04:00
public static function getPersonalMountPoints () {
2014-04-22 00:41:45 +04:00
$mountPoints = self :: readData ( OCP\User :: getUser ());
2015-08-11 20:45:07 +03:00
$backendService = self :: $appContainer -> query ( '\OCA\Files_External\Service\BackendService' );
2012-09-07 16:09:41 +04: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 21:07:04 +04:00
// Update old classes to new namespace
if ( strpos ( $mount [ 'class' ], 'OC_Filestorage_' ) !== false ) {
2014-12-11 19:35:11 +03:00
$mount [ 'class' ] = '\OC\Files\Storage\\' . substr ( $mount [ 'class' ], 15 );
2013-01-03 21:07:04 +04:00
}
2015-08-11 20:45:07 +03:00
$backend = $backendService -> getBackend ( $mount [ 'class' ]);
2014-03-19 00:15:11 +04:00
$mount [ 'options' ] = self :: decryptPasswords ( $mount [ 'options' ]);
2015-03-13 14:49:11 +03:00
$config = array (
2012-12-24 22:45:52 +04:00
'class' => $mount [ 'class' ],
2014-03-26 15:10:17 +04:00
// Remove '/uid/files/' from mount point
'mountpoint' => substr ( $mountPoint , strlen ( $uid ) + 8 ),
2015-08-11 20:45:07 +03:00
'backend' => $backend -> getText (),
2015-03-20 12:48:14 +03:00
'options' => $mount [ 'options' ]
2012-12-24 22:45:52 +04:00
);
2015-03-13 19:43:38 +03:00
if ( isset ( $mount [ 'id' ])) {
$config [ 'id' ] = ( int ) $mount [ 'id' ];
}
if ( isset ( $mount [ 'storage_id' ])) {
$config [ 'storage_id' ] = ( int ) $mount [ 'storage_id' ];
}
2015-03-13 14:49:11 +03:00
if ( isset ( $mount [ 'mountOptions' ])) {
$config [ 'mountOptions' ] = $mount [ 'mountOptions' ];
}
$personal [] = $config ;
2012-09-07 16:09:41 +04:00
}
}
return $personal ;
}
2014-03-19 15:20:48 +04:00
/**
* Test connecting using the given backend configuration
2014-12-11 19:35:11 +03:00
*
2014-03-19 15:20:48 +04:00
* @ param string $class backend class name
* @ param array $options backend configuration options
2014-10-31 13:41:07 +03:00
* @ return int see self :: STATUS_ *
2014-03-19 15:20:48 +04:00
*/
2014-10-31 13:41:07 +03:00
public static function getBackendStatus ( $class , $options , $isPersonal ) {
2014-03-18 21:29:08 +04:00
if ( self :: $skipTest ) {
2014-10-31 13:41:07 +03:00
return self :: STATUS_SUCCESS ;
2014-03-18 21:29:08 +04:00
}
2012-12-24 22:45:52 +04:00
foreach ( $options as & $option ) {
2014-03-19 15:20:48 +04:00
$option = self :: setUserVars ( OCP\User :: getUser (), $option );
2012-12-24 22:45:52 +04:00
}
if ( class_exists ( $class )) {
try {
2012-12-28 21:00:48 +04:00
$storage = new $class ( $options );
2015-01-24 00:53:21 +03:00
try {
$result = $storage -> test ( $isPersonal );
$storage -> setAvailability ( $result );
if ( $result ) {
return self :: STATUS_SUCCESS ;
}
} catch ( \Exception $e ) {
$storage -> setAvailability ( false );
throw $e ;
2014-10-31 13:41:07 +03:00
}
2012-12-24 22:45:52 +04:00
} catch ( Exception $exception ) {
2013-12-02 19:55:43 +04:00
\OCP\Util :: logException ( 'files_external' , $exception );
2012-12-24 22:45:52 +04:00
}
}
2014-10-31 13:41:07 +03:00
return self :: STATUS_ERROR ;
2012-12-24 22:45:52 +04:00
}
2012-09-07 16:09:41 +04:00
/**
2014-12-11 19:35:11 +03:00
* Add a mount point to the filesystem
*
* @ param string $mountPoint Mount point
* @ param string $class Backend class
* @ param array $classOptions Backend parameters for the class
* @ param string $mountType MOUNT_TYPE_GROUP | MOUNT_TYPE_USER
* @ param string $applicable User or group to apply mount to
* @ param bool $isPersonal Personal or system mount point i . e . is this being called from the personal or admin page
* @ param int | null $priority Mount point priority , null for default
* @ return boolean
2014-10-31 13:41:07 +03:00
*
* @ deprecated use StoragesService #addStorage() instead
2014-12-11 19:35:11 +03:00
*/
2012-11-30 19:27:11 +04:00
public static function addMountPoint ( $mountPoint ,
$class ,
$classOptions ,
$mountType ,
$applicable ,
2014-05-14 23:32:19 +04:00
$isPersonal = false ,
$priority = null ) {
2015-08-11 20:45:07 +03:00
$backendService = self :: $appContainer -> query ( '\OCA\Files_External\Service\BackendService' );
2013-11-21 20:21:51 +04:00
$mountPoint = OC\Files\Filesystem :: normalizePath ( $mountPoint );
2014-09-28 18:32:27 +04:00
$relMountPoint = $mountPoint ;
2014-04-14 12:15:43 +04:00
if ( $mountPoint === '' || $mountPoint === '/' ) {
// can't mount at root folder
2013-11-21 20:21:51 +04:00
return false ;
}
2014-02-19 22:08:28 +04:00
2015-08-11 20:45:07 +03:00
$backend = $backendService -> getBackend ( $class );
if ( ! isset ( $backend )) {
2014-02-19 22:08:28 +04:00
// invalid backend
return false ;
2014-02-18 19:36:02 +04:00
}
2012-09-07 16:09:41 +04:00
if ( $isPersonal ) {
// Verify that the mount point applies for the current user
2014-02-18 19:36:02 +04:00
// Prevent non-admin users from mounting local storage and other disabled backends
2015-08-11 20:45:07 +03:00
if ( $applicable != OCP\User :: getUser () || ! $backend -> isVisibleFor ( BackendConfig :: VISIBILITY_PERSONAL )) {
2012-09-07 16:09:41 +04:00
return false ;
}
2014-12-11 19:35:11 +03:00
$mountPoint = '/' . $applicable . '/files/' . ltrim ( $mountPoint , '/' );
2012-09-07 16:09:41 +04:00
} else {
2014-12-11 19:35:11 +03:00
$mountPoint = '/$user/files/' . ltrim ( $mountPoint , '/' );
2012-09-07 16:09:41 +04:00
}
2014-03-19 00:15:11 +04:00
$mount = array ( $applicable => array (
$mountPoint => array (
'class' => $class ,
'options' => self :: encryptPasswords ( $classOptions ))
2014-12-11 19:35:11 +03:00
)
2014-03-19 00:15:11 +04:00
);
2014-12-11 19:35:11 +03:00
if ( ! $isPersonal && ! is_null ( $priority )) {
2014-05-14 23:32:19 +04:00
$mount [ $applicable ][ $mountPoint ][ 'priority' ] = $priority ;
2014-03-28 18:24:38 +04:00
}
2014-05-13 03:14:30 +04:00
2014-12-11 19:35:11 +03:00
$mountPoints = self :: readData ( $isPersonal ? OCP\User :: getUser () : null );
2014-09-25 22:17:52 +04:00
// who else loves multi-dimensional array ?
$isNew = ! isset ( $mountPoints [ $mountType ]) ||
! isset ( $mountPoints [ $mountType ][ $applicable ]) ||
! isset ( $mountPoints [ $mountType ][ $applicable ][ $mountPoint ]);
2014-05-13 03:14:30 +04:00
$mountPoints = self :: mergeMountPoints ( $mountPoints , $mount , $mountType );
2014-05-14 23:32:19 +04:00
// Set default priority if none set
if ( ! isset ( $mountPoints [ $mountType ][ $applicable ][ $mountPoint ][ 'priority' ])) {
2015-08-11 20:45:07 +03:00
$mountPoints [ $mountType ][ $applicable ][ $mountPoint ][ 'priority' ]
= $backend -> getPriority ();
2014-05-14 23:32:19 +04:00
}
2014-12-11 19:35:11 +03:00
self :: writeData ( $isPersonal ? OCP\User :: getUser () : null , $mountPoints );
2014-05-13 03:14:30 +04:00
2014-09-25 22:17:52 +04:00
$result = self :: getBackendStatus ( $class , $classOptions , $isPersonal );
2014-10-31 13:41:07 +03:00
if ( $result === self :: STATUS_SUCCESS && $isNew ) {
2015-07-02 14:00:21 +03:00
\OC_Hook :: emit (
2014-09-25 22:17:52 +04:00
\OC\Files\Filesystem :: CLASSNAME ,
2014-09-26 14:51:25 +04:00
\OC\Files\Filesystem :: signal_create_mount ,
2014-09-25 22:17:52 +04:00
array (
2014-09-28 18:32:27 +04:00
\OC\Files\Filesystem :: signal_param_path => $relMountPoint ,
2014-09-26 14:51:25 +04:00
\OC\Files\Filesystem :: signal_param_mount_type => $mountType ,
\OC\Files\Filesystem :: signal_param_users => $applicable ,
2014-09-25 22:17:52 +04:00
)
);
}
return $result ;
2012-09-07 16:09:41 +04:00
}
/**
2014-12-11 19:35:11 +03: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
* @ return bool
2014-10-31 13:41:07 +03:00
*
* @ deprecated use StoragesService #removeStorage() instead
2014-12-11 19:35:11 +03:00
*/
2012-09-07 16:09:41 +04:00
public static function removeMountPoint ( $mountPoint , $mountType , $applicable , $isPersonal = false ) {
// Verify that the mount point applies for the current user
2014-09-28 18:32:27 +04:00
$relMountPoints = $mountPoint ;
2012-09-07 16:09:41 +04:00
if ( $isPersonal ) {
if ( $applicable != OCP\User :: getUser ()) {
return false ;
}
2014-12-11 19:35:11 +03:00
$mountPoint = '/' . $applicable . '/files/' . ltrim ( $mountPoint , '/' );
2012-09-07 16:09:41 +04:00
} else {
2014-12-11 19:35:11 +03:00
$mountPoint = '/$user/files/' . ltrim ( $mountPoint , '/' );
2012-09-07 16:09:41 +04:00
}
2014-05-22 03:53:33 +04:00
$mountPoint = \OC\Files\Filesystem :: normalizePath ( $mountPoint );
2014-12-11 19:35:11 +03:00
$mountPoints = self :: readData ( $isPersonal ? OCP\User :: getUser () : null );
2012-09-07 16:09:41 +04: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-12-11 19:35:11 +03:00
self :: writeData ( $isPersonal ? OCP\User :: getUser () : null , $mountPoints );
2015-07-02 14:00:21 +03:00
\OC_Hook :: emit (
2014-09-25 22:17:52 +04:00
\OC\Files\Filesystem :: CLASSNAME ,
2014-09-26 14:51:25 +04:00
\OC\Files\Filesystem :: signal_delete_mount ,
2014-09-25 22:17:52 +04:00
array (
2014-09-28 18:32:27 +04:00
\OC\Files\Filesystem :: signal_param_path => $relMountPoints ,
2014-09-26 14:51:25 +04:00
\OC\Files\Filesystem :: signal_param_mount_type => $mountType ,
\OC\Files\Filesystem :: signal_param_users => $applicable ,
2014-09-25 22:17:52 +04:00
)
);
2012-09-07 16:09:41 +04:00
return true ;
}
2014-05-22 03:40:42 +04: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 16:09:41 +04:00
/**
2014-12-11 19:35:11 +03:00
* Read the mount points in the config file into an array
*
* @ param string | null $user If not null , personal for $user , otherwise system
* @ return array
*/
2014-10-31 13:41:07 +03:00
public static function readData ( $user = null ) {
2014-04-22 00:41:45 +04:00
if ( isset ( $user )) {
2015-07-02 14:00:21 +03:00
$jsonFile = OC_User :: getHome ( $user ) . '/mount.json' ;
2012-09-07 16:09:41 +04:00
} else {
2015-07-02 14:00:21 +03:00
$datadir = \OC_Config :: getValue ( 'datadirectory' , \OC :: $SERVERROOT . '/data/' );
$jsonFile = \OC_Config :: getValue ( 'mount_file' , $datadir . '/mount.json' );
2012-09-07 16:09:41 +04:00
}
2013-02-16 04:50:40 +04:00
if ( is_file ( $jsonFile )) {
$mountPoints = json_decode ( file_get_contents ( $jsonFile ), true );
if ( is_array ( $mountPoints )) {
return $mountPoints ;
}
2012-09-07 16:09:41 +04:00
}
return array ();
}
/**
2014-12-11 19:35:11 +03:00
* Write the mount points to the config file
*
* @ param string | null $user If not null , personal for $user , otherwise system
* @ param array $data Mount points
*/
2014-10-31 13:41:07 +03:00
public static function writeData ( $user , $data ) {
2014-04-22 00:41:45 +04:00
if ( isset ( $user )) {
2015-07-02 14:00:21 +03:00
$file = OC_User :: getHome ( $user ) . '/mount.json' ;
2012-09-07 16:09:41 +04:00
} else {
2015-07-02 14:00:21 +03:00
$datadir = \OC_Config :: getValue ( 'datadirectory' , \OC :: $SERVERROOT . '/data/' );
$file = \OC_Config :: getValue ( 'mount_file' , $datadir . '/mount.json' );
2012-09-07 16:09:41 +04:00
}
2014-12-11 19:35:11 +03:00
foreach ( $data as & $applicables ) {
foreach ( $applicables as & $mountPoints ) {
foreach ( $mountPoints as & $options ) {
self :: addStorageId ( $options );
}
}
}
2014-12-12 14:25:59 +03:00
$content = json_encode ( $data , JSON_PRETTY_PRINT );
2012-09-07 16:09:41 +04:00
@ file_put_contents ( $file , $content );
2013-04-06 14:21:21 +04:00
@ chmod ( $file , 0640 );
2012-09-07 16:09:41 +04:00
}
2012-12-11 00:10:28 +04:00
/**
2015-08-11 20:45:07 +03:00
* Get backend dependency message
* TODO : move into AppFramework along with templates
*
* @ param BackendConfig [] $backends
* @ return string
2012-12-11 00:10:28 +04:00
*/
2015-08-11 20:45:07 +03:00
public static function dependencyMessage ( $backends ) {
2015-07-02 14:00:21 +03:00
$l = new \OC_L10N ( 'files_external' );
2015-08-11 20:45:07 +03:00
$message = '' ;
$dependencyGroups = [];
foreach ( $backends as $backend ) {
foreach ( $backend -> checkDependencies () as $dependency ) {
if ( $message = $dependency -> getMessage ()) {
$message .= '<br />' . $l -> t ( '<b>Note:</b> ' ) . $message ;
2013-08-02 17:44:56 +04:00
} else {
2015-08-11 20:45:07 +03:00
$dependencyGroups [ $dependency -> getDependency ()][] = $backend ;
2013-05-30 19:37:47 +04:00
}
}
2015-08-11 20:45:07 +03:00
}
2013-05-30 19:37:47 +04:00
2015-08-11 20:45:07 +03:00
foreach ( $dependencyGroups as $module => $dependants ) {
$backends = implode ( ', ' , array_map ( function ( $backend ) {
return '<i>' . $backend -> getText () . '</i>' ;
}, $dependants ));
$message .= '<br />' . OC_Mount_Config :: getSingleDependencyMessage ( $l , $module , $backends );
2013-05-30 19:37:47 +04:00
}
2015-08-11 20:45:07 +03:00
return $message ;
2013-08-02 17:44:56 +04:00
}
2013-05-30 19:37:47 +04:00
2013-08-02 17:44:56 +04:00
/**
* Returns a dependency missing message
2014-12-11 19:35:11 +03:00
*
2014-05-13 15:29:25 +04:00
* @ param OC_L10N $l
* @ param string $module
* @ param string $backend
2013-08-02 17:44:56 +04:00
* @ return string
*/
2015-07-02 14:00:21 +03:00
private static function getSingleDependencyMessage ( OC_L10N $l , $module , $backend ) {
2013-08-02 17:44:56 +04: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-11 00:10:28 +04:00
}
2014-03-19 00:15:11 +04:00
/**
* Encrypt passwords in the given config options
2014-12-11 19:35:11 +03:00
*
2014-03-19 00:15:11 +04:00
* @ param array $options mount options
* @ return array updated options
*/
2014-10-31 13:41:07 +03:00
public static function encryptPasswords ( $options ) {
2014-03-19 00:15:11 +04:00
if ( isset ( $options [ 'password' ])) {
2014-03-19 14:42:22 +04:00
$options [ 'password_encrypted' ] = self :: encryptPassword ( $options [ 'password' ]);
2014-03-19 20:56:36 +04: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-19 00:15:11 +04:00
}
return $options ;
}
/**
* Decrypt passwords in the given config options
2014-12-11 19:35:11 +03:00
*
2014-03-19 00:15:11 +04:00
* @ param array $options mount options
* @ return array updated options
*/
2014-10-31 13:41:07 +03:00
public static function decryptPasswords ( $options ) {
2014-03-19 00:15:11 +04:00
// note: legacy options might still have the unencrypted password in the "password" field
if ( isset ( $options [ 'password_encrypted' ])) {
2014-03-19 14:42:22 +04:00
$options [ 'password' ] = self :: decryptPassword ( $options [ 'password_encrypted' ]);
2014-03-19 00:15:11 +04:00
unset ( $options [ 'password_encrypted' ]);
}
return $options ;
}
2014-03-19 14:42:22 +04:00
/**
* Encrypt a single password
2014-12-11 19:35:11 +03:00
*
2014-03-19 14:42:22 +04:00
* @ param string $password plain text password
2014-05-13 15:29:25 +04:00
* @ return string encrypted password
2014-03-19 14:42:22 +04: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
2014-12-11 19:35:11 +03:00
*
2014-03-19 14:42:22 +04:00
* @ param string $encryptedPassword encrypted password
2014-05-13 15:29:25 +04:00
* @ return string plain text password
2014-03-19 14:42:22 +04: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-13 03:14:30 +04:00
/**
* Merges mount points
2014-12-11 19:35:11 +03:00
*
2014-05-13 03:14:30 +04:00
* @ 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 23:32:19 +04:00
$mountPath = key ( $mountPoint [ $applicable ]);
2014-05-13 03:14:30 +04:00
if ( isset ( $data [ $mountType ])) {
if ( isset ( $data [ $mountType ][ $applicable ])) {
2014-05-15 01:34:38 +04:00
// Merge priorities
if ( isset ( $data [ $mountType ][ $applicable ][ $mountPath ])
&& isset ( $data [ $mountType ][ $applicable ][ $mountPath ][ 'priority' ])
2014-12-11 19:35:11 +03:00
&& ! isset ( $mountPoint [ $applicable ][ $mountPath ][ 'priority' ])
) {
2014-05-15 01:34:38 +04:00
$mountPoint [ $applicable ][ $mountPath ][ 'priority' ]
= $data [ $mountType ][ $applicable ][ $mountPath ][ 'priority' ];
}
2014-05-13 03:14:30 +04: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-19 00:15:11 +04:00
/**
* Returns the encryption cipher
*/
private static function getCipher () {
2015-08-03 07:39:53 +03:00
$cipher = new AES ( AES :: MODE_CBC );
2014-12-17 13:12:37 +03:00
$cipher -> setKey ( \OC :: $server -> getConfig () -> getSystemValue ( 'passwordsalt' , null ));
2014-03-19 14:42:22 +04:00
return $cipher ;
2014-03-19 00:15:11 +04:00
}
2014-03-26 15:10:17 +04:00
/**
* Computes a hash based on the given configuration .
* This is mostly used to find out whether configurations
* are the same .
*/
2015-03-16 14:18:01 +03:00
public static function makeConfigHash ( $config ) {
2014-03-26 15:10:17 +04:00
$data = json_encode (
array (
2015-08-12 22:03:11 +03:00
'c' => $config [ 'backend' ],
'a' => $config [ 'authMechanism' ],
2014-03-26 15:10:17 +04:00
'm' => $config [ 'mountpoint' ],
2015-03-16 14:18:01 +03:00
'o' => $config [ 'options' ],
'p' => isset ( $config [ 'priority' ]) ? $config [ 'priority' ] : - 1 ,
'mo' => isset ( $config [ 'mountOptions' ]) ? $config [ 'mountOptions' ] : [],
2014-03-26 15:10:17 +04:00
)
);
return hash ( 'md5' , $data );
}
2014-12-11 19:35:11 +03:00
2015-01-27 15:35:31 +03:00
/**
* Add storage id to the storage configurations that did not have any .
*
* @ param string $user user for which to process storage configs
*/
2014-12-11 19:35:11 +03:00
private static function addStorageIdToConfig ( $user ) {
$config = self :: readData ( $user );
$needUpdate = false ;
foreach ( $config as & $applicables ) {
foreach ( $applicables as & $mountPoints ) {
foreach ( $mountPoints as & $options ) {
$needUpdate |= ! isset ( $options [ 'storage_id' ]);
}
}
}
if ( $needUpdate ) {
self :: writeData ( $user , $config );
}
}
2015-01-27 15:35:31 +03:00
/**
* Get storage id from the numeric storage id and set
* it into the given options argument . Only do this
* if there was no storage id set yet .
*
* This might also fail if a storage wasn ' t fully configured yet
* and couldn ' t be mounted , in which case this will simply return false .
*
* @ param array $options storage options
*
* @ return bool true if the storage id was added , false otherwise
*/
2014-12-11 19:35:11 +03:00
private static function addStorageId ( & $options ) {
if ( isset ( $options [ 'storage_id' ])) {
return false ;
}
2015-01-27 15:35:31 +03:00
2015-08-12 22:03:11 +03:00
$service = self :: $appContainer -> query ( 'OCA\Files_External\Service\BackendService' );
$class = $service -> getBackend ( $options [ 'backend' ]) -> getStorageClass ();
2015-01-27 15:35:31 +03:00
try {
/** @var \OC\Files\Storage\Storage $storage */
$storage = new $class ( $options [ 'options' ]);
// TODO: introduce StorageConfigException
} catch ( \Exception $e ) {
// storage might not be fully configured yet (ex: Dropbox)
// note that storage instances aren't supposed to open any connections
// in the constructor, so this exception is likely to be a config exception
return false ;
}
2014-12-11 19:35:11 +03:00
$options [ 'storage_id' ] = $storage -> getCache () -> getNumericStorageId ();
return true ;
}
2012-09-07 16:09:41 +04:00
}