diff options
author | Lukas Reschke <lukas@owncloud.com> | 2016-04-06 11:09:55 +0200 |
---|---|---|
committer | Lukas Reschke <lukas@owncloud.com> | 2016-04-06 11:12:22 +0200 |
commit | c12bb839e197990db86f0062fa6b7ec54aff5121 (patch) | |
tree | f70c0ac4f4113db7c0b5fdde0665c1f510fe6601 /settings/Controller | |
parent | 046506dd146f823499098d0d2b0042072e436469 (diff) | |
download | nextcloud-server-c12bb839e197990db86f0062fa6b7ec54aff5121.tar.gz nextcloud-server-c12bb839e197990db86f0062fa6b7ec54aff5121.zip |
Rename files to be PSR-4 compliant
Diffstat (limited to 'settings/Controller')
-rw-r--r-- | settings/Controller/AppSettingsController.php | 322 | ||||
-rw-r--r-- | settings/Controller/CertificateController.php | 183 | ||||
-rw-r--r-- | settings/Controller/CheckSetupController.php | 350 | ||||
-rw-r--r-- | settings/Controller/EncryptionController.php | 145 | ||||
-rw-r--r-- | settings/Controller/GroupsController.php | 159 | ||||
-rw-r--r-- | settings/Controller/LogSettingsController.php | 109 | ||||
-rw-r--r-- | settings/Controller/MailSettingsController.php | 181 | ||||
-rw-r--r-- | settings/Controller/SecuritySettingsController.php | 70 | ||||
-rw-r--r-- | settings/Controller/UsersController.php | 659 |
9 files changed, 2178 insertions, 0 deletions
diff --git a/settings/Controller/AppSettingsController.php b/settings/Controller/AppSettingsController.php new file mode 100644 index 00000000000..cc69d3130d9 --- /dev/null +++ b/settings/Controller/AppSettingsController.php @@ -0,0 +1,322 @@ +<?php +/** + * @author Joas Schilling <nickvergessen@owncloud.com> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC\Settings\Controller; + +use OC\App\DependencyAnalyzer; +use OC\App\Platform; +use OC\OCSClient; +use OCP\App\IAppManager; +use \OCP\AppFramework\Controller; +use OCP\AppFramework\Http\ContentSecurityPolicy; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\Http\TemplateResponse; +use OCP\ICacheFactory; +use OCP\INavigationManager; +use OCP\IRequest; +use OCP\IL10N; +use OCP\IConfig; + +/** + * @package OC\Settings\Controller + */ +class AppSettingsController extends Controller { + const CAT_ENABLED = 0; + const CAT_DISABLED = 1; + + /** @var \OCP\IL10N */ + private $l10n; + /** @var IConfig */ + private $config; + /** @var \OCP\ICache */ + private $cache; + /** @var INavigationManager */ + private $navigationManager; + /** @var IAppManager */ + private $appManager; + /** @var OCSClient */ + private $ocsClient; + + /** + * @param string $appName + * @param IRequest $request + * @param IL10N $l10n + * @param IConfig $config + * @param ICacheFactory $cache + * @param INavigationManager $navigationManager + * @param IAppManager $appManager + * @param OCSClient $ocsClient + */ + public function __construct($appName, + IRequest $request, + IL10N $l10n, + IConfig $config, + ICacheFactory $cache, + INavigationManager $navigationManager, + IAppManager $appManager, + OCSClient $ocsClient) { + parent::__construct($appName, $request); + $this->l10n = $l10n; + $this->config = $config; + $this->cache = $cache->create($appName); + $this->navigationManager = $navigationManager; + $this->appManager = $appManager; + $this->ocsClient = $ocsClient; + } + + /** + * Enables or disables the display of experimental apps + * @param bool $state + * @return DataResponse + */ + public function changeExperimentalConfigState($state) { + $this->config->setSystemValue('appstore.experimental.enabled', $state); + $this->appManager->clearAppsCache(); + return new DataResponse(); + } + + /** + * @param string|int $category + * @return int + */ + protected function getCategory($category) { + if (is_string($category)) { + foreach ($this->listCategories() as $cat) { + if (isset($cat['ident']) && $cat['ident'] === $category) { + $category = (int) $cat['id']; + break; + } + } + + // Didn't find the category, falling back to enabled + if (is_string($category)) { + $category = self::CAT_ENABLED; + } + } + return (int) $category; + } + + /** + * @NoCSRFRequired + * @param string $category + * @return TemplateResponse + */ + public function viewApps($category = '') { + $categoryId = $this->getCategory($category); + if ($categoryId === self::CAT_ENABLED) { + // Do not use an arbitrary input string, because we put the category in html + $category = 'enabled'; + } + + $params = []; + $params['experimentalEnabled'] = $this->config->getSystemValue('appstore.experimental.enabled', false); + $params['category'] = $category; + $params['appstoreEnabled'] = $this->config->getSystemValue('appstoreenabled', true) === true; + $this->navigationManager->setActiveEntry('core_apps'); + + $templateResponse = new TemplateResponse($this->appName, 'apps', $params, 'user'); + $policy = new ContentSecurityPolicy(); + $policy->addAllowedImageDomain('https://apps.owncloud.com'); + $templateResponse->setContentSecurityPolicy($policy); + + return $templateResponse; + } + + /** + * Get all available categories + * @return array + */ + public function listCategories() { + + if(!is_null($this->cache->get('listCategories'))) { + return $this->cache->get('listCategories'); + } + $categories = [ + ['id' => self::CAT_ENABLED, 'ident' => 'enabled', 'displayName' => (string)$this->l10n->t('Enabled')], + ['id' => self::CAT_DISABLED, 'ident' => 'disabled', 'displayName' => (string)$this->l10n->t('Not enabled')], + ]; + + if($this->ocsClient->isAppStoreEnabled()) { + // apps from external repo via OCS + $ocs = $this->ocsClient->getCategories(\OCP\Util::getVersion()); + if ($ocs) { + foreach($ocs as $k => $v) { + $name = str_replace('ownCloud ', '', $v); + $ident = str_replace(' ', '-', urlencode(strtolower($name))); + $categories[] = [ + 'id' => $k, + 'ident' => $ident, + 'displayName' => $name, + ]; + } + } + } + + $this->cache->set('listCategories', $categories, 3600); + + return $categories; + } + + /** + * Get all available apps in a category + * + * @param string $category + * @param bool $includeUpdateInfo Should we check whether there is an update + * in the app store? + * @return array + */ + public function listApps($category = '', $includeUpdateInfo = true) { + $category = $this->getCategory($category); + $cacheName = 'listApps-' . $category . '-' . (int) $includeUpdateInfo; + + if(!is_null($this->cache->get($cacheName))) { + $apps = $this->cache->get($cacheName); + } else { + switch ($category) { + // installed apps + case 0: + $apps = $this->getInstalledApps($includeUpdateInfo); + usort($apps, function ($a, $b) { + $a = (string)$a['name']; + $b = (string)$b['name']; + if ($a === $b) { + return 0; + } + return ($a < $b) ? -1 : 1; + }); + $version = \OCP\Util::getVersion(); + foreach($apps as $key => $app) { + if(!array_key_exists('level', $app) && array_key_exists('ocsid', $app)) { + $remoteAppEntry = $this->ocsClient->getApplication($app['ocsid'], $version); + + if(is_array($remoteAppEntry) && array_key_exists('level', $remoteAppEntry)) { + $apps[$key]['level'] = $remoteAppEntry['level']; + } + } + } + break; + // not-installed apps + case 1: + $apps = \OC_App::listAllApps(true, $includeUpdateInfo, $this->ocsClient); + $apps = array_filter($apps, function ($app) { + return !$app['active']; + }); + $version = \OCP\Util::getVersion(); + foreach($apps as $key => $app) { + if(!array_key_exists('level', $app) && array_key_exists('ocsid', $app)) { + $remoteAppEntry = $this->ocsClient->getApplication($app['ocsid'], $version); + + if(is_array($remoteAppEntry) && array_key_exists('level', $remoteAppEntry)) { + $apps[$key]['level'] = $remoteAppEntry['level']; + } + } + } + usort($apps, function ($a, $b) { + $a = (string)$a['name']; + $b = (string)$b['name']; + if ($a === $b) { + return 0; + } + return ($a < $b) ? -1 : 1; + }); + break; + default: + $filter = $this->config->getSystemValue('appstore.experimental.enabled', false) ? 'all' : 'approved'; + + $apps = \OC_App::getAppstoreApps($filter, $category, $this->ocsClient); + if (!$apps) { + $apps = array(); + } else { + // don't list installed apps + $installedApps = $this->getInstalledApps(false); + $installedApps = array_map(function ($app) { + if (isset($app['ocsid'])) { + return $app['ocsid']; + } + return $app['id']; + }, $installedApps); + $apps = array_filter($apps, function ($app) use ($installedApps) { + return !in_array($app['id'], $installedApps); + }); + } + + // sort by score + usort($apps, function ($a, $b) { + $a = (int)$a['score']; + $b = (int)$b['score']; + if ($a === $b) { + return 0; + } + return ($a > $b) ? -1 : 1; + }); + break; + } + } + + // fix groups to be an array + $dependencyAnalyzer = new DependencyAnalyzer(new Platform($this->config), $this->l10n); + $apps = array_map(function($app) use ($dependencyAnalyzer) { + + // fix groups + $groups = array(); + if (is_string($app['groups'])) { + $groups = json_decode($app['groups']); + } + $app['groups'] = $groups; + $app['canUnInstall'] = !$app['active'] && $app['removable']; + + // fix licence vs license + if (isset($app['license']) && !isset($app['licence'])) { + $app['licence'] = $app['license']; + } + + // analyse dependencies + $missing = $dependencyAnalyzer->analyze($app); + $app['canInstall'] = empty($missing); + $app['missingDependencies'] = $missing; + + $app['missingMinOwnCloudVersion'] = !isset($app['dependencies']['owncloud']['@attributes']['min-version']); + $app['missingMaxOwnCloudVersion'] = !isset($app['dependencies']['owncloud']['@attributes']['max-version']); + + return $app; + }, $apps); + + $this->cache->set($cacheName, $apps, 300); + + return ['apps' => $apps, 'status' => 'success']; + } + + /** + * @param bool $includeUpdateInfo Should we check whether there is an update + * in the app store? + * @return array + */ + private function getInstalledApps($includeUpdateInfo = true) { + $apps = \OC_App::listAllApps(true, $includeUpdateInfo, $this->ocsClient); + $apps = array_filter($apps, function ($app) { + return $app['active']; + }); + return $apps; + } +} diff --git a/settings/Controller/CertificateController.php b/settings/Controller/CertificateController.php new file mode 100644 index 00000000000..90d0c664d84 --- /dev/null +++ b/settings/Controller/CertificateController.php @@ -0,0 +1,183 @@ +<?php +/** + * @author Björn Schießle <schiessle@owncloud.com> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Robin Appelman <icewind@owncloud.com> + * @author Vincent Petry <pvince81@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC\Settings\Controller; + +use OCP\App\IAppManager; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\ICertificateManager; +use OCP\IL10N; +use OCP\IRequest; + +/** + * @package OC\Settings\Controller + */ +class CertificateController extends Controller { + /** @var ICertificateManager */ + private $userCertificateManager; + /** @var ICertificateManager */ + private $systemCertificateManager; + /** @var IL10N */ + private $l10n; + /** @var IAppManager */ + private $appManager; + + /** + * @param string $appName + * @param IRequest $request + * @param ICertificateManager $userCertificateManager + * @param ICertificateManager $systemCertificateManager + * @param IL10N $l10n + * @param IAppManager $appManager + */ + public function __construct($appName, + IRequest $request, + ICertificateManager $userCertificateManager, + ICertificateManager $systemCertificateManager, + IL10N $l10n, + IAppManager $appManager) { + parent::__construct($appName, $request); + $this->userCertificateManager = $userCertificateManager; + $this->systemCertificateManager = $systemCertificateManager; + $this->l10n = $l10n; + $this->appManager = $appManager; + } + + /** + * Add a new personal root certificate to the users' trust store + * + * @NoAdminRequired + * @NoSubadminRequired + * @return array + */ + public function addPersonalRootCertificate() { + return $this->addCertificate($this->userCertificateManager); + } + + /** + * Add a new root certificate to a trust store + * + * @param ICertificateManager $certificateManager + * @return array + */ + private function addCertificate(ICertificateManager $certificateManager) { + $headers = []; + if ($this->request->isUserAgent([\OC\AppFramework\Http\Request::USER_AGENT_IE_8])) { + // due to upload iframe workaround, need to set content-type to text/plain + $headers['Content-Type'] = 'text/plain'; + } + + if ($this->isCertificateImportAllowed() === false) { + return new DataResponse(['message' => 'Individual certificate management disabled'], Http::STATUS_FORBIDDEN, $headers); + } + + $file = $this->request->getUploadedFile('rootcert_import'); + if (empty($file)) { + return new DataResponse(['message' => 'No file uploaded'], Http::STATUS_UNPROCESSABLE_ENTITY, $headers); + } + + try { + $certificate = $certificateManager->addCertificate(file_get_contents($file['tmp_name']), $file['name']); + return new DataResponse( + [ + 'name' => $certificate->getName(), + 'commonName' => $certificate->getCommonName(), + 'organization' => $certificate->getOrganization(), + 'validFrom' => $certificate->getIssueDate()->getTimestamp(), + 'validTill' => $certificate->getExpireDate()->getTimestamp(), + 'validFromString' => $this->l10n->l('date', $certificate->getIssueDate()), + 'validTillString' => $this->l10n->l('date', $certificate->getExpireDate()), + 'issuer' => $certificate->getIssuerName(), + 'issuerOrganization' => $certificate->getIssuerOrganization(), + ], + Http::STATUS_OK, + $headers + ); + } catch (\Exception $e) { + return new DataResponse('An error occurred.', Http::STATUS_UNPROCESSABLE_ENTITY, $headers); + } + } + + /** + * Removes a personal root certificate from the users' trust store + * + * @NoAdminRequired + * @NoSubadminRequired + * @param string $certificateIdentifier + * @return DataResponse + */ + public function removePersonalRootCertificate($certificateIdentifier) { + + if ($this->isCertificateImportAllowed() === false) { + return new DataResponse('Individual certificate management disabled', Http::STATUS_FORBIDDEN); + } + + $this->userCertificateManager->removeCertificate($certificateIdentifier); + return new DataResponse(); + } + + /** + * check if certificate import is allowed + * + * @return bool + */ + protected function isCertificateImportAllowed() { + $externalStorageEnabled = $this->appManager->isEnabledForUser('files_external'); + if ($externalStorageEnabled) { + /** @var \OCA\Files_External\Service\BackendService $backendService */ + $backendService = \OC_Mount_Config::$app->getContainer()->query('\OCA\Files_External\Service\BackendService'); + if ($backendService->isUserMountingAllowed()) { + return true; + } + } + return false; + } + + /** + * Add a new personal root certificate to the system's trust store + * + * @return array + */ + public function addSystemRootCertificate() { + return $this->addCertificate($this->systemCertificateManager); + } + + /** + * Removes a personal root certificate from the users' trust store + * + * @param string $certificateIdentifier + * @return DataResponse + */ + public function removeSystemRootCertificate($certificateIdentifier) { + + if ($this->isCertificateImportAllowed() === false) { + return new DataResponse('Individual certificate management disabled', Http::STATUS_FORBIDDEN); + } + + $this->systemCertificateManager->removeCertificate($certificateIdentifier); + return new DataResponse(); + } +} diff --git a/settings/Controller/CheckSetupController.php b/settings/Controller/CheckSetupController.php new file mode 100644 index 00000000000..cfdfa5021bc --- /dev/null +++ b/settings/Controller/CheckSetupController.php @@ -0,0 +1,350 @@ +<?php +/** + * @author Joas Schilling <nickvergessen@owncloud.com> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Robin McCorkell <robin@mccorkell.me.uk> + * @author Roeland Jago Douma <rullzer@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC\Settings\Controller; + +use GuzzleHttp\Exception\ClientException; +use OC\AppFramework\Http; +use OC\IntegrityCheck\Checker; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\DataDisplayResponse; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\Http\RedirectResponse; +use OCP\Http\Client\IClientService; +use OCP\IConfig; +use OCP\IL10N; +use OCP\IRequest; +use OC_Util; +use OCP\IURLGenerator; + +/** + * @package OC\Settings\Controller + */ +class CheckSetupController extends Controller { + /** @var IConfig */ + private $config; + /** @var IClientService */ + private $clientService; + /** @var \OC_Util */ + private $util; + /** @var IURLGenerator */ + private $urlGenerator; + /** @var IL10N */ + private $l10n; + /** @var Checker */ + private $checker; + + /** + * @param string $AppName + * @param IRequest $request + * @param IConfig $config + * @param IClientService $clientService + * @param IURLGenerator $urlGenerator + * @param \OC_Util $util + * @param IL10N $l10n + * @param Checker $checker + */ + public function __construct($AppName, + IRequest $request, + IConfig $config, + IClientService $clientService, + IURLGenerator $urlGenerator, + \OC_Util $util, + IL10N $l10n, + Checker $checker) { + parent::__construct($AppName, $request); + $this->config = $config; + $this->clientService = $clientService; + $this->util = $util; + $this->urlGenerator = $urlGenerator; + $this->l10n = $l10n; + $this->checker = $checker; + } + + /** + * Checks if the ownCloud server can connect to the internet using HTTPS and HTTP + * @return bool + */ + private function isInternetConnectionWorking() { + if ($this->config->getSystemValue('has_internet_connection', true) === false) { + return false; + } + + try { + $client = $this->clientService->newClient(); + $client->get('https://www.owncloud.org/'); + $client->get('http://www.owncloud.org/'); + return true; + } catch (\Exception $e) { + return false; + } + } + + /** + * Checks whether a local memcache is installed or not + * @return bool + */ + private function isMemcacheConfigured() { + return $this->config->getSystemValue('memcache.local', null) !== null; + } + + /** + * Whether /dev/urandom is available to the PHP controller + * + * @return bool + */ + private function isUrandomAvailable() { + if(@file_exists('/dev/urandom')) { + $file = fopen('/dev/urandom', 'rb'); + if($file) { + fclose($file); + return true; + } + } + + return false; + } + + /** + * Public for the sake of unit-testing + * + * @return array + */ + protected function getCurlVersion() { + return curl_version(); + } + + /** + * Check if the used SSL lib is outdated. Older OpenSSL and NSS versions do + * have multiple bugs which likely lead to problems in combination with + * functionality required by ownCloud such as SNI. + * + * @link https://github.com/owncloud/core/issues/17446#issuecomment-122877546 + * @link https://bugzilla.redhat.com/show_bug.cgi?id=1241172 + * @return string + */ + private function isUsedTlsLibOutdated() { + // Appstore is disabled by default in EE + $appStoreDefault = false; + if (\OC_Util::getEditionString() === '') { + $appStoreDefault = true; + } + + // Don't run check when: + // 1. Server has `has_internet_connection` set to false + // 2. AppStore AND S2S is disabled + if(!$this->config->getSystemValue('has_internet_connection', true)) { + return ''; + } + if(!$this->config->getSystemValue('appstoreenabled', $appStoreDefault) + && $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'no' + && $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes') === 'no') { + return ''; + } + + $versionString = $this->getCurlVersion(); + if(isset($versionString['ssl_version'])) { + $versionString = $versionString['ssl_version']; + } else { + return ''; + } + + $features = (string)$this->l10n->t('installing and updating apps via the app store or Federated Cloud Sharing'); + if(!$this->config->getSystemValue('appstoreenabled', $appStoreDefault)) { + $features = (string)$this->l10n->t('Federated Cloud Sharing'); + } + + // Check if at least OpenSSL after 1.01d or 1.0.2b + if(strpos($versionString, 'OpenSSL/') === 0) { + $majorVersion = substr($versionString, 8, 5); + $patchRelease = substr($versionString, 13, 6); + + if(($majorVersion === '1.0.1' && ord($patchRelease) < ord('d')) || + ($majorVersion === '1.0.2' && ord($patchRelease) < ord('b'))) { + return (string) $this->l10n->t('cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably.', ['OpenSSL', $versionString, $features]); + } + } + + // Check if NSS and perform heuristic check + if(strpos($versionString, 'NSS/') === 0) { + try { + $firstClient = $this->clientService->newClient(); + $firstClient->get('https://www.owncloud.org/'); + + $secondClient = $this->clientService->newClient(); + $secondClient->get('https://owncloud.org/'); + } catch (ClientException $e) { + if($e->getResponse()->getStatusCode() === 400) { + return (string) $this->l10n->t('cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably.', ['NSS', $versionString, $features]); + } + } + } + + return ''; + } + + /** + * Whether the php version is still supported (at time of release) + * according to: https://secure.php.net/supported-versions.php + * + * @return array + */ + private function isPhpSupported() { + $eol = false; + + //PHP 5.4 is EOL on 14 Sep 2015 + if (version_compare(PHP_VERSION, '5.5.0') === -1) { + $eol = true; + } + + return ['eol' => $eol, 'version' => PHP_VERSION]; + } + + /** + * Check if the reverse proxy configuration is working as expected + * + * @return bool + */ + private function forwardedForHeadersWorking() { + $trustedProxies = $this->config->getSystemValue('trusted_proxies', []); + $remoteAddress = $this->request->getRemoteAddress(); + + if (is_array($trustedProxies) && in_array($remoteAddress, $trustedProxies)) { + return false; + } + + // either not enabled or working correctly + return true; + } + + /** + * Checks if the correct memcache module for PHP is installed. Only + * fails if memcached is configured and the working module is not installed. + * + * @return bool + */ + private function isCorrectMemcachedPHPModuleInstalled() { + if ($this->config->getSystemValue('memcache.distributed', null) !== '\OC\Memcache\Memcached') { + return true; + } + + // there are two different memcached modules for PHP + // we only support memcached and not memcache + // https://code.google.com/p/memcached/wiki/PHPClientComparison + return !(!extension_loaded('memcached') && extension_loaded('memcache')); + } + + /** + * @return RedirectResponse + */ + public function rescanFailedIntegrityCheck() { + $this->checker->runInstanceVerification(); + return new RedirectResponse( + $this->urlGenerator->linkToRoute('settings_admin') + ); + } + + /** + * @NoCSRFRequired + * @return DataResponse + */ + public function getFailedIntegrityCheckFiles() { + if(!$this->checker->isCodeCheckEnforced()) { + return new DataDisplayResponse('Integrity checker has been disabled. Integrity cannot be verified.'); + } + + $completeResults = $this->checker->getResults(); + + if(!empty($completeResults)) { + $formattedTextResponse = 'Technical information +===================== +The following list covers which files have failed the integrity check. Please read +the previous linked documentation to learn more about the errors and how to fix +them. + +Results +======= +'; + foreach($completeResults as $context => $contextResult) { + $formattedTextResponse .= "- $context\n"; + + foreach($contextResult as $category => $result) { + $formattedTextResponse .= "\t- $category\n"; + if($category !== 'EXCEPTION') { + foreach ($result as $key => $results) { + $formattedTextResponse .= "\t\t- $key\n"; + } + } else { + foreach ($result as $key => $results) { + $formattedTextResponse .= "\t\t- $results\n"; + } + } + + } + } + + $formattedTextResponse .= ' +Raw output +========== +'; + $formattedTextResponse .= print_r($completeResults, true); + } else { + $formattedTextResponse = 'No errors have been found.'; + } + + + $response = new DataDisplayResponse( + $formattedTextResponse, + Http::STATUS_OK, + [ + 'Content-Type' => 'text/plain', + ] + ); + + return $response; + } + + /** + * @return DataResponse + */ + public function check() { + return new DataResponse( + [ + 'serverHasInternetConnection' => $this->isInternetConnectionWorking(), + 'isMemcacheConfigured' => $this->isMemcacheConfigured(), + 'memcacheDocs' => $this->urlGenerator->linkToDocs('admin-performance'), + 'isUrandomAvailable' => $this->isUrandomAvailable(), + 'securityDocs' => $this->urlGenerator->linkToDocs('admin-security'), + 'isUsedTlsLibOutdated' => $this->isUsedTlsLibOutdated(), + 'phpSupported' => $this->isPhpSupported(), + 'forwardedForHeadersWorking' => $this->forwardedForHeadersWorking(), + 'reverseProxyDocs' => $this->urlGenerator->linkToDocs('admin-reverse-proxy'), + 'isCorrectMemcachedPHPModuleInstalled' => $this->isCorrectMemcachedPHPModuleInstalled(), + 'hasPassedCodeIntegrityCheck' => $this->checker->hasPassedCheck(), + 'codeIntegrityCheckerDocumentation' => $this->urlGenerator->linkToDocs('admin-code-integrity'), + ] + ); + } +} diff --git a/settings/Controller/EncryptionController.php b/settings/Controller/EncryptionController.php new file mode 100644 index 00000000000..504448a5a2c --- /dev/null +++ b/settings/Controller/EncryptionController.php @@ -0,0 +1,145 @@ +<?php +/** + * @author Björn Schießle <schiessle@owncloud.com> + * @author Lukas Reschke <lukas@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + + +namespace OC\Settings\Controller; +use OC\Files\View; +use OCA\Encryption\Migration; +use OCP\IL10N; +use OCP\AppFramework\Controller; +use OCP\ILogger; +use OCP\IRequest; +use OCP\IConfig; +use OC\DB\Connection; +use OCP\IUserManager; + +/** + * @package OC\Settings\Controller + */ +class EncryptionController extends Controller { + + /** @var \OCP\IL10N */ + private $l10n; + + /** @var Connection */ + private $connection; + + /** @var IConfig */ + private $config; + + /** @var IUserManager */ + private $userManager; + + /** @var View */ + private $view; + + /** @var ILogger */ + private $logger; + + /** + * @param string $appName + * @param IRequest $request + * @param \OCP\IL10N $l10n + * @param \OCP\IConfig $config + * @param \OC\DB\Connection $connection + * @param IUserManager $userManager + * @param View $view + * @param ILogger $logger + */ + public function __construct($appName, + IRequest $request, + IL10N $l10n, + IConfig $config, + Connection $connection, + IUserManager $userManager, + View $view, + ILogger $logger) { + parent::__construct($appName, $request); + $this->l10n = $l10n; + $this->config = $config; + $this->connection = $connection; + $this->view = $view; + $this->userManager = $userManager; + $this->logger = $logger; + } + + /** + * @param IConfig $config + * @param View $view + * @param Connection $connection + * @param ILogger $logger + * @return Migration + */ + protected function getMigration(IConfig $config, + View $view, + Connection $connection, + ILogger $logger) { + return new Migration($config, $view, $connection, $logger); + } + + /** + * start migration + * + * @return array + */ + public function startMigration() { + // allow as long execution on the web server as possible + set_time_limit(0); + + try { + + $migration = $this->getMigration($this->config, $this->view, $this->connection, $this->logger); + $migration->reorganizeSystemFolderStructure(); + $migration->updateDB(); + + foreach ($this->userManager->getBackends() as $backend) { + $limit = 500; + $offset = 0; + do { + $users = $backend->getUsers('', $limit, $offset); + foreach ($users as $user) { + $migration->reorganizeFolderStructureForUser($user); + } + $offset += $limit; + } while (count($users) >= $limit); + } + + $migration->finalCleanUp(); + + } catch (\Exception $e) { + return [ + 'data' => [ + 'message' => (string)$this->l10n->t('A problem occurred, please check your log files (Error: %s)', [$e->getMessage()]), + ], + 'status' => 'error', + ]; + } + + return [ + 'data' => [ + 'message' => (string) $this->l10n->t('Migration Completed'), + ], + 'status' => 'success', + ]; + } + +} diff --git a/settings/Controller/GroupsController.php b/settings/Controller/GroupsController.php new file mode 100644 index 00000000000..bb8e6755d41 --- /dev/null +++ b/settings/Controller/GroupsController.php @@ -0,0 +1,159 @@ +<?php +/** + * @author Joas Schilling <nickvergessen@owncloud.com> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC\Settings\Controller; + +use OC\AppFramework\Http; +use OC\Group\MetaData; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\DataResponse; +use OCP\IGroupManager; +use OCP\IL10N; +use OCP\IRequest; +use OCP\IUserSession; + +/** + * @package OC\Settings\Controller + */ +class GroupsController extends Controller { + /** @var IGroupManager */ + private $groupManager; + /** @var IL10N */ + private $l10n; + /** @var IUserSession */ + private $userSession; + /** @var bool */ + private $isAdmin; + + /** + * @param string $appName + * @param IRequest $request + * @param IGroupManager $groupManager + * @param IUserSession $userSession + * @param bool $isAdmin + * @param IL10N $l10n + */ + public function __construct($appName, + IRequest $request, + IGroupManager $groupManager, + IUserSession $userSession, + $isAdmin, + IL10N $l10n) { + parent::__construct($appName, $request); + $this->groupManager = $groupManager; + $this->userSession = $userSession; + $this->isAdmin = $isAdmin; + $this->l10n = $l10n; + } + + /** + * @NoAdminRequired + * + * @param string $pattern + * @param bool $filterGroups + * @param int $sortGroups + * @return DataResponse + */ + public function index($pattern = '', $filterGroups = false, $sortGroups = MetaData::SORT_USERCOUNT) { + $groupPattern = $filterGroups ? $pattern : ''; + + $groupsInfo = new MetaData( + $this->userSession->getUser()->getUID(), + $this->isAdmin, + $this->groupManager, + $this->userSession + ); + $groupsInfo->setSorting($sortGroups); + list($adminGroups, $groups) = $groupsInfo->get($groupPattern, $pattern); + + return new DataResponse( + array( + 'data' => array('adminGroups' => $adminGroups, 'groups' => $groups) + ) + ); + } + + /** + * @param string $id + * @return DataResponse + */ + public function create($id) { + if($this->groupManager->groupExists($id)) { + return new DataResponse( + array( + 'message' => (string)$this->l10n->t('Group already exists.') + ), + Http::STATUS_CONFLICT + ); + } + if($this->groupManager->createGroup($id)) { + return new DataResponse( + array( + 'groupname' => $id + ), + Http::STATUS_CREATED + ); + } + + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Unable to add group.') + ) + ), + Http::STATUS_FORBIDDEN + ); + } + + /** + * @param string $id + * @return DataResponse + */ + public function destroy($id) { + $group = $this->groupManager->get($id); + if ($group) { + if ($group->delete()) { + return new DataResponse( + array( + 'status' => 'success', + 'data' => array( + 'groupname' => $id + ) + ), + Http::STATUS_NO_CONTENT + ); + } + } + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Unable to delete group.') + ), + ), + Http::STATUS_FORBIDDEN + ); + } + +} diff --git a/settings/Controller/LogSettingsController.php b/settings/Controller/LogSettingsController.php new file mode 100644 index 00000000000..c0c9ee04ca3 --- /dev/null +++ b/settings/Controller/LogSettingsController.php @@ -0,0 +1,109 @@ +<?php +/** + * @author Georg Ehrke <georg@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC\Settings\Controller; + +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\JSONResponse; +use OCP\AppFramework\Http\StreamResponse; +use OCP\IL10N; +use OCP\IRequest; +use OCP\IConfig; + +/** + * Class LogSettingsController + * + * @package OC\Settings\Controller + */ +class LogSettingsController extends Controller { + /** + * @var \OCP\IConfig + */ + private $config; + + /** + * @var \OCP\IL10N + */ + private $l10n; + + /** + * @param string $appName + * @param IRequest $request + * @param IConfig $config + */ + public function __construct($appName, + IRequest $request, + IConfig $config, + IL10N $l10n) { + parent::__construct($appName, $request); + $this->config = $config; + $this->l10n = $l10n; + } + + /** + * set log level for logger + * + * @param int $level + * @return JSONResponse + */ + public function setLogLevel($level) { + if ($level < 0 || $level > 4) { + return new JSONResponse([ + 'message' => (string) $this->l10n->t('log-level out of allowed range'), + ], Http::STATUS_BAD_REQUEST); + } + + $this->config->setSystemValue('loglevel', $level); + return new JSONResponse([ + 'level' => $level, + ]); + } + + /** + * get log entries from logfile + * + * @param int $count + * @param int $offset + * @return JSONResponse + */ + public function getEntries($count=50, $offset=0) { + return new JSONResponse([ + 'data' => \OC_Log_Owncloud::getEntries($count, $offset), + 'remain' => count(\OC_Log_Owncloud::getEntries(1, $offset + $count)) !== 0, + ]); + } + + /** + * download logfile + * + * @NoCSRFRequired + * + * @return StreamResponse + */ + public function download() { + $resp = new StreamResponse(\OC_Log_Owncloud::getLogFilePath()); + $resp->addHeader('Content-Disposition', 'attachment; filename="owncloud.log"'); + return $resp; + } +} diff --git a/settings/Controller/MailSettingsController.php b/settings/Controller/MailSettingsController.php new file mode 100644 index 00000000000..dbba4bd9bc0 --- /dev/null +++ b/settings/Controller/MailSettingsController.php @@ -0,0 +1,181 @@ +<?php +/** + * @author Joas Schilling <nickvergessen@owncloud.com> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC\Settings\Controller; + +use OC\User\Session; +use \OCP\AppFramework\Controller; +use OCP\IRequest; +use OCP\IL10N; +use OCP\IConfig; +use OCP\Mail\IMailer; +use OCP\Mail\IMessage; + +/** + * @package OC\Settings\Controller + */ +class MailSettingsController extends Controller { + + /** @var \OCP\IL10N */ + private $l10n; + /** @var \OCP\IConfig */ + private $config; + /** @var Session */ + private $userSession; + /** @var \OC_Defaults */ + private $defaults; + /** @var IMailer */ + private $mailer; + /** @var string */ + private $defaultMailAddress; + + /** + * @param string $appName + * @param IRequest $request + * @param IL10N $l10n + * @param IConfig $config + * @param Session $userSession + * @param \OC_Defaults $defaults + * @param IMailer $mailer + * @param string $defaultMailAddress + */ + public function __construct($appName, + IRequest $request, + IL10N $l10n, + IConfig $config, + Session $userSession, + \OC_Defaults $defaults, + IMailer $mailer, + $defaultMailAddress) { + parent::__construct($appName, $request); + $this->l10n = $l10n; + $this->config = $config; + $this->userSession = $userSession; + $this->defaults = $defaults; + $this->mailer = $mailer; + $this->defaultMailAddress = $defaultMailAddress; + } + + /** + * Sets the email settings + * @param string $mail_domain + * @param string $mail_from_address + * @param string $mail_smtpmode + * @param string $mail_smtpsecure + * @param string $mail_smtphost + * @param string $mail_smtpauthtype + * @param int $mail_smtpauth + * @param string $mail_smtpport + * @return array + */ + public function setMailSettings($mail_domain, + $mail_from_address, + $mail_smtpmode, + $mail_smtpsecure, + $mail_smtphost, + $mail_smtpauthtype, + $mail_smtpauth, + $mail_smtpport) { + + $params = get_defined_vars(); + $configs = []; + foreach($params as $key => $value) { + $configs[$key] = (empty($value)) ? null : $value; + } + + // Delete passwords from config in case no auth is specified + if ($params['mail_smtpauth'] !== 1) { + $configs['mail_smtpname'] = null; + $configs['mail_smtppassword'] = null; + } + + $this->config->setSystemValues($configs); + + return array('data' => + array('message' => + (string) $this->l10n->t('Saved') + ), + 'status' => 'success' + ); + } + + /** + * Store the credentials used for SMTP in the config + * @param string $mail_smtpname + * @param string $mail_smtppassword + * @return array + */ + public function storeCredentials($mail_smtpname, $mail_smtppassword) { + $this->config->setSystemValues([ + 'mail_smtpname' => $mail_smtpname, + 'mail_smtppassword' => $mail_smtppassword, + ]); + + return array('data' => + array('message' => + (string) $this->l10n->t('Saved') + ), + 'status' => 'success' + ); + } + + /** + * Send a mail to test the settings + * @return array + */ + public function sendTestMail() { + $email = $this->config->getUserValue($this->userSession->getUser()->getUID(), $this->appName, 'email', ''); + if (!empty($email)) { + try { + $message = $this->mailer->createMessage(); + $message->setTo([$email => $this->userSession->getUser()->getDisplayName()]); + $message->setFrom([$this->defaultMailAddress]); + $message->setSubject($this->l10n->t('test email settings')); + $message->setPlainBody('If you received this email, the settings seem to be correct.'); + $this->mailer->send($message); + } catch (\Exception $e) { + return [ + 'data' => [ + 'message' => (string) $this->l10n->t('A problem occurred while sending the email. Please revise your settings. (Error: %s)', [$e->getMessage()]), + ], + 'status' => 'error', + ]; + } + + return array('data' => + array('message' => + (string) $this->l10n->t('Email sent') + ), + 'status' => 'success' + ); + } + + return array('data' => + array('message' => + (string) $this->l10n->t('You need to set your user email before being able to send test emails.'), + ), + 'status' => 'error' + ); + } + +} diff --git a/settings/Controller/SecuritySettingsController.php b/settings/Controller/SecuritySettingsController.php new file mode 100644 index 00000000000..d7274d6bcb2 --- /dev/null +++ b/settings/Controller/SecuritySettingsController.php @@ -0,0 +1,70 @@ +<?php +/** + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC\Settings\Controller; + +use \OCP\AppFramework\Controller; +use OCP\IRequest; +use OCP\IConfig; + +/** + * @package OC\Settings\Controller + */ +class SecuritySettingsController extends Controller { + /** @var \OCP\IConfig */ + private $config; + + /** + * @param string $appName + * @param IRequest $request + * @param IConfig $config + */ + public function __construct($appName, + IRequest $request, + IConfig $config) { + parent::__construct($appName, $request); + $this->config = $config; + } + + /** + * @return array + */ + protected function returnSuccess() { + return array( + 'status' => 'success' + ); + } + + /** + * Add a new trusted domain + * @param string $newTrustedDomain The newly to add trusted domain + * @return array + */ + public function trustedDomains($newTrustedDomain) { + $trustedDomains = $this->config->getSystemValue('trusted_domains'); + $trustedDomains[] = $newTrustedDomain; + $this->config->setSystemValue('trusted_domains', $trustedDomains); + + return $this->returnSuccess(); + } + +} diff --git a/settings/Controller/UsersController.php b/settings/Controller/UsersController.php new file mode 100644 index 00000000000..f5b7f2d2e5d --- /dev/null +++ b/settings/Controller/UsersController.php @@ -0,0 +1,659 @@ +<?php +/** + * @author Arthur Schiwon <blizzz@owncloud.com> + * @author Clark Tomlinson <fallen013@gmail.com> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Robin Appelman <icewind@owncloud.com> + * @author Roeland Jago Douma <rullzer@owncloud.com> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * @author Vincent Petry <pvince81@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC\Settings\Controller; + +use OC\AppFramework\Http; +use OC\User\User; +use OCP\App\IAppManager; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\Http\TemplateResponse; +use OCP\IConfig; +use OCP\IGroupManager; +use OCP\IL10N; +use OCP\ILogger; +use OCP\IRequest; +use OCP\IURLGenerator; +use OCP\IUser; +use OCP\IUserManager; +use OCP\IUserSession; +use OCP\Mail\IMailer; +use OCP\IAvatarManager; + +/** + * @package OC\Settings\Controller + */ +class UsersController extends Controller { + /** @var IL10N */ + private $l10n; + /** @var IUserSession */ + private $userSession; + /** @var bool */ + private $isAdmin; + /** @var IUserManager */ + private $userManager; + /** @var IGroupManager */ + private $groupManager; + /** @var IConfig */ + private $config; + /** @var ILogger */ + private $log; + /** @var \OC_Defaults */ + private $defaults; + /** @var IMailer */ + private $mailer; + /** @var string */ + private $fromMailAddress; + /** @var IURLGenerator */ + private $urlGenerator; + /** @var bool contains the state of the encryption app */ + private $isEncryptionAppEnabled; + /** @var bool contains the state of the admin recovery setting */ + private $isRestoreEnabled = false; + /** @var IAvatarManager */ + private $avatarManager; + + /** + * @param string $appName + * @param IRequest $request + * @param IUserManager $userManager + * @param IGroupManager $groupManager + * @param IUserSession $userSession + * @param IConfig $config + * @param bool $isAdmin + * @param IL10N $l10n + * @param ILogger $log + * @param \OC_Defaults $defaults + * @param IMailer $mailer + * @param string $fromMailAddress + * @param IURLGenerator $urlGenerator + * @param IAppManager $appManager + */ + public function __construct($appName, + IRequest $request, + IUserManager $userManager, + IGroupManager $groupManager, + IUserSession $userSession, + IConfig $config, + $isAdmin, + IL10N $l10n, + ILogger $log, + \OC_Defaults $defaults, + IMailer $mailer, + $fromMailAddress, + IURLGenerator $urlGenerator, + IAppManager $appManager, + IAvatarManager $avatarManager) { + parent::__construct($appName, $request); + $this->userManager = $userManager; + $this->groupManager = $groupManager; + $this->userSession = $userSession; + $this->config = $config; + $this->isAdmin = $isAdmin; + $this->l10n = $l10n; + $this->log = $log; + $this->defaults = $defaults; + $this->mailer = $mailer; + $this->fromMailAddress = $fromMailAddress; + $this->urlGenerator = $urlGenerator; + $this->avatarManager = $avatarManager; + + // check for encryption state - TODO see formatUserForIndex + $this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption'); + if($this->isEncryptionAppEnabled) { + // putting this directly in empty is possible in PHP 5.5+ + $result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0); + $this->isRestoreEnabled = !empty($result); + } + } + + /** + * @param IUser $user + * @param array $userGroups + * @return array + */ + private function formatUserForIndex(IUser $user, array $userGroups = null) { + + // TODO: eliminate this encryption specific code below and somehow + // hook in additional user info from other apps + + // recovery isn't possible if admin or user has it disabled and encryption + // is enabled - so we eliminate the else paths in the conditional tree + // below + $restorePossible = false; + + if ($this->isEncryptionAppEnabled) { + if ($this->isRestoreEnabled) { + // check for the users recovery setting + $recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0'); + // method call inside empty is possible with PHP 5.5+ + $recoveryModeEnabled = !empty($recoveryMode); + if ($recoveryModeEnabled) { + // user also has recovery mode enabled + $restorePossible = true; + } + } + } else { + // recovery is possible if encryption is disabled (plain files are + // available) + $restorePossible = true; + } + + $subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user); + foreach($subAdminGroups as $key => $subAdminGroup) { + $subAdminGroups[$key] = $subAdminGroup->getGID(); + } + + $displayName = $user->getEMailAddress(); + if (is_null($displayName)) { + $displayName = ''; + } + + $avatarAvailable = false; + if ($this->config->getSystemValue('enable_avatars', true) === true) { + try { + $avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists(); + } catch (\Exception $e) { + //No avatar yet + } + } + + return [ + 'name' => $user->getUID(), + 'displayname' => $user->getDisplayName(), + 'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups, + 'subadmin' => $subAdminGroups, + 'quota' => $user->getQuota(), + 'storageLocation' => $user->getHome(), + 'lastLogin' => $user->getLastLogin() * 1000, + 'backend' => $user->getBackendClassName(), + 'email' => $displayName, + 'isRestoreDisabled' => !$restorePossible, + 'isAvatarAvailable' => $avatarAvailable, + ]; + } + + /** + * @param array $userIDs Array with schema [$uid => $displayName] + * @return IUser[] + */ + private function getUsersForUID(array $userIDs) { + $users = []; + foreach ($userIDs as $uid => $displayName) { + $users[$uid] = $this->userManager->get($uid); + } + return $users; + } + + /** + * @NoAdminRequired + * + * @param int $offset + * @param int $limit + * @param string $gid GID to filter for + * @param string $pattern Pattern to search for in the username + * @param string $backend Backend to filter for (class-name) + * @return DataResponse + * + * TODO: Tidy up and write unit tests - code is mainly static method calls + */ + public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') { + // FIXME: The JS sends the group '_everyone' instead of no GID for the "all users" group. + if($gid === '_everyone') { + $gid = ''; + } + + // Remove backends + if(!empty($backend)) { + $activeBackends = $this->userManager->getBackends(); + $this->userManager->clearBackends(); + foreach($activeBackends as $singleActiveBackend) { + if($backend === get_class($singleActiveBackend)) { + $this->userManager->registerBackend($singleActiveBackend); + break; + } + } + } + + $users = []; + if ($this->isAdmin) { + + if($gid !== '') { + $batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset)); + } else { + $batch = $this->userManager->search($pattern, $limit, $offset); + } + + foreach ($batch as $user) { + $users[] = $this->formatUserForIndex($user); + } + + } else { + $subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser()); + // New class returns IGroup[] so convert back + $gids = []; + foreach ($subAdminOfGroups as $group) { + $gids[] = $group->getGID(); + } + $subAdminOfGroups = $gids; + + // Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group + if($gid !== '' && !in_array($gid, $subAdminOfGroups)) { + $gid = ''; + } + + // Batch all groups the user is subadmin of when a group is specified + $batch = []; + if($gid === '') { + foreach($subAdminOfGroups as $group) { + $groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset); + + foreach($groupUsers as $uid => $displayName) { + $batch[$uid] = $displayName; + } + } + } else { + $batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset); + } + $batch = $this->getUsersForUID($batch); + + foreach ($batch as $user) { + // Only add the groups, this user is a subadmin of + $userGroups = array_values(array_intersect( + $this->groupManager->getUserGroupIds($user), + $subAdminOfGroups + )); + $users[] = $this->formatUserForIndex($user, $userGroups); + } + } + + return new DataResponse($users); + } + + /** + * @NoAdminRequired + * + * @param string $username + * @param string $password + * @param array $groups + * @param string $email + * @return DataResponse + */ + public function create($username, $password, array $groups=array(), $email='') { + if($email !== '' && !$this->mailer->validateMailAddress($email)) { + return new DataResponse( + array( + 'message' => (string)$this->l10n->t('Invalid mail address') + ), + Http::STATUS_UNPROCESSABLE_ENTITY + ); + } + + $currentUser = $this->userSession->getUser(); + + if (!$this->isAdmin) { + if (!empty($groups)) { + foreach ($groups as $key => $group) { + $groupObject = $this->groupManager->get($group); + if($groupObject === null) { + unset($groups[$key]); + continue; + } + + if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) { + unset($groups[$key]); + } + } + } + + if (empty($groups)) { + $groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($currentUser); + // New class returns IGroup[] so convert back + $gids = []; + foreach ($groups as $group) { + $gids[] = $group->getGID(); + } + $groups = $gids; + } + } + + if ($this->userManager->userExists($username)) { + return new DataResponse( + array( + 'message' => (string)$this->l10n->t('A user with that name already exists.') + ), + Http::STATUS_CONFLICT + ); + } + + try { + $user = $this->userManager->createUser($username, $password); + } catch (\Exception $exception) { + return new DataResponse( + array( + 'message' => (string)$this->l10n->t('Unable to create user.') + ), + Http::STATUS_FORBIDDEN + ); + } + + if($user instanceof User) { + if($groups !== null) { + foreach($groups as $groupName) { + $group = $this->groupManager->get($groupName); + + if(empty($group)) { + $group = $this->groupManager->createGroup($groupName); + } + $group->addUser($user); + } + } + /** + * Send new user mail only if a mail is set + */ + if($email !== '') { + $user->setEMailAddress($email); + + // data for the mail template + $mailData = array( + 'username' => $username, + 'url' => $this->urlGenerator->getAbsoluteURL('/') + ); + + $mail = new TemplateResponse('settings', 'email.new_user', $mailData, 'blank'); + $mailContent = $mail->render(); + + $mail = new TemplateResponse('settings', 'email.new_user_plain_text', $mailData, 'blank'); + $plainTextMailContent = $mail->render(); + + $subject = $this->l10n->t('Your %s account was created', [$this->defaults->getName()]); + + try { + $message = $this->mailer->createMessage(); + $message->setTo([$email => $username]); + $message->setSubject($subject); + $message->setHtmlBody($mailContent); + $message->setPlainBody($plainTextMailContent); + $message->setFrom([$this->fromMailAddress => $this->defaults->getName()]); + $this->mailer->send($message); + } catch(\Exception $e) { + $this->log->error("Can't send new user mail to $email: " . $e->getMessage(), array('app' => 'settings')); + } + } + // fetch users groups + $userGroups = $this->groupManager->getUserGroupIds($user); + + return new DataResponse( + $this->formatUserForIndex($user, $userGroups), + Http::STATUS_CREATED + ); + } + + return new DataResponse( + array( + 'message' => (string)$this->l10n->t('Unable to create user.') + ), + Http::STATUS_FORBIDDEN + ); + + } + + /** + * @NoAdminRequired + * + * @param string $id + * @return DataResponse + */ + public function destroy($id) { + $userId = $this->userSession->getUser()->getUID(); + $user = $this->userManager->get($id); + + if($userId === $id) { + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Unable to delete user.') + ) + ), + Http::STATUS_FORBIDDEN + ); + } + + if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) { + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Authentication error') + ) + ), + Http::STATUS_FORBIDDEN + ); + } + + if($user) { + if($user->delete()) { + return new DataResponse( + array( + 'status' => 'success', + 'data' => array( + 'username' => $id + ) + ), + Http::STATUS_NO_CONTENT + ); + } + } + + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Unable to delete user.') + ) + ), + Http::STATUS_FORBIDDEN + ); + } + + /** + * Set the mail address of a user + * + * @NoAdminRequired + * @NoSubadminRequired + * + * @param string $id + * @param string $mailAddress + * @return DataResponse + */ + public function setMailAddress($id, $mailAddress) { + $userId = $this->userSession->getUser()->getUID(); + $user = $this->userManager->get($id); + + if($userId !== $id + && !$this->isAdmin + && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) { + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Forbidden') + ) + ), + Http::STATUS_FORBIDDEN + ); + } + + if($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) { + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Invalid mail address') + ) + ), + Http::STATUS_UNPROCESSABLE_ENTITY + ); + } + + if(!$user){ + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Invalid user') + ) + ), + Http::STATUS_UNPROCESSABLE_ENTITY + ); + } + + // this is the only permission a backend provides and is also used + // for the permission of setting a email address + if(!$user->canChangeDisplayName()){ + return new DataResponse( + array( + 'status' => 'error', + 'data' => array( + 'message' => (string)$this->l10n->t('Unable to change mail address') + ) + ), + Http::STATUS_FORBIDDEN + ); + } + + // delete user value if email address is empty + $user->setEMailAddress($mailAddress); + + return new DataResponse( + array( + 'status' => 'success', + 'data' => array( + 'username' => $id, + 'mailAddress' => $mailAddress, + 'message' => (string)$this->l10n->t('Email saved') + ) + ), + Http::STATUS_OK + ); + } + + /** + * Count all unique users visible for the current admin/subadmin. + * + * @NoAdminRequired + * + * @return DataResponse + */ + public function stats() { + $userCount = 0; + if ($this->isAdmin) { + $countByBackend = $this->userManager->countUsers(); + + if (!empty($countByBackend)) { + foreach ($countByBackend as $count) { + $userCount += $count; + } + } + } else { + $groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser()); + + $uniqueUsers = []; + foreach ($groups as $group) { + foreach($group->getUsers() as $uid => $displayName) { + $uniqueUsers[$uid] = true; + } + } + + $userCount = count($uniqueUsers); + } + + return new DataResponse( + [ + 'totalUsers' => $userCount + ] + ); + } + + + /** + * Set the displayName of a user + * + * @NoAdminRequired + * @NoSubadminRequired + * + * @param string $username + * @param string $displayName + * @return DataResponse + */ + public function setDisplayName($username, $displayName) { + $currentUser = $this->userSession->getUser(); + + if ($username === null) { + $username = $currentUser->getUID(); + } + + $user = $this->userManager->get($username); + + if ($user === null || + !$user->canChangeDisplayName() || + ( + !$this->groupManager->isAdmin($currentUser->getUID()) && + !$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) && + $currentUser !== $user) + ) { + return new DataResponse([ + 'status' => 'error', + 'data' => [ + 'message' => $this->l10n->t('Authentication error'), + ], + ]); + } + + if ($user->setDisplayName($displayName)) { + return new DataResponse([ + 'status' => 'success', + 'data' => [ + 'message' => $this->l10n->t('Your full name has been changed.'), + 'username' => $username, + 'displayName' => $displayName, + ], + ]); + } else { + return new DataResponse([ + 'status' => 'error', + 'data' => [ + 'message' => $this->l10n->t('Unable to change full name'), + 'displayName' => $user->getDisplayName(), + ], + ]); + } + } +} |