diff --git a/apps/settings/appinfo/routes.php b/apps/settings/appinfo/routes.php index e238510b1a75f..634443d56843d 100644 --- a/apps/settings/appinfo/routes.php +++ b/apps/settings/appinfo/routes.php @@ -76,6 +76,8 @@ ['name' => 'TwoFactorSettings#index', 'url' => '/settings/api/admin/twofactorauth', 'verb' => 'GET' , 'root' => ''], ['name' => 'TwoFactorSettings#update', 'url' => '/settings/api/admin/twofactorauth', 'verb' => 'PUT' , 'root' => ''], ['name' => 'AISettings#update', 'url' => '/settings/api/admin/ai', 'verb' => 'PUT' , 'root' => ''], + ['name' => 'CORSSettings#updateUserEnabled', 'url' => '/settings/api/admin/cors/allowusers', 'verb' => 'PUT' , 'root' => ''], + ['name' => 'CORSSettings#allowedDomains', 'url' => '/settings/api/admin/cors/domains', 'verb' => 'PUT' , 'root' => ''], ['name' => 'Help#help', 'url' => '/settings/help/{mode}', 'verb' => 'GET', 'defaults' => ['mode' => ''] , 'root' => ''], diff --git a/apps/settings/composer/composer/autoload_classmap.php b/apps/settings/composer/composer/autoload_classmap.php index 674b92b7cac36..cb7fada293ea5 100644 --- a/apps/settings/composer/composer/autoload_classmap.php +++ b/apps/settings/composer/composer/autoload_classmap.php @@ -21,6 +21,7 @@ 'OCA\\Settings\\Controller\\AppSettingsController' => $baseDir . '/../lib/Controller/AppSettingsController.php', 'OCA\\Settings\\Controller\\AuthSettingsController' => $baseDir . '/../lib/Controller/AuthSettingsController.php', 'OCA\\Settings\\Controller\\AuthorizedGroupController' => $baseDir . '/../lib/Controller/AuthorizedGroupController.php', + 'OCA\\Settings\\Controller\\CORSSettingsController' => $baseDir . '/../lib/Controller/CORSSettingsController.php', 'OCA\\Settings\\Controller\\ChangePasswordController' => $baseDir . '/../lib/Controller/ChangePasswordController.php', 'OCA\\Settings\\Controller\\CheckSetupController' => $baseDir . '/../lib/Controller/CheckSetupController.php', 'OCA\\Settings\\Controller\\CommonSettingsTrait' => $baseDir . '/../lib/Controller/CommonSettingsTrait.php', diff --git a/apps/settings/composer/composer/autoload_static.php b/apps/settings/composer/composer/autoload_static.php index d78aa56c60642..863d5528e2557 100644 --- a/apps/settings/composer/composer/autoload_static.php +++ b/apps/settings/composer/composer/autoload_static.php @@ -36,6 +36,7 @@ class ComposerStaticInitSettings 'OCA\\Settings\\Controller\\AppSettingsController' => __DIR__ . '/..' . '/../lib/Controller/AppSettingsController.php', 'OCA\\Settings\\Controller\\AuthSettingsController' => __DIR__ . '/..' . '/../lib/Controller/AuthSettingsController.php', 'OCA\\Settings\\Controller\\AuthorizedGroupController' => __DIR__ . '/..' . '/../lib/Controller/AuthorizedGroupController.php', + 'OCA\\Settings\\Controller\\CORSSettingsController' => __DIR__ . '/..' . '/../lib/Controller/CORSSettingsController.php', 'OCA\\Settings\\Controller\\ChangePasswordController' => __DIR__ . '/..' . '/../lib/Controller/ChangePasswordController.php', 'OCA\\Settings\\Controller\\CheckSetupController' => __DIR__ . '/..' . '/../lib/Controller/CheckSetupController.php', 'OCA\\Settings\\Controller\\CommonSettingsTrait' => __DIR__ . '/..' . '/../lib/Controller/CommonSettingsTrait.php', diff --git a/apps/settings/lib/Controller/CORSSettingsController.php b/apps/settings/lib/Controller/CORSSettingsController.php new file mode 100644 index 0000000000000..5cebcb55bd0a5 --- /dev/null +++ b/apps/settings/lib/Controller/CORSSettingsController.php @@ -0,0 +1,88 @@ + + * + * @license AGPL-3.0-or-later + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * 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 + */ +namespace OCA\Settings\Controller; + +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IConfig; +use OCP\IRequest; +use OCP\Util; + +class CORSSettingsController extends Controller { + + /** + * @param string $appName + * @param IRequest $request + * @param IConfig $config + */ + public function __construct( + $appName, + IRequest $request, + private IConfig $config, + ) { + parent::__construct($appName, $request); + } + + /** + * Set whether users can configure their own list of allowed CORS domains + * + * @AuthorizedAdminSetting(settings=OCA\Settings\Settings\Admin\Security) + * + * @param bool $value + * @return DataResponse + */ + public function updateUserEnabled(bool $value) { + if (!is_bool($value)) { + return new DataResponse([], Http::STATUS_BAD_REQUEST); + } + + $this->config->setSystemValue('cors.allow-user-domains', $value); + + return new DataResponse(); + } + + /** + * Set list of globally allowed CORS domains + * + * @AuthorizedAdminSetting(settings=OCA\Settings\Settings\Admin\Security) + * + * @param array $value + * @return DataResponse + */ + public function allowedDomains(array $value) { + try { + foreach ($value as $entry) { + if (!is_string($entry) || $entry === '' || Util::getFullDomain($entry) === '') { + return new DataResponse([], HTTP::STATUS_BAD_REQUEST); + } + } + } catch (\InvalidArgumentException $e) { + return new DataResponse([], Http::STATUS_BAD_REQUEST); + } + + $this->config->setSystemValue('cors.allowed-domains', $value); + + return new DataResponse(); + } +} diff --git a/apps/settings/lib/Settings/Admin/Security.php b/apps/settings/lib/Settings/Admin/Security.php index 63d3137a45ca8..96f87c8ecb1eb 100644 --- a/apps/settings/lib/Settings/Admin/Security.php +++ b/apps/settings/lib/Settings/Admin/Security.php @@ -30,6 +30,7 @@ use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Services\IInitialState; use OCP\Encryption\IManager; +use OCP\IConfig; use OCP\IUserManager; use OCP\IURLGenerator; use OCP\Settings\ISettings; @@ -40,17 +41,20 @@ class Security implements ISettings { private MandatoryTwoFactor $mandatoryTwoFactor; private IInitialState $initialState; private IURLGenerator $urlGenerator; + private IConfig $config; public function __construct(IManager $manager, IUserManager $userManager, MandatoryTwoFactor $mandatoryTwoFactor, IInitialState $initialState, - IURLGenerator $urlGenerator) { + IURLGenerator $urlGenerator, + IConfig $config) { $this->manager = $manager; $this->userManager = $userManager; $this->mandatoryTwoFactor = $mandatoryTwoFactor; $this->initialState = $initialState; $this->urlGenerator = $urlGenerator; + $this->config = $config; } /** @@ -76,6 +80,11 @@ public function getForm(): TemplateResponse { $this->initialState->provideInitialState('encryption-modules', $encryptionModuleList); $this->initialState->provideInitialState('encryption-admin-doc', $this->urlGenerator->linkToDocs('admin-encryption')); + $this->initialState->provideInitialState('cors-allowed-domains', $this->config->getSystemValue('cors.allowed-domains', [])); + $this->initialState->provideInitialState('cors-allow-user-domains', $this->config->getSystemValue('cors.allow-user-domains', false)); + $this->initialState->provideInitialState('cors-settings-admin-docs', $this->urlGenerator->linkToDocs('admin-cors')); + + return new TemplateResponse('settings', 'settings/admin/security', [], ''); } diff --git a/apps/settings/src/components/CORS.vue b/apps/settings/src/components/CORS.vue new file mode 100644 index 0000000000000..70b826faf8737 --- /dev/null +++ b/apps/settings/src/components/CORS.vue @@ -0,0 +1,273 @@ + + + + + + + diff --git a/apps/settings/src/components/Encryption.vue b/apps/settings/src/components/Encryption.vue index b6a37b41c8b7c..1369f92a0e340 100644 --- a/apps/settings/src/components/Encryption.vue +++ b/apps/settings/src/components/Encryption.vue @@ -80,18 +80,13 @@ import axios from '@nextcloud/axios' import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js' import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' import NcSettingsSection from '@nextcloud/vue/dist/Components/NcSettingsSection.js' -import { loadState } from '@nextcloud/initial-state' -import { getLoggerBuilder } from '@nextcloud/logger' +import { loadState } from '@nextcloud/initial-state' import { generateOcsUrl } from '@nextcloud/router' import { confirmPassword } from '@nextcloud/password-confirmation' -import '@nextcloud/password-confirmation/dist/style.css' import { showError } from '@nextcloud/dialogs' -const logger = getLoggerBuilder() - .setApp('settings') - .detectUser() - .build() +import { logger } from '../utils/logger.ts' export default { name: 'Encryption', diff --git a/apps/settings/src/main-admin-security.js b/apps/settings/src/main-admin-security.js index a5c239683e7d7..74e86defd34cb 100644 --- a/apps/settings/src/main-admin-security.js +++ b/apps/settings/src/main-admin-security.js @@ -4,6 +4,7 @@ * @author Christoph Wurst * @author John Molakvoæ * @author Roeland Jago Douma + * @author Ferdinand Thiessen * * @license AGPL-3.0-or-later * @@ -22,13 +23,16 @@ * */ -import { loadState } from '@nextcloud/initial-state' import Vue from 'vue' - import AdminTwoFactor from './components/AdminTwoFactor.vue' import Encryption from './components/Encryption.vue' +import CORS from './components/CORS.vue' import store from './store/admin-security.js' +import { loadState } from '@nextcloud/initial-state' + +import '@nextcloud/password-confirmation/dist/style.css' + // eslint-disable-next-line camelcase __webpack_nonce__ = btoa(OC.requestToken) @@ -49,3 +53,6 @@ new View({ const EncryptionView = Vue.extend(Encryption) new EncryptionView().$mount('#vue-admin-encryption') + +const CORSView = Vue.extend(CORS) +new CORSView().$mount('#vue-admin-cors-settings') diff --git a/apps/settings/src/utils/logger.ts b/apps/settings/src/utils/logger.ts new file mode 100644 index 0000000000000..c6e60514a1f14 --- /dev/null +++ b/apps/settings/src/utils/logger.ts @@ -0,0 +1,6 @@ +import { getLoggerBuilder } from '@nextcloud/logger' + +export const logger = getLoggerBuilder() + .setApp('settings') + .detectUser() + .build() diff --git a/apps/settings/templates/settings/admin/security.php b/apps/settings/templates/settings/admin/security.php index a7ee26b3d70db..6478614026593 100644 --- a/apps/settings/templates/settings/admin/security.php +++ b/apps/settings/templates/settings/admin/security.php @@ -4,6 +4,7 @@ * @copyright 2022 Carl Schwan * * @author Arthur Schiwon + * @author Ferdinand Thiessen * * @license GNU AGPL version 3 or any later version * @@ -28,3 +29,5 @@
+ +