diff options
Diffstat (limited to 'apps/encryption/lib')
-rw-r--r-- | apps/encryption/lib/AppInfo/Application.php | 274 | ||||
-rw-r--r-- | apps/encryption/lib/Command/EnableMasterKey.php | 86 | ||||
-rw-r--r-- | apps/encryption/lib/Command/MigrateKeys.php | 126 | ||||
-rw-r--r-- | apps/encryption/lib/Controller/RecoveryController.php | 192 | ||||
-rw-r--r-- | apps/encryption/lib/Controller/SettingsController.php | 165 | ||||
-rw-r--r-- | apps/encryption/lib/Controller/StatusController.php | 98 | ||||
-rw-r--r-- | apps/encryption/lib/Crypto/Crypt.php (renamed from apps/encryption/lib/crypto/crypt.php) | 0 | ||||
-rw-r--r-- | apps/encryption/lib/Crypto/DecryptAll.php (renamed from apps/encryption/lib/crypto/decryptall.php) | 0 | ||||
-rw-r--r-- | apps/encryption/lib/Crypto/EncryptAll.php (renamed from apps/encryption/lib/crypto/encryptall.php) | 0 | ||||
-rw-r--r-- | apps/encryption/lib/Crypto/Encryption.php (renamed from apps/encryption/lib/crypto/encryption.php) | 0 | ||||
-rw-r--r-- | apps/encryption/lib/Exceptions/MultiKeyDecryptException.php (renamed from apps/encryption/lib/exceptions/multikeydecryptexception.php) | 0 | ||||
-rw-r--r-- | apps/encryption/lib/Exceptions/MultiKeyEncryptException.php (renamed from apps/encryption/lib/exceptions/multikeyencryptexception.php) | 0 | ||||
-rw-r--r-- | apps/encryption/lib/Exceptions/PrivateKeyMissingException.php (renamed from apps/encryption/lib/exceptions/privatekeymissingexception.php) | 0 | ||||
-rw-r--r-- | apps/encryption/lib/Exceptions/PublicKeyMissingException.php (renamed from apps/encryption/lib/exceptions/publickeymissingexception.php) | 0 | ||||
-rw-r--r-- | apps/encryption/lib/HookManager.php (renamed from apps/encryption/lib/hookmanager.php) | 0 | ||||
-rw-r--r-- | apps/encryption/lib/Hooks/Contracts/IHook.php | 32 | ||||
-rw-r--r-- | apps/encryption/lib/Hooks/UserHooks.php | 322 | ||||
-rw-r--r-- | apps/encryption/lib/KeyManager.php (renamed from apps/encryption/lib/keymanager.php) | 0 | ||||
-rw-r--r-- | apps/encryption/lib/Migration.php (renamed from apps/encryption/lib/migration.php) | 0 | ||||
-rw-r--r-- | apps/encryption/lib/Recovery.php (renamed from apps/encryption/lib/recovery.php) | 0 | ||||
-rw-r--r-- | apps/encryption/lib/Session.php (renamed from apps/encryption/lib/session.php) | 0 | ||||
-rw-r--r-- | apps/encryption/lib/Users/Setup.php (renamed from apps/encryption/lib/users/setup.php) | 0 | ||||
-rw-r--r-- | apps/encryption/lib/Util.php (renamed from apps/encryption/lib/util.php) | 0 |
23 files changed, 1295 insertions, 0 deletions
diff --git a/apps/encryption/lib/AppInfo/Application.php b/apps/encryption/lib/AppInfo/Application.php new file mode 100644 index 00000000000..c7c8d2a3d31 --- /dev/null +++ b/apps/encryption/lib/AppInfo/Application.php @@ -0,0 +1,274 @@ +<?php +/** + * @author Björn Schießle <schiessle@owncloud.com> + * @author Clark Tomlinson <fallen013@gmail.com> + * @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 OCA\Encryption\AppInfo; + + +use OC\Files\View; +use OCA\Encryption\Controller\RecoveryController; +use OCA\Encryption\Controller\SettingsController; +use OCA\Encryption\Controller\StatusController; +use OCA\Encryption\Crypto\Crypt; +use OCA\Encryption\Crypto\DecryptAll; +use OCA\Encryption\Crypto\EncryptAll; +use OCA\Encryption\Crypto\Encryption; +use OCA\Encryption\HookManager; +use OCA\Encryption\Hooks\UserHooks; +use OCA\Encryption\KeyManager; +use OCA\Encryption\Recovery; +use OCA\Encryption\Session; +use OCA\Encryption\Users\Setup; +use OCA\Encryption\Util; +use OCP\App; +use OCP\AppFramework\IAppContainer; +use OCP\Encryption\IManager; +use OCP\IConfig; +use Symfony\Component\Console\Helper\QuestionHelper; + + +class Application extends \OCP\AppFramework\App { + + /** @var IManager */ + private $encryptionManager; + /** @var IConfig */ + private $config; + + /** + * @param array $urlParams + * @param bool $encryptionSystemReady + */ + public function __construct($urlParams = array(), $encryptionSystemReady = true) { + parent::__construct('encryption', $urlParams); + $this->encryptionManager = \OC::$server->getEncryptionManager(); + $this->config = \OC::$server->getConfig(); + $this->registerServices(); + if($encryptionSystemReady === false) { + /** @var Session $session */ + $session = $this->getContainer()->query('Session'); + $session->setStatus(Session::RUN_MIGRATION); + } + if ($this->encryptionManager->isEnabled() && $encryptionSystemReady) { + /** @var Setup $setup */ + $setup = $this->getContainer()->query('UserSetup'); + $setup->setupSystem(); + } + } + + /** + * register hooks + */ + + public function registerHooks() { + if (!$this->config->getSystemValue('maintenance', false)) { + + $container = $this->getContainer(); + $server = $container->getServer(); + // Register our hooks and fire them. + $hookManager = new HookManager(); + + $hookManager->registerHook([ + new UserHooks($container->query('KeyManager'), + $server->getUserManager(), + $server->getLogger(), + $container->query('UserSetup'), + $server->getUserSession(), + $container->query('Util'), + $container->query('Session'), + $container->query('Crypt'), + $container->query('Recovery')) + ]); + + $hookManager->fireHooks(); + + } else { + // Logout user if we are in maintenance to force re-login + $this->getContainer()->getServer()->getUserSession()->logout(); + } + } + + public function registerEncryptionModule() { + $container = $this->getContainer(); + + + $this->encryptionManager->registerEncryptionModule( + Encryption::ID, + Encryption::DISPLAY_NAME, + function() use ($container) { + + return new Encryption( + $container->query('Crypt'), + $container->query('KeyManager'), + $container->query('Util'), + $container->query('Session'), + $container->query('EncryptAll'), + $container->query('DecryptAll'), + $container->getServer()->getLogger(), + $container->getServer()->getL10N($container->getAppName()) + ); + }); + + } + + public function registerServices() { + $container = $this->getContainer(); + + $container->registerService('Crypt', + function (IAppContainer $c) { + $server = $c->getServer(); + return new Crypt($server->getLogger(), + $server->getUserSession(), + $server->getConfig(), + $server->getL10N($c->getAppName())); + }); + + $container->registerService('Session', + function (IAppContainer $c) { + $server = $c->getServer(); + return new Session($server->getSession()); + } + ); + + $container->registerService('KeyManager', + function (IAppContainer $c) { + $server = $c->getServer(); + + return new KeyManager($server->getEncryptionKeyStorage(), + $c->query('Crypt'), + $server->getConfig(), + $server->getUserSession(), + new Session($server->getSession()), + $server->getLogger(), + $c->query('Util') + ); + }); + + $container->registerService('Recovery', + function (IAppContainer $c) { + $server = $c->getServer(); + + return new Recovery( + $server->getUserSession(), + $c->query('Crypt'), + $server->getSecureRandom(), + $c->query('KeyManager'), + $server->getConfig(), + $server->getEncryptionKeyStorage(), + $server->getEncryptionFilesHelper(), + new View()); + }); + + $container->registerService('RecoveryController', function (IAppContainer $c) { + $server = $c->getServer(); + return new RecoveryController( + $c->getAppName(), + $server->getRequest(), + $server->getConfig(), + $server->getL10N($c->getAppName()), + $c->query('Recovery')); + }); + + $container->registerService('StatusController', function (IAppContainer $c) { + $server = $c->getServer(); + return new StatusController( + $c->getAppName(), + $server->getRequest(), + $server->getL10N($c->getAppName()), + $c->query('Session') + ); + }); + + $container->registerService('SettingsController', function (IAppContainer $c) { + $server = $c->getServer(); + return new SettingsController( + $c->getAppName(), + $server->getRequest(), + $server->getL10N($c->getAppName()), + $server->getUserManager(), + $server->getUserSession(), + $c->query('KeyManager'), + $c->query('Crypt'), + $c->query('Session'), + $server->getSession(), + $c->query('Util') + ); + }); + + $container->registerService('UserSetup', + function (IAppContainer $c) { + $server = $c->getServer(); + return new Setup($server->getLogger(), + $server->getUserSession(), + $c->query('Crypt'), + $c->query('KeyManager')); + }); + + $container->registerService('Util', + function (IAppContainer $c) { + $server = $c->getServer(); + + return new Util( + new View(), + $c->query('Crypt'), + $server->getLogger(), + $server->getUserSession(), + $server->getConfig(), + $server->getUserManager()); + }); + + $container->registerService('EncryptAll', + function (IAppContainer $c) { + $server = $c->getServer(); + return new EncryptAll( + $c->query('UserSetup'), + $c->getServer()->getUserManager(), + new View(), + $c->query('KeyManager'), + $c->query('Util'), + $server->getConfig(), + $server->getMailer(), + $server->getL10N('encryption'), + new QuestionHelper(), + $server->getSecureRandom() + ); + } + ); + + $container->registerService('DecryptAll', + function (IAppContainer $c) { + return new DecryptAll( + $c->query('Util'), + $c->query('KeyManager'), + $c->query('Crypt'), + $c->query('Session'), + new QuestionHelper() + ); + } + ); + + } + + public function registerSettings() { + // Register settings scripts + App::registerAdmin('encryption', 'settings/settings-admin'); + App::registerPersonal('encryption', 'settings/settings-personal'); + } +} diff --git a/apps/encryption/lib/Command/EnableMasterKey.php b/apps/encryption/lib/Command/EnableMasterKey.php new file mode 100644 index 00000000000..fd86c221176 --- /dev/null +++ b/apps/encryption/lib/Command/EnableMasterKey.php @@ -0,0 +1,86 @@ +<?php +/** + * @author Björn Schießle <schiessle@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 OCA\Encryption\Command; + + +use OCA\Encryption\Util; +use OCP\IConfig; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\QuestionHelper; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\ConfirmationQuestion; + +class EnableMasterKey extends Command { + + /** @var Util */ + protected $util; + + /** @var IConfig */ + protected $config; + + /** @var QuestionHelper */ + protected $questionHelper; + + /** + * @param Util $util + * @param IConfig $config + * @param QuestionHelper $questionHelper + */ + public function __construct(Util $util, + IConfig $config, + QuestionHelper $questionHelper) { + + $this->util = $util; + $this->config = $config; + $this->questionHelper = $questionHelper; + parent::__construct(); + } + + protected function configure() { + $this + ->setName('encryption:enable-master-key') + ->setDescription('Enable the master key. Only available for fresh installations with no existing encrypted data! There is also no way to disable it again.'); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + + $isAlreadyEnabled = $this->util->isMasterKeyEnabled(); + + if($isAlreadyEnabled) { + $output->writeln('Master key already enabled'); + } else { + $question = new ConfirmationQuestion( + 'Warning: Only available for fresh installations with no existing encrypted data! ' + . 'There is also no way to disable it again. Do you want to continue? (y/n) ', false); + if ($this->questionHelper->ask($input, $output, $question)) { + $this->config->setAppValue('encryption', 'useMasterKey', '1'); + $output->writeln('Master key successfully enabled.'); + } else { + $output->writeln('aborted.'); + } + } + + } + +} diff --git a/apps/encryption/lib/Command/MigrateKeys.php b/apps/encryption/lib/Command/MigrateKeys.php new file mode 100644 index 00000000000..88d8d46973f --- /dev/null +++ b/apps/encryption/lib/Command/MigrateKeys.php @@ -0,0 +1,126 @@ +<?php +/** + * @author Björn Schießle <schiessle@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 OCA\Encryption\Command; + +use OC\DB\Connection; +use OC\Files\View; +use OC\User\Manager; +use OCA\Encryption\Migration; +use OCP\IConfig; +use OCP\ILogger; +use OCP\IUserBackend; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class MigrateKeys extends Command { + + /** @var \OC\User\Manager */ + private $userManager; + + /** @var View */ + private $view; + /** @var \OC\DB\Connection */ + private $connection; + /** @var IConfig */ + private $config; + /** @var ILogger */ + private $logger; + + /** + * @param Manager $userManager + * @param View $view + * @param Connection $connection + * @param IConfig $config + * @param ILogger $logger + */ + public function __construct(Manager $userManager, + View $view, + Connection $connection, + IConfig $config, + ILogger $logger) { + + $this->userManager = $userManager; + $this->view = $view; + $this->connection = $connection; + $this->config = $config; + $this->logger = $logger; + parent::__construct(); + } + + protected function configure() { + $this + ->setName('encryption:migrate') + ->setDescription('initial migration to encryption 2.0') + ->addArgument( + 'user_id', + InputArgument::OPTIONAL | InputArgument::IS_ARRAY, + 'will migrate keys of the given user(s)' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + + // perform system reorganization + $migration = new Migration($this->config, $this->view, $this->connection, $this->logger); + + $users = $input->getArgument('user_id'); + if (!empty($users)) { + foreach ($users as $user) { + if ($this->userManager->userExists($user)) { + $output->writeln("Migrating keys <info>$user</info>"); + $migration->reorganizeFolderStructureForUser($user); + } else { + $output->writeln("<error>Unknown user $user</error>"); + } + } + } else { + $output->writeln("Reorganize system folder structure"); + $migration->reorganizeSystemFolderStructure(); + $migration->updateDB(); + foreach($this->userManager->getBackends() as $backend) { + $name = get_class($backend); + + if ($backend instanceof IUserBackend) { + $name = $backend->getBackendName(); + } + + $output->writeln("Migrating keys for users on backend <info>$name</info>"); + + $limit = 500; + $offset = 0; + do { + $users = $backend->getUsers('', $limit, $offset); + foreach ($users as $user) { + $output->writeln(" <info>$user</info>"); + $migration->reorganizeFolderStructureForUser($user); + } + $offset += $limit; + } while(count($users) >= $limit); + } + } + + $migration->finalCleanUp(); + + } +} diff --git a/apps/encryption/lib/Controller/RecoveryController.php b/apps/encryption/lib/Controller/RecoveryController.php new file mode 100644 index 00000000000..e4b02e004dc --- /dev/null +++ b/apps/encryption/lib/Controller/RecoveryController.php @@ -0,0 +1,192 @@ +<?php +/** + * @author Björn Schießle <schiessle@owncloud.com> + * @author Clark Tomlinson <fallen013@gmail.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 OCA\Encryption\Controller; + + +use OCA\Encryption\Recovery; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http; +use OCP\IConfig; +use OCP\IL10N; +use OCP\IRequest; +use OCP\AppFramework\Http\DataResponse; + +class RecoveryController extends Controller { + /** + * @var IConfig + */ + private $config; + /** + * @var IL10N + */ + private $l; + /** + * @var Recovery + */ + private $recovery; + + /** + * @param string $AppName + * @param IRequest $request + * @param IConfig $config + * @param IL10N $l10n + * @param Recovery $recovery + */ + public function __construct($AppName, + IRequest $request, + IConfig $config, + IL10N $l10n, + Recovery $recovery) { + parent::__construct($AppName, $request); + $this->config = $config; + $this->l = $l10n; + $this->recovery = $recovery; + } + + /** + * @param string $recoveryPassword + * @param string $confirmPassword + * @param string $adminEnableRecovery + * @return DataResponse + */ + public function adminRecovery($recoveryPassword, $confirmPassword, $adminEnableRecovery) { + // Check if both passwords are the same + if (empty($recoveryPassword)) { + $errorMessage = (string)$this->l->t('Missing recovery key password'); + return new DataResponse(['data' => ['message' => $errorMessage]], + Http::STATUS_BAD_REQUEST); + } + + if (empty($confirmPassword)) { + $errorMessage = (string)$this->l->t('Please repeat the recovery key password'); + return new DataResponse(['data' => ['message' => $errorMessage]], + Http::STATUS_BAD_REQUEST); + } + + if ($recoveryPassword !== $confirmPassword) { + $errorMessage = (string)$this->l->t('Repeated recovery key password does not match the provided recovery key password'); + return new DataResponse(['data' => ['message' => $errorMessage]], + Http::STATUS_BAD_REQUEST); + } + + if (isset($adminEnableRecovery) && $adminEnableRecovery === '1') { + if ($this->recovery->enableAdminRecovery($recoveryPassword)) { + return new DataResponse(['data' => ['message' => (string)$this->l->t('Recovery key successfully enabled')]]); + } + return new DataResponse(['data' => ['message' => (string)$this->l->t('Could not enable recovery key. Please check your recovery key password!')]], Http::STATUS_BAD_REQUEST); + } elseif (isset($adminEnableRecovery) && $adminEnableRecovery === '0') { + if ($this->recovery->disableAdminRecovery($recoveryPassword)) { + return new DataResponse(['data' => ['message' => (string)$this->l->t('Recovery key successfully disabled')]]); + } + return new DataResponse(['data' => ['message' => (string)$this->l->t('Could not disable recovery key. Please check your recovery key password!')]], Http::STATUS_BAD_REQUEST); + } + // this response should never be sent but just in case. + return new DataResponse(['data' => ['message' => (string)$this->l->t('Missing parameters')]], Http::STATUS_BAD_REQUEST); + } + + /** + * @param string $newPassword + * @param string $oldPassword + * @param string $confirmPassword + * @return DataResponse + */ + public function changeRecoveryPassword($newPassword, $oldPassword, $confirmPassword) { + //check if both passwords are the same + if (empty($oldPassword)) { + $errorMessage = (string)$this->l->t('Please provide the old recovery password'); + return new DataResponse(['data' => ['message' => $errorMessage]], Http::STATUS_BAD_REQUEST); + } + + if (empty($newPassword)) { + $errorMessage = (string)$this->l->t('Please provide a new recovery password'); + return new DataResponse (['data' => ['message' => $errorMessage]], Http::STATUS_BAD_REQUEST); + } + + if (empty($confirmPassword)) { + $errorMessage = (string)$this->l->t('Please repeat the new recovery password'); + return new DataResponse(['data' => ['message' => $errorMessage]], Http::STATUS_BAD_REQUEST); + } + + if ($newPassword !== $confirmPassword) { + $errorMessage = (string)$this->l->t('Repeated recovery key password does not match the provided recovery key password'); + return new DataResponse(['data' => ['message' => $errorMessage]], Http::STATUS_BAD_REQUEST); + } + + $result = $this->recovery->changeRecoveryKeyPassword($newPassword, + $oldPassword); + + if ($result) { + return new DataResponse( + [ + 'data' => [ + 'message' => (string)$this->l->t('Password successfully changed.')] + ] + ); + } + return new DataResponse( + [ + 'data' => [ + 'message' => (string)$this->l->t('Could not change the password. Maybe the old password was not correct.') + ] + ], Http::STATUS_BAD_REQUEST); + } + + /** + * @NoAdminRequired + * + * @param string $userEnableRecovery + * @return DataResponse + */ + public function userSetRecovery($userEnableRecovery) { + if ($userEnableRecovery === '0' || $userEnableRecovery === '1') { + + $result = $this->recovery->setRecoveryForUser($userEnableRecovery); + + if ($result) { + if ($userEnableRecovery === '0') { + return new DataResponse( + [ + 'data' => [ + 'message' => (string)$this->l->t('Recovery Key disabled')] + ] + ); + } + return new DataResponse( + [ + 'data' => [ + 'message' => (string)$this->l->t('Recovery Key enabled')] + ] + ); + } + + } + return new DataResponse( + [ + 'data' => [ + 'message' => (string)$this->l->t('Could not enable the recovery key, please try again or contact your administrator') + ] + ], Http::STATUS_BAD_REQUEST); + } + +} diff --git a/apps/encryption/lib/Controller/SettingsController.php b/apps/encryption/lib/Controller/SettingsController.php new file mode 100644 index 00000000000..5c171a23aec --- /dev/null +++ b/apps/encryption/lib/Controller/SettingsController.php @@ -0,0 +1,165 @@ +<?php +/** + * @author Björn Schießle <schiessle@owncloud.com> + * @author Joas Schilling <nickvergessen@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 OCA\Encryption\Controller; + +use OCA\Encryption\Crypto\Crypt; +use OCA\Encryption\KeyManager; +use OCA\Encryption\Session; +use OCA\Encryption\Util; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IL10N; +use OCP\IRequest; +use OCP\ISession; +use OCP\IUserManager; +use OCP\IUserSession; + +class SettingsController extends Controller { + + /** @var IL10N */ + private $l; + + /** @var IUserManager */ + private $userManager; + + /** @var IUserSession */ + private $userSession; + + /** @var KeyManager */ + private $keyManager; + + /** @var Crypt */ + private $crypt; + + /** @var Session */ + private $session; + + /** @var ISession */ + private $ocSession; + + /** @var Util */ + private $util; + + /** + * @param string $AppName + * @param IRequest $request + * @param IL10N $l10n + * @param IUserManager $userManager + * @param IUserSession $userSession + * @param KeyManager $keyManager + * @param Crypt $crypt + * @param Session $session + * @param ISession $ocSession + * @param Util $util + */ + public function __construct($AppName, + IRequest $request, + IL10N $l10n, + IUserManager $userManager, + IUserSession $userSession, + KeyManager $keyManager, + Crypt $crypt, + Session $session, + ISession $ocSession, + Util $util +) { + parent::__construct($AppName, $request); + $this->l = $l10n; + $this->userSession = $userSession; + $this->userManager = $userManager; + $this->keyManager = $keyManager; + $this->crypt = $crypt; + $this->session = $session; + $this->ocSession = $ocSession; + $this->util = $util; + } + + + /** + * @NoAdminRequired + * @UseSession + * + * @param string $oldPassword + * @param string $newPassword + * @return DataResponse + */ + public function updatePrivateKeyPassword($oldPassword, $newPassword) { + $result = false; + $uid = $this->userSession->getUser()->getUID(); + $errorMessage = $this->l->t('Could not update the private key password.'); + + //check if password is correct + $passwordCorrect = $this->userManager->checkPassword($uid, $newPassword); + if ($passwordCorrect === false) { + // if check with uid fails we need to check the password with the login name + // e.g. in the ldap case. For local user we need to check the password with + // the uid because in this case the login name is case insensitive + $loginName = $this->ocSession->get('loginname'); + $passwordCorrect = $this->userManager->checkPassword($loginName, $newPassword); + } + + if ($passwordCorrect !== false) { + $encryptedKey = $this->keyManager->getPrivateKey($uid); + $decryptedKey = $this->crypt->decryptPrivateKey($encryptedKey, $oldPassword, $uid); + + if ($decryptedKey) { + $encryptedKey = $this->crypt->encryptPrivateKey($decryptedKey, $newPassword, $uid); + $header = $this->crypt->generateHeader(); + if ($encryptedKey) { + $this->keyManager->setPrivateKey($uid, $header . $encryptedKey); + $this->session->setPrivateKey($decryptedKey); + $result = true; + } + } else { + $errorMessage = $this->l->t('The old password was not correct, please try again.'); + } + } else { + $errorMessage = $this->l->t('The current log-in password was not correct, please try again.'); + } + + if ($result === true) { + $this->session->setStatus(Session::INIT_SUCCESSFUL); + return new DataResponse( + ['message' => (string) $this->l->t('Private key password successfully updated.')] + ); + } else { + return new DataResponse( + ['message' => (string) $errorMessage], + Http::STATUS_BAD_REQUEST + ); + } + + } + + /** + * @UseSession + * + * @param bool $encryptHomeStorage + * @return DataResponse + */ + public function setEncryptHomeStorage($encryptHomeStorage) { + $this->util->setEncryptHomeStorage($encryptHomeStorage); + return new DataResponse(); + } +} diff --git a/apps/encryption/lib/Controller/StatusController.php b/apps/encryption/lib/Controller/StatusController.php new file mode 100644 index 00000000000..99fdc68c3d0 --- /dev/null +++ b/apps/encryption/lib/Controller/StatusController.php @@ -0,0 +1,98 @@ +<?php +/** + * @author Björn Schießle <schiessle@owncloud.com> + * @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 OCA\Encryption\Controller; + + +use OCA\Encryption\Session; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\DataResponse; +use OCP\IL10N; +use OCP\IRequest; + +class StatusController extends Controller { + + /** @var IL10N */ + private $l; + + /** @var Session */ + private $session; + + /** + * @param string $AppName + * @param IRequest $request + * @param IL10N $l10n + * @param Session $session + */ + public function __construct($AppName, + IRequest $request, + IL10N $l10n, + Session $session + ) { + parent::__construct($AppName, $request); + $this->l = $l10n; + $this->session = $session; + } + + /** + * @NoAdminRequired + * @return DataResponse + */ + public function getStatus() { + + $status = 'error'; + $message = 'no valid init status'; + switch( $this->session->getStatus()) { + case Session::RUN_MIGRATION: + $status = 'interactionNeeded'; + $message = (string)$this->l->t( + 'You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please run \'occ encryption:migrate\' or contact your administrator' + ); + break; + case Session::INIT_EXECUTED: + $status = 'interactionNeeded'; + $message = (string)$this->l->t( + 'Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files.' + ); + break; + case Session::NOT_INITIALIZED: + $status = 'interactionNeeded'; + $message = (string)$this->l->t( + 'Encryption App is enabled but your keys are not initialized, please log-out and log-in again' + ); + break; + case Session::INIT_SUCCESSFUL: + $status = 'success'; + $message = (string)$this->l->t('Encryption App is enabled and ready'); + } + + return new DataResponse( + [ + 'status' => $status, + 'data' => [ + 'message' => $message] + ] + ); + } + +} diff --git a/apps/encryption/lib/crypto/crypt.php b/apps/encryption/lib/Crypto/Crypt.php index ca70c88488f..ca70c88488f 100644 --- a/apps/encryption/lib/crypto/crypt.php +++ b/apps/encryption/lib/Crypto/Crypt.php diff --git a/apps/encryption/lib/crypto/decryptall.php b/apps/encryption/lib/Crypto/DecryptAll.php index 694aba2fb89..694aba2fb89 100644 --- a/apps/encryption/lib/crypto/decryptall.php +++ b/apps/encryption/lib/Crypto/DecryptAll.php diff --git a/apps/encryption/lib/crypto/encryptall.php b/apps/encryption/lib/Crypto/EncryptAll.php index 0037c213265..0037c213265 100644 --- a/apps/encryption/lib/crypto/encryptall.php +++ b/apps/encryption/lib/Crypto/EncryptAll.php diff --git a/apps/encryption/lib/crypto/encryption.php b/apps/encryption/lib/Crypto/Encryption.php index 6eff66e72be..6eff66e72be 100644 --- a/apps/encryption/lib/crypto/encryption.php +++ b/apps/encryption/lib/Crypto/Encryption.php diff --git a/apps/encryption/lib/exceptions/multikeydecryptexception.php b/apps/encryption/lib/Exceptions/MultiKeyDecryptException.php index 59bea59344d..59bea59344d 100644 --- a/apps/encryption/lib/exceptions/multikeydecryptexception.php +++ b/apps/encryption/lib/Exceptions/MultiKeyDecryptException.php diff --git a/apps/encryption/lib/exceptions/multikeyencryptexception.php b/apps/encryption/lib/Exceptions/MultiKeyEncryptException.php index bc0872ffdd2..bc0872ffdd2 100644 --- a/apps/encryption/lib/exceptions/multikeyencryptexception.php +++ b/apps/encryption/lib/Exceptions/MultiKeyEncryptException.php diff --git a/apps/encryption/lib/exceptions/privatekeymissingexception.php b/apps/encryption/lib/Exceptions/PrivateKeyMissingException.php index fe162a8f5c4..fe162a8f5c4 100644 --- a/apps/encryption/lib/exceptions/privatekeymissingexception.php +++ b/apps/encryption/lib/Exceptions/PrivateKeyMissingException.php diff --git a/apps/encryption/lib/exceptions/publickeymissingexception.php b/apps/encryption/lib/Exceptions/PublicKeyMissingException.php index 6fad4693dcc..6fad4693dcc 100644 --- a/apps/encryption/lib/exceptions/publickeymissingexception.php +++ b/apps/encryption/lib/Exceptions/PublicKeyMissingException.php diff --git a/apps/encryption/lib/hookmanager.php b/apps/encryption/lib/HookManager.php index a4269dca031..a4269dca031 100644 --- a/apps/encryption/lib/hookmanager.php +++ b/apps/encryption/lib/HookManager.php diff --git a/apps/encryption/lib/Hooks/Contracts/IHook.php b/apps/encryption/lib/Hooks/Contracts/IHook.php new file mode 100644 index 00000000000..4bf7ead8c15 --- /dev/null +++ b/apps/encryption/lib/Hooks/Contracts/IHook.php @@ -0,0 +1,32 @@ +<?php +/** + * @author Clark Tomlinson <fallen013@gmail.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 OCA\Encryption\Hooks\Contracts; + + +interface IHook { + /** + * Connects Hooks + * + * @return null + */ + public function addHooks(); +} diff --git a/apps/encryption/lib/Hooks/UserHooks.php b/apps/encryption/lib/Hooks/UserHooks.php new file mode 100644 index 00000000000..136a1832101 --- /dev/null +++ b/apps/encryption/lib/Hooks/UserHooks.php @@ -0,0 +1,322 @@ +<?php +/** + * @author Björn Schießle <schiessle@owncloud.com> + * @author Clark Tomlinson <fallen013@gmail.com> + * @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 OCA\Encryption\Hooks; + + +use OC\Files\Filesystem; +use OCP\IUserManager; +use OCP\Util as OCUtil; +use OCA\Encryption\Hooks\Contracts\IHook; +use OCA\Encryption\KeyManager; +use OCA\Encryption\Crypto\Crypt; +use OCA\Encryption\Users\Setup; +use OCP\App; +use OCP\ILogger; +use OCP\IUserSession; +use OCA\Encryption\Util; +use OCA\Encryption\Session; +use OCA\Encryption\Recovery; + +class UserHooks implements IHook { + /** + * @var KeyManager + */ + private $keyManager; + /** + * @var IUserManager + */ + private $userManager; + /** + * @var ILogger + */ + private $logger; + /** + * @var Setup + */ + private $userSetup; + /** + * @var IUserSession + */ + private $user; + /** + * @var Util + */ + private $util; + /** + * @var Session + */ + private $session; + /** + * @var Recovery + */ + private $recovery; + /** + * @var Crypt + */ + private $crypt; + + /** + * UserHooks constructor. + * + * @param KeyManager $keyManager + * @param IUserManager $userManager + * @param ILogger $logger + * @param Setup $userSetup + * @param IUserSession $user + * @param Util $util + * @param Session $session + * @param Crypt $crypt + * @param Recovery $recovery + */ + public function __construct(KeyManager $keyManager, + IUserManager $userManager, + ILogger $logger, + Setup $userSetup, + IUserSession $user, + Util $util, + Session $session, + Crypt $crypt, + Recovery $recovery) { + + $this->keyManager = $keyManager; + $this->userManager = $userManager; + $this->logger = $logger; + $this->userSetup = $userSetup; + $this->user = $user; + $this->util = $util; + $this->session = $session; + $this->recovery = $recovery; + $this->crypt = $crypt; + } + + /** + * Connects Hooks + * + * @return null + */ + public function addHooks() { + OCUtil::connectHook('OC_User', 'post_login', $this, 'login'); + OCUtil::connectHook('OC_User', 'logout', $this, 'logout'); + + // this hooks only make sense if no master key is used + if ($this->util->isMasterKeyEnabled() === false) { + OCUtil::connectHook('OC_User', + 'post_setPassword', + $this, + 'setPassphrase'); + + OCUtil::connectHook('OC_User', + 'pre_setPassword', + $this, + 'preSetPassphrase'); + + OCUtil::connectHook('OC_User', + 'post_createUser', + $this, + 'postCreateUser'); + + OCUtil::connectHook('OC_User', + 'post_deleteUser', + $this, + 'postDeleteUser'); + } + } + + + /** + * Startup encryption backend upon user login + * + * @note This method should never be called for users using client side encryption + * @param array $params + * @return boolean|null + */ + public function login($params) { + + if (!App::isEnabled('encryption')) { + return true; + } + + // ensure filesystem is loaded + if (!\OC\Files\Filesystem::$loaded) { + $this->setupFS($params['uid']); + } + if ($this->util->isMasterKeyEnabled() === false) { + $this->userSetup->setupUser($params['uid'], $params['password']); + } + + $this->keyManager->init($params['uid'], $params['password']); + } + + /** + * remove keys from session during logout + */ + public function logout() { + $this->session->clear(); + } + + /** + * setup encryption backend upon user created + * + * @note This method should never be called for users using client side encryption + * @param array $params + */ + public function postCreateUser($params) { + + if (App::isEnabled('encryption')) { + $this->userSetup->setupUser($params['uid'], $params['password']); + } + } + + /** + * cleanup encryption backend upon user deleted + * + * @param array $params : uid, password + * @note This method should never be called for users using client side encryption + */ + public function postDeleteUser($params) { + + if (App::isEnabled('encryption')) { + $this->keyManager->deletePublicKey($params['uid']); + } + } + + /** + * If the password can't be changed within ownCloud, than update the key password in advance. + * + * @param array $params : uid, password + * @return boolean|null + */ + public function preSetPassphrase($params) { + if (App::isEnabled('encryption')) { + + $user = $this->userManager->get($params['uid']); + + if ($user && !$user->canChangePassword()) { + $this->setPassphrase($params); + } + } + } + + /** + * Change a user's encryption passphrase + * + * @param array $params keys: uid, password + * @return boolean|null + */ + public function setPassphrase($params) { + + // Get existing decrypted private key + $privateKey = $this->session->getPrivateKey(); + $user = $this->user->getUser(); + + // current logged in user changes his own password + if ($user && $params['uid'] === $user->getUID() && $privateKey) { + + // Encrypt private key with new user pwd as passphrase + $encryptedPrivateKey = $this->crypt->encryptPrivateKey($privateKey, $params['password'], $params['uid']); + + // Save private key + if ($encryptedPrivateKey) { + $this->keyManager->setPrivateKey($this->user->getUser()->getUID(), + $this->crypt->generateHeader() . $encryptedPrivateKey); + } else { + $this->logger->error('Encryption could not update users encryption password'); + } + + // NOTE: Session does not need to be updated as the + // private key has not changed, only the passphrase + // used to decrypt it has changed + } else { // admin changed the password for a different user, create new keys and re-encrypt file keys + $user = $params['uid']; + $this->initMountPoints($user); + $recoveryPassword = isset($params['recoveryPassword']) ? $params['recoveryPassword'] : null; + + // we generate new keys if... + // ...we have a recovery password and the user enabled the recovery key + // ...encryption was activated for the first time (no keys exists) + // ...the user doesn't have any files + if ( + ($this->recovery->isRecoveryEnabledForUser($user) && $recoveryPassword) + || !$this->keyManager->userHasKeys($user) + || !$this->util->userHasFiles($user) + ) { + + // backup old keys + //$this->backupAllKeys('recovery'); + + $newUserPassword = $params['password']; + + $keyPair = $this->crypt->createKeyPair(); + + // Save public key + $this->keyManager->setPublicKey($user, $keyPair['publicKey']); + + // Encrypt private key with new password + $encryptedKey = $this->crypt->encryptPrivateKey($keyPair['privateKey'], $newUserPassword, $user); + + if ($encryptedKey) { + $this->keyManager->setPrivateKey($user, $this->crypt->generateHeader() . $encryptedKey); + + if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files + $this->recovery->recoverUsersFiles($recoveryPassword, $user); + } + } else { + $this->logger->error('Encryption Could not update users encryption password'); + } + } + } + } + + /** + * init mount points for given user + * + * @param string $user + * @throws \OC\User\NoUserException + */ + protected function initMountPoints($user) { + Filesystem::initMountPoints($user); + } + + + /** + * after password reset we create a new key pair for the user + * + * @param array $params + */ + public function postPasswordReset($params) { + $password = $params['password']; + + $this->keyManager->deleteUserKeys($params['uid']); + $this->userSetup->setupUser($params['uid'], $password); + } + + /** + * setup file system for user + * + * @param string $uid user id + */ + protected function setupFS($uid) { + \OC_Util::setupFS($uid); + } +} diff --git a/apps/encryption/lib/keymanager.php b/apps/encryption/lib/KeyManager.php index 4f22c3def63..4f22c3def63 100644 --- a/apps/encryption/lib/keymanager.php +++ b/apps/encryption/lib/KeyManager.php diff --git a/apps/encryption/lib/migration.php b/apps/encryption/lib/Migration.php index db9541d6f5a..db9541d6f5a 100644 --- a/apps/encryption/lib/migration.php +++ b/apps/encryption/lib/Migration.php diff --git a/apps/encryption/lib/recovery.php b/apps/encryption/lib/Recovery.php index f0ac7bb2383..f0ac7bb2383 100644 --- a/apps/encryption/lib/recovery.php +++ b/apps/encryption/lib/Recovery.php diff --git a/apps/encryption/lib/session.php b/apps/encryption/lib/Session.php index 62cc09b018d..62cc09b018d 100644 --- a/apps/encryption/lib/session.php +++ b/apps/encryption/lib/Session.php diff --git a/apps/encryption/lib/users/setup.php b/apps/encryption/lib/Users/Setup.php index e59340c4ce2..e59340c4ce2 100644 --- a/apps/encryption/lib/users/setup.php +++ b/apps/encryption/lib/Users/Setup.php diff --git a/apps/encryption/lib/util.php b/apps/encryption/lib/Util.php index e87ed478a1a..e87ed478a1a 100644 --- a/apps/encryption/lib/util.php +++ b/apps/encryption/lib/Util.php |