diff options
author | Bjoern Schiessle <schiessle@owncloud.com> | 2015-07-24 12:24:18 +0200 |
---|---|---|
committer | Bjoern Schiessle <schiessle@owncloud.com> | 2015-08-30 19:00:03 +0200 |
commit | 289e9130f35334a6f0cffcedee82da7d9f5082d0 (patch) | |
tree | 6330cd354add9962f3a1ec8c84aa0482b826df82 /core/command | |
parent | 045f8cc97101521cafd664faf7b8f24ea9e88451 (diff) | |
download | nextcloud-server-289e9130f35334a6f0cffcedee82da7d9f5082d0.tar.gz nextcloud-server-289e9130f35334a6f0cffcedee82da7d9f5082d0.zip |
make system root of key storage configurable
Diffstat (limited to 'core/command')
-rw-r--r-- | core/command/encryption/changekeystorageroot.php | 270 | ||||
-rw-r--r-- | core/command/encryption/showkeystorageroot.php | 58 |
2 files changed, 328 insertions, 0 deletions
diff --git a/core/command/encryption/changekeystorageroot.php b/core/command/encryption/changekeystorageroot.php new file mode 100644 index 00000000000..662e0a3161a --- /dev/null +++ b/core/command/encryption/changekeystorageroot.php @@ -0,0 +1,270 @@ +<?php +/** + * @author Björn Schießle <schiessle@owncloud.com> + * + * @copyright Copyright (c) 2015, 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\Core\Command\Encryption; + +use OC\Encryption\Keys\Storage; +use OC\Encryption\Util; +use OC\Files\Filesystem; +use OC\Files\View; +use OCP\IConfig; +use OCP\IUserManager; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\ProgressBar; +use Symfony\Component\Console\Helper\QuestionHelper; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\ConfirmationQuestion; + +class ChangeKeyStorageRoot extends Command { + + /** @var View */ + protected $rootView; + + /** @var IUserManager */ + protected $userManager; + + /** @var IConfig */ + protected $config; + + /** @var Util */ + protected $util; + + /** @var QuestionHelper */ + protected $questionHelper; + + /** + * @param View $view + * @param IUserManager $userManager + * @param IConfig $config + * @param Util $util + * @param QuestionHelper $questionHelper + */ + public function __construct(View $view, IUserManager $userManager, IConfig $config, Util $util, QuestionHelper $questionHelper) { + parent::__construct(); + $this->rootView = $view; + $this->userManager = $userManager; + $this->config = $config; + $this->util = $util; + $this->questionHelper = $questionHelper; + } + + protected function configure() { + parent::configure(); + $this + ->setName('encryption:change-key-storage-root') + ->setDescription('Change key storage root') + ->addArgument( + 'newRoot', + InputArgument::OPTIONAL, + 'new root of the key storage relative to the data folder' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $oldRoot = $this->util->getKeyStorageRoot(); + $newRoot = $input->getArgument('newRoot'); + + if ($newRoot === null) { + $question = new ConfirmationQuestion('No storage root given, do you want to reset the key storage root to the default location? (y/n) ', false); + if (!$this->questionHelper->ask($input, $output, $question)) { + return; + } + $newRoot = ''; + } + + $oldRootDescription = $oldRoot !== '' ? $oldRoot : 'default storage location'; + $newRootDescription = $newRoot !== '' ? $newRoot : 'default storage location'; + $output->writeln("Change key storage root from <info>$oldRootDescription</info> to <info>$newRootDescription</info>"); + $success = $this->moveAllKeys($oldRoot, $newRoot, $output); + if ($success) { + $this->util->setKeyStorageRoot($newRoot); + $output->writeln(''); + $output->writeln("Key storage root successfully changed to <info>$newRootDescription</info>"); + } + } + + /** + * move keys to new key storage root + * + * @param string $oldRoot + * @param string $newRoot + * @param OutputInterface $output + * @return bool + * @throws \Exception + */ + protected function moveAllKeys($oldRoot, $newRoot, OutputInterface $output) { + + $output->writeln("Start to move keys:"); + + if ($this->rootView->is_dir(($oldRoot)) === false) { + $output->writeln("No old keys found: Nothing needs to be moved"); + return false; + } + + $this->prepareNewRoot($newRoot); + $this->moveSystemKeys($oldRoot, $newRoot); + $this->moveUserKeys($oldRoot, $newRoot, $output); + + return true; + } + + /** + * prepare new key storage + * + * @param string $newRoot + * @throws \Exception + */ + protected function prepareNewRoot($newRoot) { + if ($this->rootView->is_dir($newRoot) === false) { + throw new \Exception("New root folder doesn't exist. Please create the folder or check the permissions and try again."); + } + + $result = $this->rootView->file_put_contents( + $newRoot . '/' . Storage::KEY_STORAGE_MARKER, + 'ownCloud will detect this folder as key storage root only if this file exists' + ); + + if ($result === false) { + throw new \Exception("Can't write to new root folder. Please check the permissions and try again"); + } + + } + + + /** + * move system key folder + * + * @param string $oldRoot + * @param string $newRoot + */ + protected function moveSystemKeys($oldRoot, $newRoot) { + if ( + $this->rootView->is_dir($oldRoot . '/files_encryption') && + $this->targetExists($newRoot . '/files_encryption') === false + ) { + $this->rootView->rename($oldRoot . '/files_encryption', $newRoot . '/files_encryption'); + } + } + + + /** + * setup file system for the given user + * + * @param string $uid + */ + protected function setupUserFS($uid) { + \OC_Util::tearDownFS(); + \OC_Util::setupFS($uid); + } + + + /** + * iterate over each user and move the keys to the new storage + * + * @param string $oldRoot + * @param string $newRoot + * @param OutputInterface $output + */ + protected function moveUserKeys($oldRoot, $newRoot, OutputInterface $output) { + + $progress = new ProgressBar($output); + $progress->start(); + + + foreach($this->userManager->getBackends() as $backend) { + $limit = 500; + $offset = 0; + do { + $users = $backend->getUsers('', $limit, $offset); + foreach ($users as $user) { + $progress->advance(); + $this->setupUserFS($user); + $this->moveUserEncryptionFolder($user, $oldRoot, $newRoot); + } + $offset += $limit; + } while(count($users) >= $limit); + } + $progress->finish(); + } + + /** + * move user encryption folder to new root folder + * + * @param string $user + * @param string $oldRoot + * @param string $newRoot + * @throws \Exception + */ + protected function moveUserEncryptionFolder($user, $oldRoot, $newRoot) { + + if ($this->userManager->userExists($user)) { + + $source = $oldRoot . '/' . $user . '/files_encryption'; + $target = $newRoot . '/' . $user . '/files_encryption'; + if ( + $this->rootView->is_dir($source) && + $this->targetExists($target) === false + ) { + $this->prepareParentFolder($newRoot . '/' . $user); + $this->rootView->rename($source, $target); + } + } + } + + /** + * Make preparations to filesystem for saving a key file + * + * @param string $path relative to data/ + */ + protected function prepareParentFolder($path) { + $path = Filesystem::normalizePath($path); + // If the file resides within a subdirectory, create it + if ($this->rootView->file_exists($path) === false) { + $sub_dirs = explode('/', ltrim($path, '/')); + $dir = ''; + foreach ($sub_dirs as $sub_dir) { + $dir .= '/' . $sub_dir; + if ($this->rootView->file_exists($dir) === false) { + $this->rootView->mkdir($dir); + } + } + } + } + + /** + * check if target already exists + * + * @param $path + * @return bool + * @throws \Exception + */ + protected function targetExists($path) { + if ($this->rootView->file_exists($path)) { + throw new \Exception("new folder '$path' already exists"); + } + + return false; + } + +} diff --git a/core/command/encryption/showkeystorageroot.php b/core/command/encryption/showkeystorageroot.php new file mode 100644 index 00000000000..acb2e75a6ae --- /dev/null +++ b/core/command/encryption/showkeystorageroot.php @@ -0,0 +1,58 @@ +<?php +/** + * @author Björn Schießle <schiessle@owncloud.com> + * + * @copyright Copyright (c) 2015, 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\Core\Command\Encryption; + +use OC\Encryption\Util; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class ShowKeyStorageRoot extends Command{ + + /** @var Util */ + protected $util; + + /** + * @param Util $util + */ + public function __construct(Util $util) { + parent::__construct(); + $this->util = $util; + } + + protected function configure() { + parent::configure(); + $this + ->setName('encryption:show-key-storage-root') + ->setDescription('Show current key storage root'); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $currentRoot = $this->util->getKeyStorageRoot(); + + $rootDescription = $currentRoot !== '' ? $currentRoot : 'default storage location (data/)'; + + $output->writeln("Current key storage root: <info>$rootDescription</info>"); + } + +} |