diff options
author | John Molakvoæ <skjnldsv@protonmail.com> | 2023-07-13 09:58:24 +0200 |
---|---|---|
committer | John Molakvoæ <skjnldsv@protonmail.com> | 2023-08-01 16:38:06 +0200 |
commit | 38480fda3cd1f10652bc1e854207b074921e66b8 (patch) | |
tree | c4c9112123f649802c9f86d056fe6da5e89be068 /apps/files_external/lib | |
parent | 385f987a28a535e8b6b0020693daa5347093c186 (diff) | |
download | nextcloud-server-38480fda3cd1f10652bc1e854207b074921e66b8.tar.gz nextcloud-server-38480fda3cd1f10652bc1e854207b074921e66b8.zip |
feat(files_external): migrate to vue
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
Diffstat (limited to 'apps/files_external/lib')
10 files changed, 135 insertions, 62 deletions
diff --git a/apps/files_external/lib/AppInfo/Application.php b/apps/files_external/lib/AppInfo/Application.php index 6f8018746b3..fc6a5d64e7c 100644 --- a/apps/files_external/lib/AppInfo/Application.php +++ b/apps/files_external/lib/AppInfo/Application.php @@ -29,6 +29,7 @@ */ namespace OCA\Files_External\AppInfo; +use OCA\Files\Event\LoadAdditionalScriptsEvent; use OCA\Files_External\Config\ConfigAdapter; use OCA\Files_External\Config\UserPlaceholderHandler; use OCA\Files_External\Lib\Auth\AmazonS3\AccessKey; @@ -62,6 +63,7 @@ use OCA\Files_External\Lib\Backend\Swift; use OCA\Files_External\Lib\Config\IAuthMechanismProvider; use OCA\Files_External\Lib\Config\IBackendProvider; use OCA\Files_External\Listener\GroupDeletedListener; +use OCA\Files_External\Listener\LoadAdditionalListener; use OCA\Files_External\Listener\UserDeletedListener; use OCA\Files_External\Service\BackendService; use OCP\AppFramework\App; @@ -78,6 +80,7 @@ require_once __DIR__ . '/../../3rdparty/autoload.php'; * @package OCA\Files_External\AppInfo */ class Application extends App implements IBackendProvider, IAuthMechanismProvider, IBootstrap { + public const APP_ID = 'files_external'; /** * Application constructor. @@ -85,28 +88,19 @@ class Application extends App implements IBackendProvider, IAuthMechanismProvide * @throws \OCP\AppFramework\QueryException */ public function __construct(array $urlParams = []) { - parent::__construct('files_external', $urlParams); + parent::__construct(self::APP_ID, $urlParams); } public function register(IRegistrationContext $context): void { $context->registerEventListener(UserDeletedEvent::class, UserDeletedListener::class); $context->registerEventListener(GroupDeletedEvent::class, GroupDeletedListener::class); + $context->registerEventListener(LoadAdditionalScriptsEvent::class, LoadAdditionalListener::class); } public function boot(IBootContext $context): void { $context->injectFn(function (IMountProviderCollection $mountProviderCollection, ConfigAdapter $configAdapter) { $mountProviderCollection->registerProvider($configAdapter); }); - \OCA\Files\App::getNavigationManager()->add(function () { - $l = \OC::$server->getL10N('files_external'); - return [ - 'id' => 'extstoragemounts', - 'appname' => 'files_external', - 'script' => 'list.php', - 'order' => 30, - 'name' => $l->t('External storage'), - ]; - }); $context->injectFn(function (BackendService $backendService, UserPlaceholderHandler $userConfigHandler) { $backendService->registerBackendProvider($this); $backendService->registerAuthMechanismProvider($this); diff --git a/apps/files_external/lib/Controller/ApiController.php b/apps/files_external/lib/Controller/ApiController.php index ed54837a9bd..1276dde91c6 100644 --- a/apps/files_external/lib/Controller/ApiController.php +++ b/apps/files_external/lib/Controller/ApiController.php @@ -37,30 +37,22 @@ use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCSController; use OCP\IRequest; -use OCP\IUserSession; /** * @psalm-import-type FilesExternalMount from ResponseDefinitions */ class ApiController extends OCSController { - /** @var IUserSession */ - private $userSession; - /** @var UserGlobalStoragesService */ - private $userGlobalStoragesService; - /** @var UserStoragesService */ - private $userStoragesService; + private UserGlobalStoragesService $userGlobalStoragesService; + private UserStoragesService $userStoragesService; public function __construct( string $appName, IRequest $request, - IUserSession $userSession, UserGlobalStoragesService $userGlobalStorageService, UserStoragesService $userStorageService ) { parent::__construct($appName, $request); - - $this->userSession = $userSession; $this->userGlobalStoragesService = $userGlobalStorageService; $this->userStoragesService = $userStorageService; } @@ -89,14 +81,15 @@ class ApiController extends OCSController { } $entry = [ + 'id' => $mountConfig->getId(), + 'type' => 'dir', 'name' => basename($mountPoint), 'path' => $path, - 'type' => 'dir', - 'backend' => $mountConfig->getBackend()->getText(), - 'scope' => $isSystemMount ? 'system' : 'personal', 'permissions' => $permissions, - 'id' => $mountConfig->getId(), + 'scope' => $isSystemMount ? 'system' : 'personal', + 'backend' => $mountConfig->getBackend()->getText(), 'class' => $mountConfig->getBackend()->getIdentifier(), + 'config' => $mountConfig->jsonSerialize(true), ]; return $entry; } @@ -127,4 +120,31 @@ class ApiController extends OCSController { return new DataResponse($entries); } + + /** + * @NoAdminRequired + * + * Ask for credentials using a browser's native basic auth prompt + * Then returns it if provided + */ + public function askNativeAuth(): DataResponse { + if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) { + $response = new DataResponse([], Http::STATUS_UNAUTHORIZED); + $response->addHeader('WWW-Authenticate', 'Basic realm="Storage authentification needed"'); + return $response; + } + + $user = $_SERVER['PHP_AUTH_USER']; + $password = $_SERVER['PHP_AUTH_PW']; + + // Reset auth + unset($_SERVER['PHP_AUTH_USER']); + unset($_SERVER['PHP_AUTH_PW']); + + // Using 401 again to ensure we clear any cached Authorization + return new DataResponse([ + 'user' => $user, + 'password' => $password, + ], Http::STATUS_UNAUTHORIZED); + } } diff --git a/apps/files_external/lib/Controller/GlobalStoragesController.php b/apps/files_external/lib/Controller/GlobalStoragesController.php index ce45bf3307c..cb785695647 100644 --- a/apps/files_external/lib/Controller/GlobalStoragesController.php +++ b/apps/files_external/lib/Controller/GlobalStoragesController.php @@ -134,7 +134,7 @@ class GlobalStoragesController extends StoragesController { $this->updateStorageStatus($newStorage); return new DataResponse( - $this->formatStorageForUI($newStorage), + $newStorage->jsonSerialize(true), Http::STATUS_CREATED ); } @@ -201,7 +201,7 @@ class GlobalStoragesController extends StoragesController { $this->updateStorageStatus($storage, $testOnly); return new DataResponse( - $this->formatStorageForUI($storage), + $storage->jsonSerialize(true), Http::STATUS_OK ); } diff --git a/apps/files_external/lib/Controller/StoragesController.php b/apps/files_external/lib/Controller/StoragesController.php index 6b8e9574d6f..ead6aa9663a 100644 --- a/apps/files_external/lib/Controller/StoragesController.php +++ b/apps/files_external/lib/Controller/StoragesController.php @@ -276,7 +276,7 @@ abstract class StoragesController extends Controller { * @return DataResponse */ public function index() { - $storages = $this->formatStoragesForUI($this->service->getStorages()); + $storages = array_map(static fn ($storage) => $storage->jsonSerialize(true), $this->service->getStorages()); return new DataResponse( $storages, @@ -284,29 +284,6 @@ abstract class StoragesController extends Controller { ); } - protected function formatStoragesForUI(array $storages): array { - return array_map(function ($storage) { - return $this->formatStorageForUI($storage); - }, $storages); - } - - protected function formatStorageForUI(StorageConfig $storage): StorageConfig { - /** @var DefinitionParameter[] $parameters */ - $parameters = array_merge($storage->getBackend()->getParameters(), $storage->getAuthMechanism()->getParameters()); - - $options = $storage->getBackendOptions(); - foreach ($options as $key => $value) { - foreach ($parameters as $parameter) { - if ($parameter->getName() === $key && $parameter->getType() === DefinitionParameter::VALUE_PASSWORD) { - $storage->setBackendOption($key, DefinitionParameter::UNMODIFIED_PLACEHOLDER); - break; - } - } - } - - return $storage; - } - /** * Get an external storage entry. * @@ -329,7 +306,7 @@ abstract class StoragesController extends Controller { ); } - $data = $this->formatStorageForUI($storage)->jsonSerialize(); + $data = $storage->jsonSerialize(true); $isAdmin = $this->groupManager->isAdmin($this->userSession->getUser()->getUID()); $data['can_edit'] = $storage->getType() === StorageConfig::MOUNT_TYPE_PERSONAl || $isAdmin; diff --git a/apps/files_external/lib/Controller/UserGlobalStoragesController.php b/apps/files_external/lib/Controller/UserGlobalStoragesController.php index 91bc1701372..ba15afb2bdf 100644 --- a/apps/files_external/lib/Controller/UserGlobalStoragesController.php +++ b/apps/files_external/lib/Controller/UserGlobalStoragesController.php @@ -88,12 +88,13 @@ class UserGlobalStoragesController extends StoragesController { * @NoAdminRequired */ public function index() { - $storages = $this->formatStoragesForUI($this->service->getUniqueStorages()); - - // remove configuration data, this must be kept private - foreach ($storages as $storage) { + /** @var UserGlobalStoragesService */ + $service = $this->service; + $storages = array_map(function ($storage) { + // remove configuration data, this must be kept private $this->sanitizeStorage($storage); - } + return $storage->jsonSerialize(true); + }, $service->getUniqueStorages()); return new DataResponse( $storages, @@ -135,7 +136,7 @@ class UserGlobalStoragesController extends StoragesController { $this->sanitizeStorage($storage); - $data = $this->formatStorageForUI($storage)->jsonSerialize(); + $data = $storage->jsonSerialize(true); $isAdmin = $this->groupManager->isAdmin($this->userSession->getUser()->getUID()); $data['can_edit'] = $storage->getType() === StorageConfig::MOUNT_TYPE_PERSONAl || $isAdmin; @@ -189,7 +190,7 @@ class UserGlobalStoragesController extends StoragesController { $this->sanitizeStorage($storage); return new DataResponse( - $this->formatStorageForUI($storage), + $storage->jsonSerialize(true), Http::STATUS_OK ); } diff --git a/apps/files_external/lib/Controller/UserStoragesController.php b/apps/files_external/lib/Controller/UserStoragesController.php index a875f7c2dcb..7c141afcb30 100644 --- a/apps/files_external/lib/Controller/UserStoragesController.php +++ b/apps/files_external/lib/Controller/UserStoragesController.php @@ -159,7 +159,7 @@ class UserStoragesController extends StoragesController { $this->updateStorageStatus($newStorage); return new DataResponse( - $this->formatStorageForUI($newStorage), + $newStorage->jsonSerialize(true), Http::STATUS_CREATED ); } @@ -219,7 +219,7 @@ class UserStoragesController extends StoragesController { $this->updateStorageStatus($storage, $testOnly); return new DataResponse( - $this->formatStorageForUI($storage), + $storage->jsonSerialize(true), Http::STATUS_OK ); } diff --git a/apps/files_external/lib/Lib/Auth/Password/SessionCredentials.php b/apps/files_external/lib/Lib/Auth/Password/SessionCredentials.php index 228366db204..a1add7c870f 100644 --- a/apps/files_external/lib/Lib/Auth/Password/SessionCredentials.php +++ b/apps/files_external/lib/Lib/Auth/Password/SessionCredentials.php @@ -58,6 +58,10 @@ class SessionCredentials extends AuthMechanism { throw new InsufficientDataForMeaningfulAnswerException('No session credentials saved'); } + if ($user === null) { + throw new StorageAuthException('Session unavailable'); + } + if ($credentials->getUID() !== $user->getUID()) { throw new StorageAuthException('Session credentials for storage owner not available'); } diff --git a/apps/files_external/lib/Lib/StorageConfig.php b/apps/files_external/lib/Lib/StorageConfig.php index be61d2982c0..8cb59f70892 100644 --- a/apps/files_external/lib/Lib/StorageConfig.php +++ b/apps/files_external/lib/Lib/StorageConfig.php @@ -397,11 +397,17 @@ class StorageConfig implements \JsonSerializable { /** * Serialize config to JSON */ - public function jsonSerialize(): array { + public function jsonSerialize(bool $obfuscate = false): array { $result = []; if (!is_null($this->id)) { $result['id'] = $this->id; } + + // obfuscate sensitive data if requested + if ($obfuscate) { + $this->formatStorageForUI(); + } + $result['mountPoint'] = $this->mountPoint; $result['backend'] = $this->backend->getIdentifier(); $result['authMechanism'] = $this->authMechanism->getIdentifier(); @@ -428,4 +434,19 @@ class StorageConfig implements \JsonSerializable { $result['type'] = ($this->getType() === self::MOUNT_TYPE_PERSONAl) ? 'personal': 'system'; return $result; } + + protected function formatStorageForUI(): void { + /** @var DefinitionParameter[] $parameters */ + $parameters = array_merge($this->getBackend()->getParameters(), $this->getAuthMechanism()->getParameters()); + + $options = $this->getBackendOptions(); + foreach ($options as $key => $value) { + foreach ($parameters as $parameter) { + if ($parameter->getName() === $key && $parameter->getType() === DefinitionParameter::VALUE_PASSWORD) { + $this->setBackendOption($key, DefinitionParameter::UNMODIFIED_PLACEHOLDER); + break; + } + } + } + } } diff --git a/apps/files_external/lib/Listener/LoadAdditionalListener.php b/apps/files_external/lib/Listener/LoadAdditionalListener.php new file mode 100644 index 00000000000..e5cb5e96d0a --- /dev/null +++ b/apps/files_external/lib/Listener/LoadAdditionalListener.php @@ -0,0 +1,55 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program 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 + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCA\Files_External\Listener; + +use OCA\Files_External\AppInfo\Application; +use OCA\Files\Event\LoadAdditionalScriptsEvent; +use OCP\AppFramework\Services\IInitialState; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\IConfig; +use OCP\Util; + +/** + * @template-implements IEventListener<Event|LoadAdditionalScriptsEvent> + */ +class LoadAdditionalListener implements IEventListener { + + public function __construct( + private IConfig $config, + private IInitialState $initialState, + ) {} + + public function handle(Event $event): void { + if (!($event instanceof LoadAdditionalScriptsEvent)) { + return; + } + + $allowUserMounting = $this->config->getAppValue('files_external', 'allow_user_mounting', 'no') === 'yes'; + $this->initialState->provideInitialState('allowUserMounting', $allowUserMounting); + Util::addScript(Application::APP_ID, 'main', 'files'); + } +} diff --git a/apps/files_external/lib/ResponseDefinitions.php b/apps/files_external/lib/ResponseDefinitions.php index d26d05a36f4..bae29085361 100644 --- a/apps/files_external/lib/ResponseDefinitions.php +++ b/apps/files_external/lib/ResponseDefinitions.php @@ -35,6 +35,7 @@ namespace OCA\Files_External; * permissions: int, * id: int, * class: string, + * config: array<array-key, mixed>, * } */ class ResponseDefinitions { |