summaryrefslogtreecommitdiffstats
path: root/settings/Controller
diff options
context:
space:
mode:
authorLukas Reschke <lukas@owncloud.com>2016-04-06 11:09:55 +0200
committerLukas Reschke <lukas@owncloud.com>2016-04-06 11:12:22 +0200
commitc12bb839e197990db86f0062fa6b7ec54aff5121 (patch)
treef70c0ac4f4113db7c0b5fdde0665c1f510fe6601 /settings/Controller
parent046506dd146f823499098d0d2b0042072e436469 (diff)
downloadnextcloud-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.php322
-rw-r--r--settings/Controller/CertificateController.php183
-rw-r--r--settings/Controller/CheckSetupController.php350
-rw-r--r--settings/Controller/EncryptionController.php145
-rw-r--r--settings/Controller/GroupsController.php159
-rw-r--r--settings/Controller/LogSettingsController.php109
-rw-r--r--settings/Controller/MailSettingsController.php181
-rw-r--r--settings/Controller/SecuritySettingsController.php70
-rw-r--r--settings/Controller/UsersController.php659
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(),
+ ],
+ ]);
+ }
+ }
+}