From 63e7fe608a5f507c5d2b417c45cf26589d091ebc Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Wed, 14 Jan 2015 20:39:23 +0100 Subject: create basic interfaces and wrapper to make encryption more modular --- lib/private/encryption/keystorage.php | 223 ++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 lib/private/encryption/keystorage.php (limited to 'lib/private/encryption') diff --git a/lib/private/encryption/keystorage.php b/lib/private/encryption/keystorage.php new file mode 100644 index 00000000000..5b56f6af4e7 --- /dev/null +++ b/lib/private/encryption/keystorage.php @@ -0,0 +1,223 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library 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 library. If not, see . + */ + +namespace OC\Encryption; + +class KeyStorage implements \OCP\Encryption\IKeyStorage { + + /** @var \OC\Files\View */ + private $view; + + /** @var \OC\Encryption\Util */ + private $util; + + // base dir where all the file related keys are stored + private static $keys_base_dir = '/files_encryption/keys/'; + private static $encryption_base_dir = '/files_encryption'; + + private static $key_cache = array(); // cache keys + + /** + * @param \OC\Files\View $view + * @param \OC\Encryption\Util $util + */ + public function __construct(\OC\Files\View $view, \OC\Encryption\Util $util) { + $this->view = $view; + $this->util = $util; + } + + /** + * get user specific key + * + * @param string $uid ID if the user for whom we want the key + * @param string $keyid id of the key + * + * @return mixed key + */ + public function getUserKey($uid, $keyid) { + $path = '/' . $uid . self::$encryption_base_dir . '/' . $uid . '.' . $keyid; + return $this->getKey($path); + + } + + /** + * get file specific key + * + * @param string $path path to file + * @param string $keyId id of the key + * + * @return mixed key + */ + public function getFileKey($path, $keyId) { + $keyDir = $this->getFileKeyDir($path); + return $this->getKey($keyDir . $keyId); + } + + /** + * get system-wide encryption keys not related to a specific user, + * e.g something like a key for public link shares + * + * @param string $keyId id of the key + * + * @return mixed key + */ + public function getSystemUserKey($keyId) { + $path = '/' . self::$encryption_base_dir . '/' . $keyId; + return $this->getKey($path); + } + + /** + * set user specific key + * + * @param string $uid ID if the user for whom we want the key + * @param string $keyId id of the key + * @param mixed $key + */ + public function setUserKey($uid, $keyId, $key) { + $path = '/' . $uid . self::$encryption_base_dir . '/' . $uid . '.' . $keyId; + return $this->setKey($path, $key); + } + + /** + * set file specific key + * + * @param string $path path to file + * @param string $keyId id of the key + * @param mixed $key + */ + public function setFileKey($path, $keyId, $key) { + $keyDir = $this->getFileKeyDir($path); + return $this->setKey($keyDir . $keyId, $key); + } + + /** + * set system-wide encryption keys not related to a specific user, + * e.g something like a key for public link shares + * + * @param string $keyId id of the key + * @param mixed $key + * + * @return mixed key + */ + public function setSystemUserKey($keyId, $key) { + $path = '/' . self::$encryption_base_dir . '/' . $keyId; + return $this->setKey($path, $key); + } + + + /** + * read key from hard disk + * + * @param string $path to key + * @return string + */ + private function getKey($path) { + + $key = ''; + + if (isset(self::$key_cache[$path])) { + $key = self::$key_cache[$path]; + } else { + + /** @var \OCP\Files\Storage $storage */ + list($storage, $internalPath) = $this->view->resolvePath($path); + + if ($storage->file_exists($internalPath)) { + $key = $storage->file_get_contents($internalPath); + self::$key_cache[$path] = $key; + } + + } + + return $key; + } + + /** + * write key to disk + * + * + * @param string $path path to key directory + * @param string $key key + * @return bool + */ + private function setKey($path, $key) { + $this->keySetPreparation(dirname($path)); + + /** @var \OCP\Files\Storage $storage */ + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($path); + $result = $storage->file_put_contents($internalPath, $key); + + if (is_int($result) && $result > 0) { + self::$key_cache[$path] = $key; + return true; + } + + return false; + } + + /** + * get path to key folder for a given file + * + * @param string $path path to the file, relative to the users file directory + * @return string + */ + private function getFileKeyDir($path) { + + if ($this->view->is_dir('/' . \OCP\User::getUser() . '/' . $path)) { + throw new Exception\EncryptionException('file was expected but directoy was given', Exception\EncryptionException::GENERIC); + } + + list($owner, $filename) = $this->util->getUidAndFilename($path); + $filename = $this->util->stripPartialFileExtension($filename); + $filePath_f = ltrim($filename, '/'); + + // in case of system wide mount points the keys are stored directly in the data directory + if ($this->util->isSystemWideMountPoint($filename)) { + $keyPath = self::$keys_base_dir . $filePath_f . '/'; + } else { + $keyPath = '/' . $owner . self::$keys_base_dir . $filePath_f . '/'; + } + + return $keyPath; + } + + /** + * Make preparations to filesystem for saving a keyfile + * + * @param string $path relative to the views root + */ + protected function keySetPreparation($path) { + // If the file resides within a subdirectory, create it + if (!$this->view->file_exists($path)) { + $sub_dirs = explode('/', $path); + $dir = ''; + foreach ($sub_dirs as $sub_dir) { + $dir .= '/' . $sub_dir; + if (!$this->view->is_dir($dir)) { + $this->view->mkdir($dir); + } + } + } + } + +} -- cgit v1.2.3 From 39733c8da1c12cc79b7d650edf2ea1074330ee5f Mon Sep 17 00:00:00 2001 From: Clark Tomlinson Date: Tue, 24 Feb 2015 13:05:19 -0500 Subject: Initial commit --- apps/encryption/appinfo/app.php | 33 ++ apps/encryption/appinfo/encryption.php | 182 +++++++++++ apps/encryption/appinfo/info.xml | 36 +++ apps/encryption/appinfo/routes.php | 39 +++ apps/encryption/controller/recoverycontroller.php | 106 ++++++ apps/encryption/hooks/apphooks.php | 37 +++ apps/encryption/hooks/contracts/ihook.php | 32 ++ apps/encryption/hooks/filesystemhooks.php | 46 +++ apps/encryption/hooks/sharehooks.php | 40 +++ apps/encryption/hooks/userhooks.php | 304 ++++++++++++++++++ apps/encryption/lib/crypto/Encryption.php | 116 +++++++ apps/encryption/lib/crypto/crypt.php | 355 +++++++++++++++++++++ apps/encryption/lib/hookmanager.php | 64 ++++ apps/encryption/lib/keymanager.php | 217 +++++++++++++ apps/encryption/lib/migrator.php | 123 +++++++ apps/encryption/lib/recovery.php | 134 ++++++++ apps/encryption/lib/setup.php | 38 +++ apps/encryption/lib/users/setup.php | 63 ++++ apps/encryption/settings/settings-admin.php | 24 ++ apps/encryption/settings/settings-personal.php | 41 +++ apps/encryption/tests/lib/KeyManagerTest.php | 90 ++++++ apps/encryption/tests/lib/MigratorTest.php | 62 ++++ .../tests/lib/RequirementsCheckerTest.php | 51 +++ apps/files_encryption/lib/hooks.php | 226 ------------- .../exceptions/decryptionfailedexception.php | 28 ++ .../exceptions/emptyencryptiondataexception.php | 28 ++ .../exceptions/encryptionfailedexception.php | 28 ++ .../encryptionheadertolargeexception.php | 28 ++ .../exceptions/genericencryptionexception.php | 27 ++ .../exceptions/privatekeymissingexception.php | 28 ++ .../exceptions/publickeymissingexception.php | 28 ++ .../exceptions/unexpectedblocksizeexception.php | 28 ++ .../unexpectedendofencryptionheaderexception.php | 28 ++ .../exceptions/unknowncipherexception.php | 28 ++ lib/private/encryption/keystorage.php | 57 +++- lib/public/encryption/ikeystorage.php | 30 +- tests/lib/encryption/managertest.php | 58 ++++ 37 files changed, 2630 insertions(+), 253 deletions(-) create mode 100644 apps/encryption/appinfo/app.php create mode 100644 apps/encryption/appinfo/encryption.php create mode 100644 apps/encryption/appinfo/info.xml create mode 100644 apps/encryption/appinfo/routes.php create mode 100644 apps/encryption/controller/recoverycontroller.php create mode 100644 apps/encryption/hooks/apphooks.php create mode 100644 apps/encryption/hooks/contracts/ihook.php create mode 100644 apps/encryption/hooks/filesystemhooks.php create mode 100644 apps/encryption/hooks/sharehooks.php create mode 100644 apps/encryption/hooks/userhooks.php create mode 100644 apps/encryption/lib/crypto/Encryption.php create mode 100644 apps/encryption/lib/crypto/crypt.php create mode 100644 apps/encryption/lib/hookmanager.php create mode 100644 apps/encryption/lib/keymanager.php create mode 100644 apps/encryption/lib/migrator.php create mode 100644 apps/encryption/lib/recovery.php create mode 100644 apps/encryption/lib/setup.php create mode 100644 apps/encryption/lib/users/setup.php create mode 100644 apps/encryption/settings/settings-admin.php create mode 100644 apps/encryption/settings/settings-personal.php create mode 100644 apps/encryption/tests/lib/KeyManagerTest.php create mode 100644 apps/encryption/tests/lib/MigratorTest.php create mode 100644 apps/encryption/tests/lib/RequirementsCheckerTest.php create mode 100644 lib/private/encryption/exceptions/decryptionfailedexception.php create mode 100644 lib/private/encryption/exceptions/emptyencryptiondataexception.php create mode 100644 lib/private/encryption/exceptions/encryptionfailedexception.php create mode 100644 lib/private/encryption/exceptions/encryptionheadertolargeexception.php create mode 100644 lib/private/encryption/exceptions/genericencryptionexception.php create mode 100644 lib/private/encryption/exceptions/privatekeymissingexception.php create mode 100644 lib/private/encryption/exceptions/publickeymissingexception.php create mode 100644 lib/private/encryption/exceptions/unexpectedblocksizeexception.php create mode 100644 lib/private/encryption/exceptions/unexpectedendofencryptionheaderexception.php create mode 100644 lib/private/encryption/exceptions/unknowncipherexception.php (limited to 'lib/private/encryption') diff --git a/apps/encryption/appinfo/app.php b/apps/encryption/appinfo/app.php new file mode 100644 index 00000000000..72e7fc42ca0 --- /dev/null +++ b/apps/encryption/appinfo/app.php @@ -0,0 +1,33 @@ + + * @since 2/19/15, 9:52 AM + * @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 + * + */ + +use OCA\Encryption\AppInfo\Encryption; + +if (!OC::$CLI) { + $di = \OC::$server; + $app = new Encryption('encryption', + [], + $di->getEncryptionManager(), + $di->getConfig()); + + $app->boot(); +} + diff --git a/apps/encryption/appinfo/encryption.php b/apps/encryption/appinfo/encryption.php new file mode 100644 index 00000000000..f2ab89aadef --- /dev/null +++ b/apps/encryption/appinfo/encryption.php @@ -0,0 +1,182 @@ + + * @since 3/11/15, 11:03 AM + * @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 + * + */ +namespace OCA\Encryption\AppInfo; + + +use OCA\Encryption\Crypto\Crypt; +use OCA\Encryption\HookManager; +use OCA\Encryption\Hooks\AppHooks; +use OCA\Encryption\Hooks\FileSystemHooks; +use OCA\Encryption\Hooks\ShareHooks; +use OCA\Encryption\Hooks\UserHooks; +use OCA\Encryption\KeyManager; +use OCA\Encryption\Migrator; +use OCA\Encryption\Recovery; +use OCA\Encryption\Users\Setup; +use OCP\App; +use OCP\AppFramework\IAppContainer; +use OCP\Encryption\IManager; +use OCP\IConfig; + + +class Encryption extends \OCP\AppFramework\App { + /** + * @var IManager + */ + private $encryptionManager; + /** + * @var IConfig + */ + private $config; + + /** + * @param $appName + * @param array $urlParams + * @param IManager $encryptionManager + * @param IConfig $config + */ + public function __construct($appName, $urlParams = array(), IManager $encryptionManager, IConfig $config) { + parent::__construct($appName, $urlParams); + $this->encryptionManager = $encryptionManager; + $this->config = $config; + } + + /** + * + */ + public function boot() { + $this->registerServices(); + $this->registerHooks(); + $this->registerEncryptionModule(); + $this->registerSettings(); + } + + /** + * + */ + 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->getLogger(), + $container->query('UserSetup'), + $container->query('Migrator'), + $server->getUserSession()), +// new ShareHooks(), +// new FileSystemHooks(), +// new AppHooks() + ]); + + $hookManager->fireHooks(); + + } else { + // Logout user if we are in maintenance to force re-login + $this->getContainer()->getServer()->getUserSession()->logout(); + } + } + + /** + * + */ + public function registerEncryptionModule() { +// $this->encryptionManager->registerEncryptionModule(new \OCA\Encryption\Crypto\Encryption()); + } + + /** + * + */ + public function registerServices() { + $container = $this->getContainer(); + + $container->registerService('Crypt', + function (IAppContainer $c) { + $server = $c->getServer(); + return new Crypt($server->getLogger(), + $server->getUserSession(), + $server->getConfig()); + }); + + $container->registerService('KeyManager', + function (IAppContainer $c) { + $server = $c->getServer(); + + return new KeyManager($server->getEncryptionKeyStorage(), + $c->query('Crypt'), + $server->getConfig(), + $server->getUserSession()); + }); + + + $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()); + }); + + $container->registerService('UserSetup', + function (IAppContainer $c) { + $server = $c->getServer(); + return new Setup($server->getLogger(), + $server->getUserSession(), + $c->query('Crypt'), + $c->query('KeyManager')); + }); + + $container->registerService('Migrator', + function (IAppContainer $c) { + $server = $c->getServer(); + + return new Migrator($server->getUserSession(), + $server->getConfig(), + $server->getUserManager(), + $server->getLogger(), + $c->query('Crypt')); + }); + + } + + /** + * + */ + public function registerSettings() { + +// script('encryption', 'encryption'); +// script('encryption', 'detect-migration'); + + + // Register settings scripts + App::registerAdmin('encryption', 'settings/settings-admin'); + App::registerPersonal('encryption', 'settings/settings-personal'); + } +} diff --git a/apps/encryption/appinfo/info.xml b/apps/encryption/appinfo/info.xml new file mode 100644 index 00000000000..e4a7d790e9c --- /dev/null +++ b/apps/encryption/appinfo/info.xml @@ -0,0 +1,36 @@ + + + encryption + + This application encrypts all files accessed by ownCloud at rest, + wherever they are stored. As an example, with this application + enabled, external cloud based Amazon S3 storage will be encrypted, + protecting this data on storage outside of the control of the Admin. + When this application is enabled for the first time, all files are + encrypted as users log in and are prompted for their password. The + recommended recovery key option enables recovery of files in case + the key is lost. + Note that this app encrypts all files that are touched by ownCloud, + so external storage providers and applications such as SharePoint + will see new files encrypted when they are accessed. Encryption is + based on AES 128 or 256 bit keys. More information is available in + the Encryption documentation + +Encryption + AGPL + Bjoern Schiessle, Clark Tomlinson + 8 + true + + user-encryption + admin-encryption + + false + + + + + openssl + + + diff --git a/apps/encryption/appinfo/routes.php b/apps/encryption/appinfo/routes.php new file mode 100644 index 00000000000..a86f3717ce9 --- /dev/null +++ b/apps/encryption/appinfo/routes.php @@ -0,0 +1,39 @@ + + * @since 2/19/15, 11:22 AM + * @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 + * + */ + + +use OCP\AppFramework\App; + +(new App('encryption'))->registerRoutes($this, array('routes' => array( + + [ + 'name' => 'recovery#adminRecovery', + 'url' => '/ajax/adminRecovery', + 'verb' => 'POST' + ], + [ + 'name' => 'recovery#userRecovery', + 'url' => '/ajax/userRecovery', + 'verb' => 'POST' + ] + + +))); diff --git a/apps/encryption/controller/recoverycontroller.php b/apps/encryption/controller/recoverycontroller.php new file mode 100644 index 00000000000..abea8993336 --- /dev/null +++ b/apps/encryption/controller/recoverycontroller.php @@ -0,0 +1,106 @@ + + * @since 2/19/15, 11:25 AM + * @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 + * + */ + +namespace OCA\Encryption\Controller; + + +use OCA\Encryption\Recovery; +use OCP\AppFramework\Controller; +use OCP\IConfig; +use OCP\IL10N; +use OCP\IRequest; +use OCP\JSON; +use Symfony\Component\HttpFoundation\JsonResponse; + +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; + } + + public function adminRecovery($recoveryPassword, $confirmPassword, $adminEnableRecovery) { + // Check if both passwords are the same + if (empty($recoveryPassword)) { + $errorMessage = $this->l->t('Missing recovery key password'); + return new JsonResponse(['data' => ['message' => $errorMessage]], 500); + } + + if (empty($confirmPassword)) { + $errorMessage = $this->l->t('Please repeat the recovery key password'); + return new JsonResponse(['data' => ['message' => $errorMessage]], 500); + } + + if ($recoveryPassword !== $confirmPassword) { + $errorMessage = $this->l->t('Repeated recovery key password does not match the provided recovery key password'); + return new JsonResponse(['data' => ['message' => $errorMessage]], 500); + } + + // Enable recoveryAdmin + $recoveryKeyId = $this->config->getAppValue('encryption', 'recoveryKeyId'); + + if (isset($adminEnableRecovery) && $adminEnableRecovery === '1') { + if ($this->recovery->enableAdminRecovery($recoveryKeyId, $recoveryPassword)) { + return new JsonResponse(['data' => array('message' => $this->l->t('Recovery key successfully enabled'))]); + } + return new JsonResponse(['data' => array('message' => $this->l->t('Could not enable recovery key. Please check your recovery key password!'))]); + } elseif (isset($adminEnableRecovery) && $adminEnableRecovery === '0') { + if ($this->recovery->disableAdminRecovery($recoveryKeyId, $recoveryPassword)) { + return new JsonResponse(['data' => array('message' => $this->l->t('Recovery key successfully disabled'))]); + } + return new JsonResponse(['data' => array('message' => $this->l->t('Could not disable recovery key. Please check your recovery key password!'))]); + } + } + + public function userRecovery($userEnableRecovery) { + if (isset($userEnableRecovery) && ($userEnableRecovery === '0' || $userEnableRecovery === '1')) { + $userId = $this->user->getUID(); + if ($userEnableRecovery === '1') { + // Todo xxx figure out if we need keyid's here or what. + return $this->recovery->addRecoveryKeys(); + } + // Todo xxx see :98 + return $this->recovery->removeRecoveryKeys(); + } + } + +} diff --git a/apps/encryption/hooks/apphooks.php b/apps/encryption/hooks/apphooks.php new file mode 100644 index 00000000000..713e9cadef6 --- /dev/null +++ b/apps/encryption/hooks/apphooks.php @@ -0,0 +1,37 @@ + + * @since 2/19/15, 10:02 AM + * @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 + * + */ + +namespace OCA\Encryption\Hooks; + +use OCA\Encryption\Hooks\Contracts\IHook; +use OCP\Util; + +class AppHooks implements IHook { + /** + * Connects Hooks + * + * @return null + */ + public function addHooks() { + Util::connectHook('OC_App', 'pre_disable', 'OCA\Encryption\Hooks', 'preDisable'); + Util::connectHook('OC_App', 'post_disable', 'OCA\Encryption\Hooks', 'postEnable'); + } +} diff --git a/apps/encryption/hooks/contracts/ihook.php b/apps/encryption/hooks/contracts/ihook.php new file mode 100644 index 00000000000..2cc01fd7c9b --- /dev/null +++ b/apps/encryption/hooks/contracts/ihook.php @@ -0,0 +1,32 @@ + + * @since 2/19/15, 10:03 AM + * @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 + * + */ + +namespace OCA\Encryption\Hooks\Contracts; + + +interface IHook { + /** + * Connects Hooks + * + * @return null + */ + public function addHooks(); +} diff --git a/apps/encryption/hooks/filesystemhooks.php b/apps/encryption/hooks/filesystemhooks.php new file mode 100644 index 00000000000..fda6b75b299 --- /dev/null +++ b/apps/encryption/hooks/filesystemhooks.php @@ -0,0 +1,46 @@ + + * @since 2/19/15, 10:02 AM + * @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 + * + */ + +namespace OCA\Encryption\Hooks; + + +use OCA\Encryption\Hooks\Contracts\IHook; +use OCP\Util; + +class FileSystemHooks implements IHook { + + /** + * Connects Hooks + * + * @return null + */ + public function addHooks() { + Util::connectHook('OC_Filesystem', 'rename', 'OCA\Encryption\Hooks', 'preRename'); + Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRenameOrCopy'); + Util::connectHook('OC_Filesystem', 'copy', 'OCA\Encryption\Hooks', 'preCopy'); + Util::connectHook('OC_Filesystem', 'post_copy', 'OCA\Encryption\Hooks', 'postRenameOrCopy'); + Util::connectHook('OC_Filesystem', 'post_delete', 'OCA\Encryption\Hooks', 'postDelete'); + Util::connectHook('OC_Filesystem', 'delete', 'OCA\Encryption\Hooks', 'preDelete'); + Util::connectHook('\OC\Core\LostPassword\Controller\LostController', 'post_passwordReset', 'OCA\Encryption\Hooks', 'postPasswordReset'); + Util::connectHook('OC_Filesystem', 'post_umount', 'OCA\Encryption\Hooks', 'postUnmount'); + Util::connectHook('OC_Filesystem', 'umount', 'OCA\Encryption\Hooks', 'preUnmount'); + } +} diff --git a/apps/encryption/hooks/sharehooks.php b/apps/encryption/hooks/sharehooks.php new file mode 100644 index 00000000000..fc50712b821 --- /dev/null +++ b/apps/encryption/hooks/sharehooks.php @@ -0,0 +1,40 @@ + + * @since 2/19/15, 10:02 AM + * @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 + * + */ + +namespace OCA\Encryption\Hooks; + + +use OCA\Encryption\Hooks\Contracts\IHook; +use OCP\Util; + +class ShareHooks implements IHook { + + /** + * Connects Hooks + * + * @return null + */ + public function addHooks() { + Util::connectHook('OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared'); + Util::connectHook('OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared'); + Util::connectHook('OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare'); + } +} diff --git a/apps/encryption/hooks/userhooks.php b/apps/encryption/hooks/userhooks.php new file mode 100644 index 00000000000..79de70a6d02 --- /dev/null +++ b/apps/encryption/hooks/userhooks.php @@ -0,0 +1,304 @@ + + * @since 2/19/15, 10:02 AM + * @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 + * + */ + +namespace OCA\Encryption\Hooks; + + +use OCA\Encryption\Hooks\Contracts\IHook; +use OCA\Encryption\KeyManager; +use OCA\Encryption\Migrator; +use OCA\Encryption\RequirementsChecker; +use OCA\Encryption\Users\Setup; +use OCP\App; +use OCP\ILogger; +use OCP\IUserSession; +use OCP\Util; +use Test\User; + +class UserHooks implements IHook { + /** + * @var KeyManager + */ + private $keyManager; + /** + * @var ILogger + */ + private $logger; + /** + * @var Setup + */ + private $userSetup; + /** + * @var Migrator + */ + private $migrator; + /** + * @var IUserSession + */ + private $user; + + /** + * UserHooks constructor. + * + * @param KeyManager $keyManager + * @param ILogger $logger + * @param Setup $userSetup + * @param Migrator $migrator + * @param IUserSession $user + */ + public function __construct( + KeyManager $keyManager, ILogger $logger, Setup $userSetup, Migrator $migrator, IUserSession $user) { + + $this->keyManager = $keyManager; + $this->logger = $logger; + $this->userSetup = $userSetup; + $this->migrator = $migrator; + $this->user = $user; + } + + /** + * Connects Hooks + * + * @return null + */ + public function addHooks() { + Util::connectHook('OC_User', 'post_login', $this, 'login'); + Util::connectHook('OC_User', 'logout', $this, 'logout'); + Util::connectHook('OC_User', 'post_setPassword', $this, 'setPassphrase'); + Util::connectHook('OC_User', 'pre_setPassword', $this, 'preSetPassphrase'); + Util::connectHook('OC_User', 'post_createUser', $this, 'postCreateUser'); + Util::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 + */ + public function login($params) { + + if (!App::isEnabled('encryption')) { + return true; + } + + // ensure filesystem is loaded + // Todo: update? + if (!\OC\Files\Filesystem::$loaded) { + \OC_Util::setupFS($params['uid']); + } + + // setup user, if user not ready force relogin + if (!$this->userSetup->setupUser($params['password'])) { + return false; + } + + $cache = $this->keyManager->init(); + + // Check if first-run file migration has already been performed + $ready = false; + $migrationStatus = $this->migrator->getStatus($params['uid']); + if ($migrationStatus === Migrator::$migrationOpen && $cache !== false) { + $ready = $this->migrator->beginMigration(); + } elseif ($migrationStatus === Migrator::$migrationInProgress) { + // refuse login as long as the initial encryption is running + sleep(5); + $this->user->logout(); + return false; + } + + $result = true; + + // If migration not yet done + if ($ready) { + + // Encrypt existing user files + try { + $result = $util->encryptAll('/' . $params['uid'] . '/' . 'files'); + } catch (\Exception $ex) { + \OCP\Util::writeLog('Encryption library', 'Initial encryption failed! Error: ' . $ex->getMessage(), \OCP\Util::FATAL); + $result = false; + } + + if ($result) { + \OC_Log::write( + 'Encryption library', 'Encryption of existing files belonging to "' . $params['uid'] . '" completed' + , \OC_Log::INFO + ); + // Register successful migration in DB + $util->finishMigration(); + } else { + \OCP\Util::writeLog('Encryption library', 'Initial encryption failed!', \OCP\Util::FATAL); + $util->resetMigrationStatus(); + \OCP\User::logout(); + } + } + + return $result; + } + + /** + * remove keys from session during logout + */ + public function logout() { + $session = new Session(new \OC\Files\View()); + $session->removeKeys(); + } + + /** + * setup encryption backend upon user created + * + * @note This method should never be called for users using client side encryption + */ + public function postCreateUser($params) { + + if (App::isEnabled('files_encryption')) { + $view = new \OC\Files\View('/'); + $util = new Util($view, $params['uid']); + Helper::setupUser($util, $params['password']); + } + } + + /** + * cleanup encryption backend upon user deleted + * + * @note This method should never be called for users using client side encryption + */ + public function postDeleteUser($params) { + + if (App::isEnabled('files_encryption')) { + Keymanager::deletePublicKey(new \OC\Files\View(), $params['uid']); + } + } + + /** + * If the password can't be changed within ownCloud, than update the key password in advance. + */ + public function preSetPassphrase($params) { + if (App::isEnabled('files_encryption')) { + if (!\OC_User::canUserChangePassword($params['uid'])) { + self::setPassphrase($params); + } + } + } + + /** + * Change a user's encryption passphrase + * + * @param array $params keys: uid, password + */ + public function setPassphrase($params) { + if (App::isEnabled('files_encryption') === false) { + return true; + } + + // Only attempt to change passphrase if server-side encryption + // is in use (client-side encryption does not have access to + // the necessary keys) + if (Crypt::mode() === 'server') { + + $view = new \OC\Files\View('/'); + $session = new Session($view); + + // Get existing decrypted private key + $privateKey = $session->getPrivateKey(); + + if ($params['uid'] === \OCP\User::getUser() && $privateKey) { + + // Encrypt private key with new user pwd as passphrase + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($privateKey, $params['password'], Helper::getCipher()); + + // Save private key + if ($encryptedPrivateKey) { + Keymanager::setPrivateKey($encryptedPrivateKey, \OCP\User::getUser()); + } else { + \OCP\Util::writeLog('files_encryption', 'Could not update users encryption password', \OCP\Util::ERROR); + } + + // 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 reencrypt file keys + + $user = $params['uid']; + $util = new Util($view, $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 (($util->recoveryEnabledForUser() && $recoveryPassword) + || !$util->userKeysExists() + || !$view->file_exists($user . '/files') + ) { + + // backup old keys + $util->backupAllKeys('recovery'); + + $newUserPassword = $params['password']; + + // make sure that the users home is mounted + \OC\Files\Filesystem::initMountPoints($user); + + $keypair = Crypt::createKeypair(); + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + // Save public key + Keymanager::setPublicKey($keypair['publicKey'], $user); + + // Encrypt private key with new password + $encryptedKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $newUserPassword, Helper::getCipher()); + if ($encryptedKey) { + Keymanager::setPrivateKey($encryptedKey, $user); + + if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files + $util = new Util($view, $user); + $util->recoverUsersFiles($recoveryPassword); + } + } else { + \OCP\Util::writeLog('files_encryption', 'Could not update users encryption password', \OCP\Util::ERROR); + } + + \OC_FileProxy::$enabled = $proxyStatus; + } + } + } + } + + /** + * after password reset we create a new key pair for the user + * + * @param array $params + */ + public function postPasswordReset($params) { + $uid = $params['uid']; + $password = $params['password']; + + $util = new Util(new \OC\Files\View(), $uid); + $util->replaceUserKeys($password); + } +} diff --git a/apps/encryption/lib/crypto/Encryption.php b/apps/encryption/lib/crypto/Encryption.php new file mode 100644 index 00000000000..123581b83ac --- /dev/null +++ b/apps/encryption/lib/crypto/Encryption.php @@ -0,0 +1,116 @@ + + * @since 3/6/15, 2:28 PM + * @link http:/www.clarkt.com + * @copyright Clark Tomlinson © 2015 + * + */ + +namespace OCA\Encryption\Crypto; + + +use OCP\Encryption\IEncryptionModule; + +class Encryption extends Crypt implements IEncryptionModule { + + /** + * @return string defining the technical unique id + */ + public function getId() { + // TODO: Implement getId() method. + } + + /** + * In comparison to getKey() this function returns a human readable (maybe translated) name + * + * @return string + */ + public function getDisplayName() { + // TODO: Implement getDisplayName() method. + } + + /** + * start receiving chunks from a file. This is the place where you can + * perform some initial step before starting encrypting/decrypting the + * chunks + * + * @param string $path to the file + * @param array $header contains the header data read from the file + * @param array $accessList who has access to the file contains the key 'users' and 'public' + * + * $return array $header contain data as key-value pairs which should be + * written to the header, in case of a write operation + * or if no additional data is needed return a empty array + */ + public function begin($path, $header, $accessList) { + // TODO: Implement begin() method. + } + + /** + * last chunk received. This is the place where you can perform some final + * operation and return some remaining data if something is left in your + * buffer. + * + * @param string $path to the file + * @return string remained data which should be written to the file in case + * of a write operation + */ + public function end($path) { + // TODO: Implement end() method. + } + + /** + * encrypt data + * + * @param string $data you want to encrypt + * @return mixed encrypted data + */ + public function encrypt($data) { + // Todo: xxx Update Signature and usages + $this->symmetricEncryptFileContent($data); + } + + /** + * decrypt data + * + * @param string $data you want to decrypt + * @param string $user decrypt as user (null for public access) + * @return mixed decrypted data + */ + public function decrypt($data, $user) { + // Todo: xxx Update Usages? + $this->symmetricDecryptFileContent($data, $user); + } + + /** + * update encrypted file, e.g. give additional users access to the file + * + * @param string $path path to the file which should be updated + * @param array $accessList who has access to the file contains the key 'users' and 'public' + * @return boolean + */ + public function update($path, $accessList) { + // TODO: Implement update() method. + } + + /** + * should the file be encrypted or not + * + * @param string $path + * @return boolean + */ + public function shouldEncrypt($path) { + // TODO: Implement shouldEncrypt() method. + } + + /** + * calculate unencrypted size + * + * @param string $path to file + * @return integer unencrypted size + */ + public function calculateUnencryptedSize($path) { + // TODO: Implement calculateUnencryptedSize() method. + } +} diff --git a/apps/encryption/lib/crypto/crypt.php b/apps/encryption/lib/crypto/crypt.php new file mode 100644 index 00000000000..8018f11a370 --- /dev/null +++ b/apps/encryption/lib/crypto/crypt.php @@ -0,0 +1,355 @@ + + * @since 2/19/15, 1:42 PM + * @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 + * + */ + +namespace OCA\Encryption\Crypto; + + +use OC\Encryption\Exceptions\DecryptionFailedException; +use OC\Encryption\Exceptions\EncryptionFailedException; +use OC\Encryption\Exceptions\GenericEncryptionException; +use OCP\IConfig; +use OCP\ILogger; +use OCP\IUser; +use OCP\IUserSession; + +class Crypt { + + const ENCRYPTION_UKNOWN_ERROR = -1; + const ENCRYPTION_NOT_INIALIZED_ERROR = 1; + const ENCRYPTIION_PRIVATE_KEY_NOT_VALID_ERROR = 2; + const ENCRYPTION_NO_SHARE_KEY_FOUND = 3; + + const BLOCKSIZE = 8192; + const DEFAULT_CIPHER = 'AES-256-CFB'; + + const HEADERSTART = 'HBEGIN'; + const HEADEREND = 'HEND'; + /** + * @var ILogger + */ + private $logger; + /** + * @var IUser + */ + private $user; + /** + * @var IConfig + */ + private $config; + + /** + * @param ILogger $logger + * @param IUserSession $userSession + * @param IConfig $config + */ + public function __construct(ILogger $logger, IUserSession $userSession, IConfig $config) { + $this->logger = $logger; + $this->user = $userSession && $userSession->isLoggedIn() ? $userSession->getUser() : false; + $this->config = $config; + } + + /** + * @param null $user + * @return string + */ + public function mode($user = null) { + return 'server'; + } + + /** + * + */ + public function createKeyPair() { + + $log = $this->logger; + $res = $this->getOpenSSLPKey(); + + if (!$res) { + $log->error("Encryption Library could'nt generate users key-pair for {$this->user->getUID()}", ['app' => 'encryption']); + + if (openssl_error_string()) { + $log->error('Encryption library openssl_pkey_new() fails: ' . openssl_error_string(), ['app' => 'encryption']); + } + } elseif (openssl_pkey_export($res, $privateKey, null, $this->getOpenSSLConfig())) { + $keyDetails = openssl_pkey_get_details($res); + $publicKey = $keyDetails['key']; + + return [ + 'publicKey' => $publicKey, + 'privateKey' => $privateKey + ]; + } + $log->error('Encryption library couldn\'t export users private key, please check your servers openSSL configuration.' . $user->getUID(), ['app' => 'encryption']); + if (openssl_error_string()) { + $log->error('Encryption Library:' . openssl_error_string(), ['app' => 'encryption']); + } + + return false; + } + + /** + * @return resource + */ + public function getOpenSSLPKey() { + $config = $this->getOpenSSLConfig(); + return openssl_pkey_new($config); + } + + /** + * @return array + */ + private function getOpenSSLConfig() { + $config = ['private_key_bits' => 4096]; + $config = array_merge(\OC::$server->getConfig()->getSystemValue('openssl', []), $config); + return $config; + } + + /** + * @param $plainContent + * @param $passphrase + * @return bool|string + * @throws GenericEncryptionException + */ + public function symmetricEncryptFileContent($plainContent, $passphrase) { + + if (!$plainContent) { + $this->logger->error('Encryption Library, symmetrical encryption failed no content given', ['app' => 'encryption']); + return false; + } + + $iv = $this->generateIv(); + + try { + $encryptedContent = $this->encrypt($plainContent, $iv, $passphrase, $this->getCipher()); + // combine content to encrypt the IV identifier and actual IV + $catFile = $this->concatIV($encryptedContent, $iv); + $padded = $this->addPadding($catFile); + + return $padded; + } catch (EncryptionFailedException $e) { + $message = 'Could not encrypt file content (code: ' . $e->getCode() . '): '; + $this->logger->error('files_encryption' . $message . $e->getMessage(), ['app' => 'encryption']); + return false; + } + + } + + /** + * @param $plainContent + * @param $iv + * @param string $passphrase + * @param string $cipher + * @return string + * @throws EncryptionFailedException + */ + private function encrypt($plainContent, $iv, $passphrase = '', $cipher = self::DEFAULT_CIPHER) { + $encryptedContent = openssl_encrypt($plainContent, $cipher, $passphrase, false, $iv); + + if (!$encryptedContent) { + $error = 'Encryption (symmetric) of content failed'; + $this->logger->error($error . openssl_error_string(), ['app' => 'encryption']); + throw new EncryptionFailedException($error); + } + + return $encryptedContent; + } + + /** + * @return mixed|string + */ + public function getCipher() { + $cipher = $this->config->getSystemValue('cipher', self::DEFAULT_CIPHER); + if ($cipher !== 'AES-256-CFB' || $cipher !== 'AES-128-CFB') { + $this->logger->warning('Wrong cipher defined in config.php only AES-128-CFB and AES-256-CFB are supported. Fall back' . self::DEFAULT_CIPHER, ['app' => 'encryption']); + $cipher = self::DEFAULT_CIPHER; + } + + return $cipher; + } + + /** + * @param $encryptedContent + * @param $iv + * @return string + */ + private function concatIV($encryptedContent, $iv) { + return $encryptedContent . '00iv00' . $iv; + } + + /** + * @param $data + * @return string + */ + private function addPadding($data) { + return $data . 'xx'; + } + + /** + * @param $recoveryKey + * @param $password + * @return bool|string + */ + public function decryptPrivateKey($recoveryKey, $password) { + + $header = $this->parseHeader($recoveryKey); + $cipher = $this->getCipher($header); + + // If we found a header we need to remove it from the key we want to decrypt + if (!empty($header)) { + $recoveryKey = substr($recoveryKey, strpos($recoveryKey, self::HEADEREND) + strlen(self::HEADERSTART)); + } + + $plainKey = $this->symmetricDecryptFileContent($recoveryKey, $password, $cipher); + + // Check if this is a valid private key + $res = openssl_get_privatekey($plainKey); + if (is_resource($res)) { + $sslInfo = openssl_pkey_get_details($res); + if (!isset($sslInfo['key'])) { + return false; + } + } else { + return false; + } + + return $plainKey; + } + + /** + * @param $keyFileContents + * @param string $passphrase + * @param string $cipher + * @return bool|string + * @throws DecryptionFailedException + */ + public function symmetricDecryptFileContent($keyFileContents, $passphrase = '', $cipher = self::DEFAULT_CIPHER) { + // Remove Padding + $noPadding = $this->removePadding($keyFileContents); + + $catFile = $this->splitIv($noPadding); + + $plainContent = $this->decrypt($catFile['encrypted'], $catFile['iv'], $passphrase, $cipher); + + if ($plainContent) { + return $plainContent; + } + + return false; + } + + /** + * @param $padded + * @return bool|string + */ + private function removePadding($padded) { + if (substr($padded, -2) === 'xx') { + return substr($padded, 0, -2); + } + return false; + } + + /** + * @param $catFile + * @return array + */ + private function splitIv($catFile) { + // Fetch encryption metadata from end of file + $meta = substr($catFile, -22); + + // Fetch IV from end of file + $iv = substr($meta, -16); + + // Remove IV and IV Identifier text to expose encrypted content + + $encrypted = substr($catFile, 0, -22); + + return [ + 'encrypted' => $encrypted, + 'iv' => $iv + ]; + } + + /** + * @param $encryptedContent + * @param $iv + * @param string $passphrase + * @param string $cipher + * @return string + * @throws DecryptionFailedException + */ + private function decrypt($encryptedContent, $iv, $passphrase = '', $cipher = self::DEFAULT_CIPHER) { + $plainContent = openssl_decrypt($encryptedContent, $cipher, $passphrase, false, $iv); + + if ($plainContent) { + return $plainContent; + } else { + throw new DecryptionFailedException('Encryption library: Decryption (symmetric) of content failed'); + } + } + + /** + * @param $data + * @return array + */ + private function parseHeader($data) { + $result = []; + + if (substr($data, 0, strlen(self::HEADERSTART)) === self::HEADERSTART) { + $endAt = strpos($data, self::HEADEREND); + $header = substr($data, 0, $endAt + strlen(self::HEADEREND)); + + // +1 not to start with an ':' which would result in empty element at the beginning + $exploded = explode(':', substr($header, strlen(self::HEADERSTART) + 1)); + + $element = array_shift($exploded); + + while ($element != self::HEADEREND) { + $result[$element] = array_shift($exploded); + $element = array_shift($exploded); + } + } + + return $result; + } + + /** + * @return string + * @throws GenericEncryptionException + */ + private function generateIv() { + $random = openssl_random_pseudo_bytes(12, $strong); + if ($random) { + if (!$strong) { + // If OpenSSL indicates randomness is insecure log error + $this->logger->error('Encryption Library: Insecure symmetric key was generated using openssl_random_psudo_bytes()', ['app' => 'encryption']); + } + + /* + * We encode the iv purely for string manipulation + * purposes -it gets decoded before use + */ + return base64_encode($random); + } + // If we ever get here we've failed anyway no need for an else + throw new GenericEncryptionException('Generating IV Failed'); + } +} + diff --git a/apps/encryption/lib/hookmanager.php b/apps/encryption/lib/hookmanager.php new file mode 100644 index 00000000000..a535230a6a7 --- /dev/null +++ b/apps/encryption/lib/hookmanager.php @@ -0,0 +1,64 @@ + + * @since 2/19/15, 10:13 AM + * @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 + * + */ + +namespace OCA\Encryption; + + +use OCA\Encryption\Hooks\Contracts\IHook; + +class HookManager { + + private $hookInstances = []; + + /** + * @param array|IHook $instances + * - This accepts either a single instance of IHook or an array of instances of IHook + * @return bool + */ + public function registerHook($instances) { + if (is_array($instances)) { + foreach ($instances as $instance) { + if (!$instance instanceof IHook) { + return false; + } + $this->hookInstances[] = $instance; + return true; + } + + } + $this->hookInstances[] = $instances; + return true; + } + + /** + * + */ + public function fireHooks() { + foreach ($this->hookInstances as $instance) { + /** + * @var $instance IHook + */ + $instance->addHooks(); + } + + } + +} diff --git a/apps/encryption/lib/keymanager.php b/apps/encryption/lib/keymanager.php new file mode 100644 index 00000000000..272bf0849c2 --- /dev/null +++ b/apps/encryption/lib/keymanager.php @@ -0,0 +1,217 @@ + + * @since 2/19/15, 1:20 PM + * @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 + * + */ + +namespace OCA\Encryption; + + +use OC\Encryption\Exceptions\PrivateKeyMissingException; +use OC\Encryption\Exceptions\PublicKeyMissingException; +use OCA\Encryption\Crypto\Crypt; +use OCP\Encryption\IKeyStorage; +use OCP\IConfig; +use OCP\IUser; +use OCP\IUserSession; + +class KeyManager { + + /** + * @var IKeyStorage + */ + private $keyStorage; + + /** + * @var Crypt + */ + private $crypt; + /** + * @var string + */ + private $recoveryKeyId; + /** + * @var string + */ + private $publicShareKeyId; + /** + * @var string UserID + */ + private $keyId; + + /** + * @var string + */ + private $publicKeyId = '.public'; + /** + * @var string + */ + private $privateKeyId = '.private'; + /** + * @var IConfig + */ + private $config; + + /** + * @param IKeyStorage $keyStorage + * @param Crypt $crypt + * @param IConfig $config + * @param IUserSession $userSession + */ + public function __construct(IKeyStorage $keyStorage, Crypt $crypt, IConfig $config, IUserSession $userSession) { + + $this->keyStorage = $keyStorage; + $this->crypt = $crypt; + $this->config = $config; + $this->recoveryKeyId = $this->config->getAppValue('encryption', 'recoveryKeyId'); + $this->publicShareKeyId = $this->config->getAppValue('encryption', 'publicShareKeyId'); + $this->keyId = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : false; + + } + + /** + * @param $userId + * @return mixed + * @throws PrivateKeyMissingException + */ + public function getPrivateKey($userId) { + $privateKey = $this->keyStorage->getUserKey($userId, $this->privateKeyId); + + if (strlen($privateKey) !== 0) { + return $privateKey; + } + throw new PrivateKeyMissingException(); + } + + /** + * @param $userId + * @return mixed + * @throws PublicKeyMissingException + */ + public function getPublicKey($userId) { + $publicKey = $this->keyStorage->getUserKey($userId, $this->publicKeyId); + + if (strlen($publicKey) !== 0) { + return $publicKey; + } + throw new PublicKeyMissingException(); + } + + /** + * @return bool + */ + public function recoveryKeyExists() { + return (strlen($this->keyStorage->getSystemUserKey($this->recoveryKeyId)) !== 0); + } + + /** + * @param $userId + * @return bool + */ + public function userHasKeys($userId) { + try { + $this->getPrivateKey($userId); + $this->getPublicKey($userId); + } catch (PrivateKeyMissingException $e) { + return false; + } catch (PublicKeyMissingException $e) { + return false; + } + return true; + } + + /** + * @param $password + * @return bool + */ + public function checkRecoveryPassword($password) { + $recoveryKey = $this->keyStorage->getSystemUserKey($this->recoveryKeyId); + $decryptedRecoveryKey = $this->crypt->decryptPrivateKey($recoveryKey, $password); + + if ($decryptedRecoveryKey) { + return true; + } + return false; + } + + /** + * @param $userId + * @param $key + * @return bool + */ + public function setPublicKey($userId, $key) { + return $this->keyStorage->setUserKey($userId, $this->publicKeyId, $key); + } + + /** + * @param $userId + * @param $key + * @return bool + */ + public function setPrivateKey($userId, $key) { + return $this->keyStorage->setUserKey($userId, $this->privateKeyId, $key); + } + + + /** + * @param $password + * @param $keyPair + * @return bool + */ + public function storeKeyPair($password, $keyPair) { + // Save Public Key + $this->setPublicKey($this->keyId, $keyPair['publicKey']); + + $encryptedKey = $this->crypt->symmetricEncryptFileContent($keyPair['privateKey'], $password); + + if ($encryptedKey) { + $this->setPrivateKey($this->keyId, $encryptedKey); + $this->config->setAppValue('encryption', 'recoveryAdminEnabled', 1); + return true; + } + return false; + } + + /** + * @return bool + */ + public function ready() { + return $this->keyStorage->ready(); + } + + + /** + * @return \OCP\ICache + * @throws PrivateKeyMissingException + */ + public function init() { + try { + $privateKey = $this->getPrivateKey($this->keyId); + } catch (PrivateKeyMissingException $e) { + return false; + } + + $cache = \OC::$server->getMemCacheFactory(); + + $cacheInstance = $cache->create('Encryption'); + $cacheInstance->set('privateKey', $privateKey); + + return $cacheInstance; + } + +} diff --git a/apps/encryption/lib/migrator.php b/apps/encryption/lib/migrator.php new file mode 100644 index 00000000000..8f7823cb1ae --- /dev/null +++ b/apps/encryption/lib/migrator.php @@ -0,0 +1,123 @@ + + * @since 3/9/15, 2:44 PM + * @link http:/www.clarkt.com + * @copyright Clark Tomlinson © 2015 + * + */ + +namespace OCA\Encryption; + + +use OCA\Encryption\Crypto\Crypt; +use OCP\IConfig; +use OCP\ILogger; +use OCP\IUserManager; +use OCP\IUserSession; +use OCP\PreConditionNotMetException; + +class Migrator { + + /** + * @var bool + */ + private $status = false; + /** + * @var IUserManager + */ + private $user; + /** + * @var IConfig + */ + private $config; + /** + * @var string + */ + public static $migrationOpen = '0'; + /** + * @var string + */ + public static $migrationInProgress = '-1'; + /** + * @var string + */ + public static $migrationComplete = '1'; + /** + * @var IUserManager + */ + private $userManager; + /** + * @var ILogger + */ + private $log; + /** + * @var Crypt + */ + private $crypt; + + /** + * Migrator constructor. + * + * @param IUserSession $userSession + * @param IConfig $config + * @param IUserManager $userManager + * @param ILogger $log + * @param Crypt $crypt + */ + public function __construct(IUserSession $userSession, IConfig $config, IUserManager $userManager, ILogger $log, Crypt $crypt) { + $this->user = $userSession && $userSession->isLoggedIn() ? $userSession->getUser() : false; + $this->config = $config; + $this->userManager = $userManager; + $this->log = $log; + $this->crypt = $crypt; + } + + /** + * @param $userId + * @return bool|string + */ + public function getStatus($userId) { + if ($this->userManager->userExists($userId)) { + $this->status = $this->config->getUserValue($userId, 'encryption', 'migrationStatus', false); + + if (!$this->status) { + $this->config->setUserValue($userId, 'encryption', 'migrationStatus', self::$migrationOpen); + $this->status = self::$migrationOpen; + } + } + + return $this->status; + } + + /** + * @return bool + */ + public function beginMigration() { + $status = $this->setMigrationStatus(self::$migrationInProgress, self::$migrationOpen); + + if ($status) { + $this->log->info('Encryption Library Start migration to encrypt for ' . $this->user->getUID()); + return $status; + } + $this->log->warning('Encryption Library Could not activate migration for ' . $this->user->getUID() . '. Probably another process already started the inital encryption'); + return $status; + } + + /** + * @param $status + * @param bool $preCondition + * @return bool + */ + private function setMigrationStatus($status, $preCondition = false) { + // Convert to string if preCondition is set + $preCondition = ($preCondition === false) ? false : (string)$preCondition; + + try { + $this->config->setUserValue($this->user->getUID(), 'encryption', 'migrationStatus', (string)$status, $preCondition); + return true; + } catch (PreConditionNotMetException $e) { + return false; + } + } +} diff --git a/apps/encryption/lib/recovery.php b/apps/encryption/lib/recovery.php new file mode 100644 index 00000000000..88350e96c53 --- /dev/null +++ b/apps/encryption/lib/recovery.php @@ -0,0 +1,134 @@ + + * @since 2/19/15, 11:45 AM + * @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 + * + */ + +namespace OCA\Encryption; + + +use OC\Files\View; +use OCA\Encryption\Crypto\Crypt; +use OCP\Encryption\IKeyStorage; +use OCP\IConfig; +use OCP\IUser; +use OCP\Security\ISecureRandom; + +class Recovery { + + + /** + * @var null|IUser + */ + protected $user; + /** + * @var Crypt + */ + protected $crypt; + /** + * @var ISecureRandom + */ + private $random; + /** + * @var KeyManager + */ + private $keyManager; + /** + * @var IConfig + */ + private $config; + /** + * @var IEncryptionKeyStorage + */ + private $keyStorage; + + /** + * @param IUser $user + * @param Crypt $crypt + * @param ISecureRandom $random + * @param KeyManager $keyManager + * @param IConfig $config + * @param IKeyStorage $keyStorage + */ + public function __construct(IUser $user, + Crypt $crypt, + ISecureRandom $random, + KeyManager $keyManager, + IConfig $config, + IKeyStorage $keyStorage) { + $this->user = $user; + $this->crypt = $crypt; + $this->random = $random; + $this->keyManager = $keyManager; + $this->config = $config; + $this->keyStorage = $keyStorage; + } + + /** + * @param $recoveryKeyId + * @param $password + * @return bool + */ + public function enableAdminRecovery($recoveryKeyId, $password) { + $appConfig = $this->config; + + if ($recoveryKeyId === null) { + $recoveryKeyId = $this->random->getLowStrengthGenerator(); + $appConfig->setAppValue('encryption', 'recoveryKeyId', $recoveryKeyId); + } + + $keyManager = $this->keyManager; + + if (!$keyManager->recoveryKeyExists()) { + $keyPair = $this->crypt->createKeyPair(); + + return $this->keyManager->storeKeyPair($password, $keyPair); + } + + if ($keyManager->checkRecoveryPassword($password)) { + $appConfig->setAppValue('encryption', 'recoveryAdminEnabled', 1); + return true; + } + + return false; + } + + /** + * @param $recoveryPassword + * @return bool + */ + public function disableAdminRecovery($recoveryPassword) { + $keyManager = $this->keyManager; + + if ($keyManager->checkRecoveryPassword($recoveryPassword)) { + // Set recoveryAdmin as disabled + $this->config->setAppValue('encryption', 'recoveryAdminEnabled', 0); + return true; + } + return false; + } + + public function addRecoveryKeys($keyId) { + // No idea new way to do this.... + } + + public function removeRecoveryKeys() { + // No idea new way to do this.... + } + +} diff --git a/apps/encryption/lib/setup.php b/apps/encryption/lib/setup.php new file mode 100644 index 00000000000..cc8f00f0a40 --- /dev/null +++ b/apps/encryption/lib/setup.php @@ -0,0 +1,38 @@ + + * @since 3/6/15, 11:30 AM + * @link http:/www.clarkt.com + * @copyright Clark Tomlinson © 2015 + * + */ + +namespace OCA\Encryption; + + +use OCP\ILogger; +use OCP\IUser; +use OCP\IUserSession; + +class Setup { + /** + * @var ILogger + */ + protected $logger; + /** + * @var IUser + */ + protected $user; + + /** + * Setup constructor. + * + * @param ILogger $logger + * @param IUserSession $userSession + */ + public function __construct(ILogger $logger, IUserSession $userSession) { + $this->logger = $logger; + $this->user = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : false; + + } +} diff --git a/apps/encryption/lib/users/setup.php b/apps/encryption/lib/users/setup.php new file mode 100644 index 00000000000..123d6973be9 --- /dev/null +++ b/apps/encryption/lib/users/setup.php @@ -0,0 +1,63 @@ + + * @since 3/6/15, 11:36 AM + * @link http:/www.clarkt.com + * @copyright Clark Tomlinson © 2015 + * + */ + +namespace OCA\Encryption\Users; + + +use OCA\Encryption\Crypto\Crypt; +use OCA\Encryption\KeyManager; +use OCP\ILogger; +use OCP\IUserSession; + +class Setup extends \OCA\Encryption\Setup { + /** + * @var Crypt + */ + private $crypt; + /** + * @var KeyManager + */ + private $keyManager; + + + /** + * @param ILogger $logger + * @param IUserSession $userSession + * @param Crypt $crypt + * @param KeyManager $keyManager + */ + public function __construct(ILogger $logger, IUserSession $userSession, Crypt $crypt, KeyManager $keyManager) { + parent::__construct($logger, $userSession); + $this->crypt = $crypt; + $this->keyManager = $keyManager; + } + + /** + * @param $password + * @return bool + */ + public function setupUser($password) { + if ($this->keyManager->ready()) { + $this->logger->debug('Encryption Library: User Account ' . $this->user->getUID() . ' Is not ready for encryption; configuration started'); + return $this->setupServerSide($password); + } + } + + /** + * @param $password + * @return bool + */ + private function setupServerSide($password) { + // Check if user already has keys + if (!$this->keyManager->userHasKeys($this->user->getUID())) { + return $this->keyManager->storeKeyPair($password, $this->crypt->createKeyPair()); + } + return true; + } +} diff --git a/apps/encryption/settings/settings-admin.php b/apps/encryption/settings/settings-admin.php new file mode 100644 index 00000000000..0f5d56a3734 --- /dev/null +++ b/apps/encryption/settings/settings-admin.php @@ -0,0 +1,24 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +\OC_Util::checkAdminUser(); + +$tmpl = new OCP\Template('files_encryption', 'settings-admin'); + +// Check if an adminRecovery account is enabled for recovering files after lost pwd +$recoveryAdminEnabled = \OC::$server->getAppConfig()->getValue('files_encryption', 'recoveryAdminEnabled', '0'); +$session = new \OCA\Files_Encryption\Session(new \OC\Files\View('/')); +$initStatus = $session->getInitialized(); + +$tmpl->assign('recoveryEnabled', $recoveryAdminEnabled); +$tmpl->assign('initStatus', $initStatus); + +\OCP\Util::addscript('files_encryption', 'settings-admin'); +\OCP\Util::addscript('core', 'multiselect'); + +return $tmpl->fetchPage(); diff --git a/apps/encryption/settings/settings-personal.php b/apps/encryption/settings/settings-personal.php new file mode 100644 index 00000000000..fe2d846f50a --- /dev/null +++ b/apps/encryption/settings/settings-personal.php @@ -0,0 +1,41 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +// Add CSS stylesheet +\OC_Util::addStyle('files_encryption', 'settings-personal'); + +$tmpl = new OCP\Template('files_encryption', 'settings-personal'); + +$user = \OCP\USER::getUser(); +$view = new \OC\Files\View('/'); +$util = new \OCA\Files_Encryption\Util($view, $user); +$session = new \OCA\Files_Encryption\Session($view); + +$privateKeySet = $session->getPrivateKey() !== false; +// did we tried to initialize the keys for this session? +$initialized = $session->getInitialized(); + +$recoveryAdminEnabled = \OC::$server->getAppConfig()->getValue('files_encryption', 'recoveryAdminEnabled'); +$recoveryEnabledForUser = $util->recoveryEnabledForUser(); + +$result = false; + +if ($recoveryAdminEnabled || !$privateKeySet) { + + \OCP\Util::addscript('files_encryption', 'settings-personal'); + + $tmpl->assign('recoveryEnabled', $recoveryAdminEnabled); + $tmpl->assign('recoveryEnabledForUser', $recoveryEnabledForUser); + $tmpl->assign('privateKeySet', $privateKeySet); + $tmpl->assign('initialized', $initialized); + + $result = $tmpl->fetchPage(); +} + +return $result; + diff --git a/apps/encryption/tests/lib/KeyManagerTest.php b/apps/encryption/tests/lib/KeyManagerTest.php new file mode 100644 index 00000000000..260e69a73bf --- /dev/null +++ b/apps/encryption/tests/lib/KeyManagerTest.php @@ -0,0 +1,90 @@ + + * @since 3/5/15, 10:53 AM + * @link http:/www.clarkt.com + * @copyright Clark Tomlinson © 2015 + * + */ + +namespace OCA\Encryption\Tests; + + +use OCA\Encryption\KeyManager; +use Test\TestCase; + +class KeyManagerTest extends TestCase { + /** + * @var KeyManager + */ + private $instance; + /** + * @var + */ + private $userId; + /** + * @var + */ + private $dummyKeys; + + public function setUp() { + parent::setUp(); + $keyStorageMock = $this->getMock('OCP\Encryption\IKeyStorage'); + $cryptMock = $this->getMockBuilder('OCA\Encryption\Crypt') + ->disableOriginalConstructor() + ->getMock(); + $configMock = $this->getMock('OCP\IConfig'); + $userMock = $this->getMock('OCP\IUser'); + $userMock->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('admin')); + $this->userId = 'admin'; + $this->instance = new KeyManager($keyStorageMock, $cryptMock, $configMock, $userMock); + + $this->dummyKeys = ['public' => 'randomweakpublickeyhere', + 'private' => 'randomweakprivatekeyhere']; + } + + /** + * @expectedException OC\Encryption\Exceptions\PrivateKeyMissingException + */ + public function testGetPrivateKey() { + $this->assertFalse($this->instance->getPrivateKey($this->userId)); + } + + /** + * @expectedException OC\Encryption\Exceptions\PublicKeyMissingException + */ + public function testGetPublicKey() { + $this->assertFalse($this->instance->getPublicKey($this->userId)); + } + + /** + * + */ + public function testRecoveryKeyExists() { + $this->assertFalse($this->instance->recoveryKeyExists()); + } + + /** + * + */ + public function testCheckRecoveryKeyPassword() { + $this->assertFalse($this->instance->checkRecoveryPassword('pass')); + } + + public function testSetPublicKey() { + + $this->assertTrue($this->instance->setPublicKey($this->userId, $this->dummyKeys['public'])); + } + + public function testSetPrivateKey() { + $this->assertTrue($this->instance->setPrivateKey($this->userId, $this->dummyKeys['private'])); + } + + public function testUserHasKeys() { + $this->assertFalse($this->instance->userHasKeys($this->userId)); + } + + +} diff --git a/apps/encryption/tests/lib/MigratorTest.php b/apps/encryption/tests/lib/MigratorTest.php new file mode 100644 index 00000000000..a9d57b34209 --- /dev/null +++ b/apps/encryption/tests/lib/MigratorTest.php @@ -0,0 +1,62 @@ + + * @since 3/9/15, 2:56 PM + * @link http:/www.clarkt.com + * @copyright Clark Tomlinson © 2015 + * + */ + +namespace OCA\Encryption\Tests; + + +use OCA\Encryption\Migrator; +use Test\TestCase; + +class MigratorTest extends TestCase { + + /** + * @var Migrator + */ + private $instance; + + /** + * + */ + public function testGetStatus() { + $this->assertFalse($this->instance->getStatus('admin')); + } + + /** + * + */ + public function testBeginMigration() { + $this->assertTrue($this->instance->beginMigration()); + } + + /** + * + */ + public function testSetMigrationStatus() { + $this->assertTrue(\Test_Helper::invokePrivate($this->instance, + 'setMigrationStatus', + ['0', '-1']) + ); + } + + /** + * + */ + protected function setUp() { + parent::setUp(); + + $cryptMock = $this->getMockBuilder('OCA\Encryption\Crypto\Crypt')->disableOriginalConstructor()->getMock(); + $this->instance = new Migrator($this->getMock('OCP\IUser'), + $this->getMock('OCP\IConfig'), + $this->getMock('OCP\IUserManager'), + $this->getMock('OCP\ILogger'), + $cryptMock); + } + + +} diff --git a/apps/encryption/tests/lib/RequirementsCheckerTest.php b/apps/encryption/tests/lib/RequirementsCheckerTest.php new file mode 100644 index 00000000000..97ddd76b750 --- /dev/null +++ b/apps/encryption/tests/lib/RequirementsCheckerTest.php @@ -0,0 +1,51 @@ + + * @since 3/6/15, 10:36 AM + * @link http:/www.clarkt.com + * @copyright Clark Tomlinson © 2015 + * + */ + +namespace OCA\Encryption\Tests; + + +use OCA\Encryption\RequirementsChecker; +use Test\TestCase; + +class RequirementsCheckerTest extends TestCase { + /** + * @var RequirementsChecker + */ + private $instance; + + /** + * + */ + protected function setUp() { + parent::setUp(); + $log = $this->getMock('OCP\ILogger'); + $crypt = $this->getMockBuilder('OCA\Encryption\Crypt') + ->disableOriginalConstructor() + ->getMock(); + $crypt + ->method('getOpenSSLPkey') + ->will($this->returnValue(true)); + $this->instance = new RequirementsChecker($crypt, $log); + } + + /** + * + */ + public function testCanCheckConfigration() { + $this->assertTrue($this->instance->checkConfiguration()); + } + + /** + * + */ + public function testCanCheckRequiredExtensions() { + $this->assertTrue($this->instance->checkExtensions()); + } + +} diff --git a/apps/files_encryption/lib/hooks.php b/apps/files_encryption/lib/hooks.php index 4a29ffaaedf..536e512bdb2 100644 --- a/apps/files_encryption/lib/hooks.php +++ b/apps/files_encryption/lib/hooks.php @@ -34,234 +34,8 @@ class Hooks { // file for which we want to delete the keys after the delete operation was successful private static $unmountedFiles = array(); - /** - * Startup encryption backend upon user login - * @note This method should never be called for users using client side encryption - */ - public static function login($params) { - - if (\OCP\App::isEnabled('files_encryption') === false) { - return true; - } - - - $l = new \OC_L10N('files_encryption'); - - $view = new \OC\Files\View('/'); - - // ensure filesystem is loaded - if (!\OC\Files\Filesystem::$loaded) { - \OC_Util::setupFS($params['uid']); - } - - $privateKey = Keymanager::getPrivateKey($view, $params['uid']); - - // if no private key exists, check server configuration - if (!$privateKey) { - //check if all requirements are met - if (!Helper::checkRequirements() || !Helper::checkConfiguration()) { - $error_msg = $l->t("Missing requirements."); - $hint = $l->t('Please make sure that OpenSSL together with the PHP extension is enabled and configured properly. For now, the encryption app has been disabled.'); - \OC_App::disable('files_encryption'); - \OCP\Util::writeLog('Encryption library', $error_msg . ' ' . $hint, \OCP\Util::ERROR); - \OCP\Template::printErrorPage($error_msg, $hint); - } - } - - $util = new Util($view, $params['uid']); - - // setup user, if user not ready force relogin - if (Helper::setupUser($util, $params['password']) === false) { - return false; - } - - $session = $util->initEncryption($params); - - // Check if first-run file migration has already been performed - $ready = false; - $migrationStatus = $util->getMigrationStatus(); - if ($migrationStatus === Util::MIGRATION_OPEN && $session !== false) { - $ready = $util->beginMigration(); - } elseif ($migrationStatus === Util::MIGRATION_IN_PROGRESS) { - // refuse login as long as the initial encryption is running - sleep(5); - \OCP\User::logout(); - return false; - } - - $result = true; - - // If migration not yet done - if ($ready) { - - // Encrypt existing user files - try { - $result = $util->encryptAll('/' . $params['uid'] . '/' . 'files'); - } catch (\Exception $ex) { - \OCP\Util::writeLog('Encryption library', 'Initial encryption failed! Error: ' . $ex->getMessage(), \OCP\Util::FATAL); - $result = false; - } - - if ($result) { - \OC_Log::write( - 'Encryption library', 'Encryption of existing files belonging to "' . $params['uid'] . '" completed' - , \OC_Log::INFO - ); - // Register successful migration in DB - $util->finishMigration(); - } else { - \OCP\Util::writeLog('Encryption library', 'Initial encryption failed!', \OCP\Util::FATAL); - $util->resetMigrationStatus(); - \OCP\User::logout(); - } - } - - return $result; - } - - /** - * remove keys from session during logout - */ - public static function logout() { - $session = new Session(new \OC\Files\View()); - $session->removeKeys(); - } - - /** - * setup encryption backend upon user created - * @note This method should never be called for users using client side encryption - */ - public static function postCreateUser($params) { - - if (\OCP\App::isEnabled('files_encryption')) { - $view = new \OC\Files\View('/'); - $util = new Util($view, $params['uid']); - Helper::setupUser($util, $params['password']); - } - } - - /** - * cleanup encryption backend upon user deleted - * @note This method should never be called for users using client side encryption - */ - public static function postDeleteUser($params) { - - if (\OCP\App::isEnabled('files_encryption')) { - Keymanager::deletePublicKey(new \OC\Files\View(), $params['uid']); - } - } - - /** - * If the password can't be changed within ownCloud, than update the key password in advance. - */ - public static function preSetPassphrase($params) { - if (\OCP\App::isEnabled('files_encryption')) { - if ( ! \OC_User::canUserChangePassword($params['uid']) ) { - self::setPassphrase($params); - } - } - } - - /** - * Change a user's encryption passphrase - * @param array $params keys: uid, password - */ - public static function setPassphrase($params) { - if (\OCP\App::isEnabled('files_encryption') === false) { - return true; - } - - // Only attempt to change passphrase if server-side encryption - // is in use (client-side encryption does not have access to - // the necessary keys) - if (Crypt::mode() === 'server') { - - $view = new \OC\Files\View('/'); - $session = new Session($view); - - // Get existing decrypted private key - $privateKey = $session->getPrivateKey(); - - if ($params['uid'] === \OCP\User::getUser() && $privateKey) { - - // Encrypt private key with new user pwd as passphrase - $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($privateKey, $params['password'], Helper::getCipher()); - - // Save private key - if ($encryptedPrivateKey) { - Keymanager::setPrivateKey($encryptedPrivateKey, \OCP\User::getUser()); - } else { - \OCP\Util::writeLog('files_encryption', 'Could not update users encryption password', \OCP\Util::ERROR); - } - - // 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 reencrypt file keys - - $user = $params['uid']; - $util = new Util($view, $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 (($util->recoveryEnabledForUser() && $recoveryPassword) - || !$util->userKeysExists() - || !$view->file_exists($user . '/files')) { - - // backup old keys - $util->backupAllKeys('recovery'); - - $newUserPassword = $params['password']; - - // make sure that the users home is mounted - \OC\Files\Filesystem::initMountPoints($user); - - $keypair = Crypt::createKeypair(); - - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - - // Save public key - Keymanager::setPublicKey($keypair['publicKey'], $user); - - // Encrypt private key with new password - $encryptedKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $newUserPassword, Helper::getCipher()); - if ($encryptedKey) { - Keymanager::setPrivateKey($encryptedKey, $user); - - if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files - $util = new Util($view, $user); - $util->recoverUsersFiles($recoveryPassword); - } - } else { - \OCP\Util::writeLog('files_encryption', 'Could not update users encryption password', \OCP\Util::ERROR); - } - - \OC_FileProxy::$enabled = $proxyStatus; - } - } - } - } - - /** - * after password reset we create a new key pair for the user - * - * @param array $params - */ - public static function postPasswordReset($params) { - $uid = $params['uid']; - $password = $params['password']; - - $util = new Util(new \OC\Files\View(), $uid); - $util->replaceUserKeys($password); - } - /* * check if files can be encrypted to every user. */ diff --git a/lib/private/encryption/exceptions/decryptionfailedexception.php b/lib/private/encryption/exceptions/decryptionfailedexception.php new file mode 100644 index 00000000000..43fea90fed8 --- /dev/null +++ b/lib/private/encryption/exceptions/decryptionfailedexception.php @@ -0,0 +1,28 @@ + + * @since 2/25/15, 9:38 AM + * @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 + * + */ + + +namespace OC\Encryption\Exceptions; + + +class DecryptionFailedException extends GenericEncryptionException { + +} diff --git a/lib/private/encryption/exceptions/emptyencryptiondataexception.php b/lib/private/encryption/exceptions/emptyencryptiondataexception.php new file mode 100644 index 00000000000..ea181809856 --- /dev/null +++ b/lib/private/encryption/exceptions/emptyencryptiondataexception.php @@ -0,0 +1,28 @@ + + * @since 2/25/15, 9:38 AM + * @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 + * + */ + + +namespace OC\Encryption\Exceptions; + + +class EmptyEncryptionDataException extends GenericEncryptionException{ + +} diff --git a/lib/private/encryption/exceptions/encryptionfailedexception.php b/lib/private/encryption/exceptions/encryptionfailedexception.php new file mode 100644 index 00000000000..9e6648f7bf5 --- /dev/null +++ b/lib/private/encryption/exceptions/encryptionfailedexception.php @@ -0,0 +1,28 @@ + + * @since 2/25/15, 9:37 AM + * @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 + * + */ + + +namespace OC\Encryption\Exceptions; + + +class EncryptionFailedException extends GenericEncryptionException{ + +} diff --git a/lib/private/encryption/exceptions/encryptionheadertolargeexception.php b/lib/private/encryption/exceptions/encryptionheadertolargeexception.php new file mode 100644 index 00000000000..cc980aa4beb --- /dev/null +++ b/lib/private/encryption/exceptions/encryptionheadertolargeexception.php @@ -0,0 +1,28 @@ + + * @since 2/25/15, 9:35 AM + * @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 + * + */ + + +namespace OC\Encryption\Exceptions; + + +class EncryptionHeaderToLargeException extends GenericEncryptionException { + +} diff --git a/lib/private/encryption/exceptions/genericencryptionexception.php b/lib/private/encryption/exceptions/genericencryptionexception.php new file mode 100644 index 00000000000..608e5e6010a --- /dev/null +++ b/lib/private/encryption/exceptions/genericencryptionexception.php @@ -0,0 +1,27 @@ + + * @since 2/25/15, 9:30 AM + * @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 + * + */ + +namespace OC\Encryption\Exceptions; + + +class GenericEncryptionException extends \Exception { + +} diff --git a/lib/private/encryption/exceptions/privatekeymissingexception.php b/lib/private/encryption/exceptions/privatekeymissingexception.php new file mode 100644 index 00000000000..878b83d240c --- /dev/null +++ b/lib/private/encryption/exceptions/privatekeymissingexception.php @@ -0,0 +1,28 @@ + + * @since 2/25/15, 9:39 AM + * @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 + * + */ + + +namespace OC\Encryption\Exceptions; + + +class PrivateKeyMissingException extends GenericEncryptionException{ + +} diff --git a/lib/private/encryption/exceptions/publickeymissingexception.php b/lib/private/encryption/exceptions/publickeymissingexception.php new file mode 100644 index 00000000000..d5f2aae42cc --- /dev/null +++ b/lib/private/encryption/exceptions/publickeymissingexception.php @@ -0,0 +1,28 @@ + + * @since 2/25/15, 9:39 AM + * @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 + * + */ + + +namespace OC\Encryption\Exceptions; + + +class PublicKeyMissingException extends GenericEncryptionException { + +} diff --git a/lib/private/encryption/exceptions/unexpectedblocksizeexception.php b/lib/private/encryption/exceptions/unexpectedblocksizeexception.php new file mode 100644 index 00000000000..799d08e6bab --- /dev/null +++ b/lib/private/encryption/exceptions/unexpectedblocksizeexception.php @@ -0,0 +1,28 @@ + + * @since 2/25/15, 9:35 AM + * @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 + * + */ + + +namespace OC\Encryption\Exceptions; + + +interface UnexpectedBlockSize { + +} diff --git a/lib/private/encryption/exceptions/unexpectedendofencryptionheaderexception.php b/lib/private/encryption/exceptions/unexpectedendofencryptionheaderexception.php new file mode 100644 index 00000000000..04f65cf7626 --- /dev/null +++ b/lib/private/encryption/exceptions/unexpectedendofencryptionheaderexception.php @@ -0,0 +1,28 @@ + + * @since 2/25/15, 9:34 AM + * @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 + * + */ + + +namespace OC\Encryption\Exceptions; + + +class UnexpectedEndOfEncryptionHeaderException extends GenericEncryptionException { + +} diff --git a/lib/private/encryption/exceptions/unknowncipherexception.php b/lib/private/encryption/exceptions/unknowncipherexception.php new file mode 100644 index 00000000000..5177af6106b --- /dev/null +++ b/lib/private/encryption/exceptions/unknowncipherexception.php @@ -0,0 +1,28 @@ + + * @since 2/25/15, 9:36 AM + * @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 + * + */ + + +namespace OC\Encryption\Exceptions; + + +class UnknownCipherException extends GenericEncryptionException{ + +} diff --git a/lib/private/encryption/keystorage.php b/lib/private/encryption/keystorage.php index 5b56f6af4e7..fbc427edf0f 100644 --- a/lib/private/encryption/keystorage.php +++ b/lib/private/encryption/keystorage.php @@ -23,25 +23,29 @@ namespace OC\Encryption; +use OC\Encryption\Util; +use OC\Files\View; +use OCA\Files_Encryption\Exception\EncryptionException; + class KeyStorage implements \OCP\Encryption\IKeyStorage { - /** @var \OC\Files\View */ + /** @var View */ private $view; - /** @var \OC\Encryption\Util */ + /** @var Util */ private $util; // base dir where all the file related keys are stored private static $keys_base_dir = '/files_encryption/keys/'; private static $encryption_base_dir = '/files_encryption'; - private static $key_cache = array(); // cache keys + private $keyCache = array(); /** - * @param \OC\Files\View $view - * @param \OC\Encryption\Util $util + * @param View $view + * @param Util $util */ - public function __construct(\OC\Files\View $view, \OC\Encryption\Util $util) { + public function __construct(View $view, Util $util) { $this->view = $view; $this->util = $util; } @@ -50,14 +54,13 @@ class KeyStorage implements \OCP\Encryption\IKeyStorage { * get user specific key * * @param string $uid ID if the user for whom we want the key - * @param string $keyid id of the key + * @param string $keyId id of the key * * @return mixed key */ - public function getUserKey($uid, $keyid) { - $path = '/' . $uid . self::$encryption_base_dir . '/' . $uid . '.' . $keyid; + public function getUserKey($uid, $keyId) { + $path = '/' . $uid . self::$encryption_base_dir . '/' . $uid . '.' . $keyId; return $this->getKey($path); - } /** @@ -135,8 +138,8 @@ class KeyStorage implements \OCP\Encryption\IKeyStorage { $key = ''; - if (isset(self::$key_cache[$path])) { - $key = self::$key_cache[$path]; + if (isset($this->keyCache[$path])) { + $key = $this->keyCache[$path]; } else { /** @var \OCP\Files\Storage $storage */ @@ -144,7 +147,7 @@ class KeyStorage implements \OCP\Encryption\IKeyStorage { if ($storage->file_exists($internalPath)) { $key = $storage->file_get_contents($internalPath); - self::$key_cache[$path] = $key; + $this->keyCache[$path] = $key; } } @@ -168,7 +171,7 @@ class KeyStorage implements \OCP\Encryption\IKeyStorage { $result = $storage->file_put_contents($internalPath, $key); if (is_int($result) && $result > 0) { - self::$key_cache[$path] = $key; + $this->keyCache[$path] = $key; return true; } @@ -180,11 +183,16 @@ class KeyStorage implements \OCP\Encryption\IKeyStorage { * * @param string $path path to the file, relative to the users file directory * @return string + * @throws EncryptionException + * @internal param string $keyId */ private function getFileKeyDir($path) { + // + // TODO: NO DEPRICATED API !!! + // if ($this->view->is_dir('/' . \OCP\User::getUser() . '/' . $path)) { - throw new Exception\EncryptionException('file was expected but directoy was given', Exception\EncryptionException::GENERIC); + throw new EncryptionException('file was expected but directory was given', EncryptionException::GENERIC); } list($owner, $filename) = $this->util->getUidAndFilename($path); @@ -220,4 +228,23 @@ class KeyStorage implements \OCP\Encryption\IKeyStorage { } } + /** + * Check if encryption system is ready to begin encrypting + * all the things + * + * @return bool + */ + public function ready() { + $paths = [ + self::$encryption_base_dir, + self::$keys_base_dir + ]; + foreach ($paths as $path) { + if (!$this->view->file_exists($path)) { + return false; + } + } + return true; + } + } diff --git a/lib/public/encryption/ikeystorage.php b/lib/public/encryption/ikeystorage.php index cf94d56e59b..2ab5048709e 100644 --- a/lib/public/encryption/ikeystorage.php +++ b/lib/public/encryption/ikeystorage.php @@ -29,59 +29,65 @@ interface IKeyStorage { * get user specific key * * @param string $uid ID if the user for whom we want the key - * @param string $keyid id of the key + * @param string $keyId id of the key * * @return mixed key */ - public function getUserKey($uid, $keyid); + public function getUserKey($uid, $keyId); /** * get file specific key * * @param string $path path to file - * @param string $keyid id of the key + * @param string $keyId id of the key * * @return mixed key */ - public function getFileKey($path, $keyid); + public function getFileKey($path, $keyId); /** * get system-wide encryption keys not related to a specific user, * e.g something like a key for public link shares * - * @param string $keyid id of the key + * @param string $keyId id of the key * * @return mixed key */ - public function getSystemUserKey($uid, $keyid); + public function getSystemUserKey($keyId); /** * set user specific key * * @param string $uid ID if the user for whom we want the key - * @param string $keyid id of the key + * @param string $keyId id of the key * @param mixed $key */ - public function setUserKey($uid, $keyid, $key); + public function setUserKey($uid, $keyId, $key); /** * set file specific key * * @param string $path path to file - * @param string $keyid id of the key + * @param string $keyId id of the key * @param mixed $key */ - public function setFileKey($path, $keyid, $key); + public function setFileKey($path, $keyId, $key); /** * set system-wide encryption keys not related to a specific user, * e.g something like a key for public link shares * - * @param string $keyid id of the key + * @param string $keyId id of the key * @param mixed $key * * @return mixed key */ - public function setSystemUserKey($uid, $keyid, $key); + public function setSystemUserKey($keyId, $key); + /** + * Return if encryption is setup and ready encrypt things + * + * @return bool + */ + public function ready(); } diff --git a/tests/lib/encryption/managertest.php b/tests/lib/encryption/managertest.php index ab297bae0cb..5a0efa37b36 100644 --- a/tests/lib/encryption/managertest.php +++ b/tests/lib/encryption/managertest.php @@ -111,4 +111,62 @@ class ManagerTest extends TestCase { $en0 = $m->getEncryptionModule(0); $this->assertEquals(0, $en0->getId()); } + + /** + * @expectedException \OC\Encryption\Exceptions\ModuleAlreadyExistsException + * @expectedExceptionMessage At the moment it is not allowed to register more than one encryption module + */ + public function testModuleRegistration() { + $config = $this->getMock('\OCP\IConfig'); + $config->expects($this->any())->method('getSystemValue')->willReturn(true); + $em = $this->getMock('\OCP\Encryption\IEncryptionModule'); + $em->expects($this->any())->method('getId')->willReturn(0); + $em->expects($this->any())->method('getDisplayName')->willReturn('TestDummyModule0'); + $m = new Manager($config); + $m->registerEncryptionModule($em); + $this->assertTrue($m->isEnabled()); + $m->registerEncryptionModule($em); + } + + public function testModuleUnRegistration() { + $config = $this->getMock('\OCP\IConfig'); + $config->expects($this->any())->method('getSystemValue')->willReturn(true); + $em = $this->getMock('\OCP\Encryption\IEncryptionModule'); + $em->expects($this->any())->method('getId')->willReturn(0); + $em->expects($this->any())->method('getDisplayName')->willReturn('TestDummyModule0'); + $m = new Manager($config); + $m->registerEncryptionModule($em); + $this->assertTrue($m->isEnabled()); + $m->unregisterEncryptionModule($em); + $this->assertFalse($m->isEnabled()); + } + + /** + * @expectedException \OC\Encryption\Exceptions\ModuleDoesNotExistsException + * @expectedExceptionMessage Module with id: unknown does not exists. + */ + public function testGetEncryptionModuleUnknown() { + $config = $this->getMock('\OCP\IConfig'); + $config->expects($this->any())->method('getSystemValue')->willReturn(true); + $em = $this->getMock('\OCP\Encryption\IEncryptionModule'); + $em->expects($this->any())->method('getId')->willReturn(0); + $em->expects($this->any())->method('getDisplayName')->willReturn('TestDummyModule0'); + $m = new Manager($config); + $m->registerEncryptionModule($em); + $this->assertTrue($m->isEnabled()); + $m->getEncryptionModule('unknown'); + } + + public function testGetEncryptionModule() { + $config = $this->getMock('\OCP\IConfig'); + $config->expects($this->any())->method('getSystemValue')->willReturn(true); + $em = $this->getMock('\OCP\Encryption\IEncryptionModule'); + $em->expects($this->any())->method('getId')->willReturn(0); + $em->expects($this->any())->method('getDisplayName')->willReturn('TestDummyModule0'); + $m = new Manager($config); + $m->registerEncryptionModule($em); + $this->assertTrue($m->isEnabled()); + $en0 = $m->getEncryptionModule(0); + $this->assertEquals(0, $en0->getId()); + } } -- cgit v1.2.3 From 5bc9ababeb06c3e901b7d11b8c2c1d44865d3339 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Tue, 17 Mar 2015 13:11:38 +0100 Subject: fix keystorage and add unit tests --- lib/private/encryption/keys/storage.php | 105 +------------- lib/private/encryption/keystorage.php | 250 -------------------------------- lib/public/encryption/ikeystorage.php | 93 ------------ lib/public/encryption/keys/istorage.php | 2 +- 4 files changed, 9 insertions(+), 441 deletions(-) delete mode 100644 lib/private/encryption/keystorage.php delete mode 100644 lib/public/encryption/ikeystorage.php (limited to 'lib/private/encryption') diff --git a/lib/private/encryption/keys/storage.php b/lib/private/encryption/keys/storage.php index 041db2a2cb8..fba86e1737c 100644 --- a/lib/private/encryption/keys/storage.php +++ b/lib/private/encryption/keys/storage.php @@ -67,7 +67,8 @@ class Storage implements \OCP\Encryption\Keys\IStorage { * @return mixed key */ public function getUserKey($uid, $keyId) { - $path = $this->constructUserKeyPath($keyId, $uid); + $path = '/' . $uid . $this->encryption_base_dir . '/' + . $this->encryptionModuleId . '/' . $uid . '.' . $keyId; return $this->getKey($path); } @@ -93,7 +94,7 @@ class Storage implements \OCP\Encryption\Keys\IStorage { * @return mixed key */ public function getSystemUserKey($keyId) { - $path = $this->constructUserKeyPath($keyId); + $path = $this->encryption_base_dir . '/' . $this->encryptionModuleId . '/' . $keyId; return $this->getKey($path); } @@ -105,7 +106,8 @@ class Storage implements \OCP\Encryption\Keys\IStorage { * @param mixed $key */ public function setUserKey($uid, $keyId, $key) { - $path = $this->constructUserKeyPath($keyId, $uid); + $path = '/' . $uid . $this->encryption_base_dir . '/' + . $this->encryptionModuleId . '/' . $uid . '.' . $keyId; return $this->setKey($path, $key); } @@ -114,7 +116,7 @@ class Storage implements \OCP\Encryption\Keys\IStorage { * * @param string $path path to file * @param string $keyId id of the key - * @param boolean + * @param mixed $key */ public function setFileKey($path, $keyId, $key) { $keyDir = $this->getFileKeyDir($path); @@ -131,79 +133,11 @@ class Storage implements \OCP\Encryption\Keys\IStorage { * @return mixed key */ public function setSystemUserKey($keyId, $key) { - $path = $this->constructUserKeyPath($keyId); + $path = $this->encryption_base_dir . '/' + . $this->encryptionModuleId . '/' . $keyId; return $this->setKey($path, $key); } - /** - * delete user specific key - * - * @param string $uid ID if the user for whom we want to delete the key - * @param string $keyId id of the key - * - * @return boolean - */ - public function deleteUserKey($uid, $keyId) { - $path = $this->constructUserKeyPath($keyId, $uid); - return $this->view->unlink($path); - } - - /** - * delete file specific key - * - * @param string $path path to file - * @param string $keyId id of the key - * - * @return boolean - */ - public function deleteFileKey($path, $keyId) { - $keyDir = $this->getFileKeyDir($path); - return $this->view->unlink($keyDir . $keyId); - } - - /** - * delete all file keys for a given file - * - * @param string $path to the file - * @return boolean - */ - public function deleteAllFileKeys($path) { - $keyDir = $this->getFileKeyDir($path); - return $this->view->deleteAll(dirname($keyDir)); - } - - /** - * delete system-wide encryption keys not related to a specific user, - * e.g something like a key for public link shares - * - * @param string $keyId id of the key - * - * @return boolean - */ - public function deleteSystemUserKey($keyId) { - $path = $this->constructUserKeyPath($keyId); - return $this->view->unlink($path); - } - - - /** - * construct path to users key - * - * @param string $keyId - * @param string $uid - * @return string - */ - protected function constructUserKeyPath($keyId, $uid = null) { - - if ($uid === null) { - $path = $this->encryption_base_dir . '/' . $this->encryptionModuleId . '/' . $keyId; - } else { - $path = '/' . $uid . $this->encryption_base_dir . '/' - . $this->encryptionModuleId . '/' . $uid . '.' . $keyId; - } - - return $path; - } /** * read key from hard disk @@ -275,29 +209,6 @@ class Storage implements \OCP\Encryption\Keys\IStorage { return \OC\Files\Filesystem::normalizePath($keyPath . $this->encryptionModuleId . '/', false); } - /** - * move keys if a file was renamed - * - * @param string $source - * @param string $target - * @param string $owner - * @param bool $systemWide - */ - public function renameKeys($source, $target, $owner, $systemWide) { - if ($systemWide) { - $sourcePath = $this->keys_base_dir . $source . '/'; - $targetPath = $this->keys_base_dir . $target . '/'; - } else { - $sourcePath = '/' . $owner . $this->keys_base_dir . $source . '/'; - $targetPath = '/' . $owner . $this->keys_base_dir . $target . '/'; - } - - if ($this->view->file_exists($sourcePath)) { - $this->keySetPreparation(dirname($targetPath)); - $this->view->rename($sourcePath, $targetPath); - } - } - /** * Make preparations to filesystem for saving a keyfile * diff --git a/lib/private/encryption/keystorage.php b/lib/private/encryption/keystorage.php deleted file mode 100644 index fbc427edf0f..00000000000 --- a/lib/private/encryption/keystorage.php +++ /dev/null @@ -1,250 +0,0 @@ - - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. If not, see . - */ - -namespace OC\Encryption; - -use OC\Encryption\Util; -use OC\Files\View; -use OCA\Files_Encryption\Exception\EncryptionException; - -class KeyStorage implements \OCP\Encryption\IKeyStorage { - - /** @var View */ - private $view; - - /** @var Util */ - private $util; - - // base dir where all the file related keys are stored - private static $keys_base_dir = '/files_encryption/keys/'; - private static $encryption_base_dir = '/files_encryption'; - - private $keyCache = array(); - - /** - * @param View $view - * @param Util $util - */ - public function __construct(View $view, Util $util) { - $this->view = $view; - $this->util = $util; - } - - /** - * get user specific key - * - * @param string $uid ID if the user for whom we want the key - * @param string $keyId id of the key - * - * @return mixed key - */ - public function getUserKey($uid, $keyId) { - $path = '/' . $uid . self::$encryption_base_dir . '/' . $uid . '.' . $keyId; - return $this->getKey($path); - } - - /** - * get file specific key - * - * @param string $path path to file - * @param string $keyId id of the key - * - * @return mixed key - */ - public function getFileKey($path, $keyId) { - $keyDir = $this->getFileKeyDir($path); - return $this->getKey($keyDir . $keyId); - } - - /** - * get system-wide encryption keys not related to a specific user, - * e.g something like a key for public link shares - * - * @param string $keyId id of the key - * - * @return mixed key - */ - public function getSystemUserKey($keyId) { - $path = '/' . self::$encryption_base_dir . '/' . $keyId; - return $this->getKey($path); - } - - /** - * set user specific key - * - * @param string $uid ID if the user for whom we want the key - * @param string $keyId id of the key - * @param mixed $key - */ - public function setUserKey($uid, $keyId, $key) { - $path = '/' . $uid . self::$encryption_base_dir . '/' . $uid . '.' . $keyId; - return $this->setKey($path, $key); - } - - /** - * set file specific key - * - * @param string $path path to file - * @param string $keyId id of the key - * @param mixed $key - */ - public function setFileKey($path, $keyId, $key) { - $keyDir = $this->getFileKeyDir($path); - return $this->setKey($keyDir . $keyId, $key); - } - - /** - * set system-wide encryption keys not related to a specific user, - * e.g something like a key for public link shares - * - * @param string $keyId id of the key - * @param mixed $key - * - * @return mixed key - */ - public function setSystemUserKey($keyId, $key) { - $path = '/' . self::$encryption_base_dir . '/' . $keyId; - return $this->setKey($path, $key); - } - - - /** - * read key from hard disk - * - * @param string $path to key - * @return string - */ - private function getKey($path) { - - $key = ''; - - if (isset($this->keyCache[$path])) { - $key = $this->keyCache[$path]; - } else { - - /** @var \OCP\Files\Storage $storage */ - list($storage, $internalPath) = $this->view->resolvePath($path); - - if ($storage->file_exists($internalPath)) { - $key = $storage->file_get_contents($internalPath); - $this->keyCache[$path] = $key; - } - - } - - return $key; - } - - /** - * write key to disk - * - * - * @param string $path path to key directory - * @param string $key key - * @return bool - */ - private function setKey($path, $key) { - $this->keySetPreparation(dirname($path)); - - /** @var \OCP\Files\Storage $storage */ - list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($path); - $result = $storage->file_put_contents($internalPath, $key); - - if (is_int($result) && $result > 0) { - $this->keyCache[$path] = $key; - return true; - } - - return false; - } - - /** - * get path to key folder for a given file - * - * @param string $path path to the file, relative to the users file directory - * @return string - * @throws EncryptionException - * @internal param string $keyId - */ - private function getFileKeyDir($path) { - - // - // TODO: NO DEPRICATED API !!! - // - if ($this->view->is_dir('/' . \OCP\User::getUser() . '/' . $path)) { - throw new EncryptionException('file was expected but directory was given', EncryptionException::GENERIC); - } - - list($owner, $filename) = $this->util->getUidAndFilename($path); - $filename = $this->util->stripPartialFileExtension($filename); - $filePath_f = ltrim($filename, '/'); - - // in case of system wide mount points the keys are stored directly in the data directory - if ($this->util->isSystemWideMountPoint($filename)) { - $keyPath = self::$keys_base_dir . $filePath_f . '/'; - } else { - $keyPath = '/' . $owner . self::$keys_base_dir . $filePath_f . '/'; - } - - return $keyPath; - } - - /** - * Make preparations to filesystem for saving a keyfile - * - * @param string $path relative to the views root - */ - protected function keySetPreparation($path) { - // If the file resides within a subdirectory, create it - if (!$this->view->file_exists($path)) { - $sub_dirs = explode('/', $path); - $dir = ''; - foreach ($sub_dirs as $sub_dir) { - $dir .= '/' . $sub_dir; - if (!$this->view->is_dir($dir)) { - $this->view->mkdir($dir); - } - } - } - } - - /** - * Check if encryption system is ready to begin encrypting - * all the things - * - * @return bool - */ - public function ready() { - $paths = [ - self::$encryption_base_dir, - self::$keys_base_dir - ]; - foreach ($paths as $path) { - if (!$this->view->file_exists($path)) { - return false; - } - } - return true; - } - -} diff --git a/lib/public/encryption/ikeystorage.php b/lib/public/encryption/ikeystorage.php deleted file mode 100644 index 2ab5048709e..00000000000 --- a/lib/public/encryption/ikeystorage.php +++ /dev/null @@ -1,93 +0,0 @@ - - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. If not, see . - */ - -namespace OCP\Encryption; - -interface IKeyStorage { - - /** - * get user specific key - * - * @param string $uid ID if the user for whom we want the key - * @param string $keyId id of the key - * - * @return mixed key - */ - public function getUserKey($uid, $keyId); - - /** - * get file specific key - * - * @param string $path path to file - * @param string $keyId id of the key - * - * @return mixed key - */ - public function getFileKey($path, $keyId); - - /** - * get system-wide encryption keys not related to a specific user, - * e.g something like a key for public link shares - * - * @param string $keyId id of the key - * - * @return mixed key - */ - public function getSystemUserKey($keyId); - - /** - * set user specific key - * - * @param string $uid ID if the user for whom we want the key - * @param string $keyId id of the key - * @param mixed $key - */ - public function setUserKey($uid, $keyId, $key); - - /** - * set file specific key - * - * @param string $path path to file - * @param string $keyId id of the key - * @param mixed $key - */ - public function setFileKey($path, $keyId, $key); - - /** - * set system-wide encryption keys not related to a specific user, - * e.g something like a key for public link shares - * - * @param string $keyId id of the key - * @param mixed $key - * - * @return mixed key - */ - public function setSystemUserKey($keyId, $key); - - /** - * Return if encryption is setup and ready encrypt things - * - * @return bool - */ - public function ready(); -} diff --git a/lib/public/encryption/keys/istorage.php b/lib/public/encryption/keys/istorage.php index 4c2b01f4ad0..c4c970804e9 100644 --- a/lib/public/encryption/keys/istorage.php +++ b/lib/public/encryption/keys/istorage.php @@ -69,7 +69,7 @@ interface IStorage { * * @param string $path path to file * @param string $keyId id of the key - * @param boolean + * @param mixed $key */ public function setFileKey($path, $keyId, $key); -- cgit v1.2.3 From e2f714263f50a27ed0894710faead3e9f9d1d9d6 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Wed, 18 Mar 2015 10:58:02 +0100 Subject: fix encryption manager to handle more than one encryption module --- lib/private/encryption/manager.php | 24 ++++++++++++++++++------ tests/lib/encryption/managertest.php | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) (limited to 'lib/private/encryption') diff --git a/lib/private/encryption/manager.php b/lib/private/encryption/manager.php index 5164025239c..fa50d32218d 100644 --- a/lib/private/encryption/manager.php +++ b/lib/private/encryption/manager.php @@ -106,12 +106,24 @@ class Manager implements \OCP\Encryption\IManager { * @return IEncryptionModule * @throws Exceptions\ModuleDoesNotExistsException */ - public function getEncryptionModule($moduleId) { - if (isset($this->encryptionModules[$moduleId])) { - return $this->encryptionModules[$moduleId]; - } else { - $message = "Module with id: $moduleId does not exists."; - throw new Exceptions\ModuleDoesNotExistsException($message); + public function getEncryptionModule($moduleId = '') { + if (!empty($moduleId)) { + if (isset($this->encryptionModules[$moduleId])) { + return $this->encryptionModules[$moduleId]; + } else { + $message = "Module with id: $moduleId does not exists."; + throw new Exceptions\ModuleDoesNotExistsException($message); + } + } else { // get default module and return this + // For now we simply return the first module until we have a way + // to enable multiple modules and define a default module + $module = reset($this->encryptionModules); + if ($module) { + return $module; + } else { + $message = 'No encryption module registered'; + throw new Exceptions\ModuleDoesNotExistsException($message); + } } } diff --git a/tests/lib/encryption/managertest.php b/tests/lib/encryption/managertest.php index 5a0efa37b36..e5a1898515a 100644 --- a/tests/lib/encryption/managertest.php +++ b/tests/lib/encryption/managertest.php @@ -114,7 +114,7 @@ class ManagerTest extends TestCase { /** * @expectedException \OC\Encryption\Exceptions\ModuleAlreadyExistsException - * @expectedExceptionMessage At the moment it is not allowed to register more than one encryption module + * @expectedExceptionMessage Id "0" already used by encryption module "TestDummyModule0" */ public function testModuleRegistration() { $config = $this->getMock('\OCP\IConfig'); -- cgit v1.2.3 From 506222567e71fc0d77fa77ee7805c93fa7655b6c Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 20 Mar 2015 16:24:44 +0100 Subject: add deleteKey methods to key storage --- lib/private/encryption/keys/storage.php | 69 +++++++++++++++++++++++++++++---- lib/public/encryption/keys/istorage.php | 1 + 2 files changed, 63 insertions(+), 7 deletions(-) (limited to 'lib/private/encryption') diff --git a/lib/private/encryption/keys/storage.php b/lib/private/encryption/keys/storage.php index fba86e1737c..8f1822ca492 100644 --- a/lib/private/encryption/keys/storage.php +++ b/lib/private/encryption/keys/storage.php @@ -67,8 +67,7 @@ class Storage implements \OCP\Encryption\Keys\IStorage { * @return mixed key */ public function getUserKey($uid, $keyId) { - $path = '/' . $uid . $this->encryption_base_dir . '/' - . $this->encryptionModuleId . '/' . $uid . '.' . $keyId; + $path = $this->constructUserKeyPath($keyId, $uid); return $this->getKey($path); } @@ -94,7 +93,7 @@ class Storage implements \OCP\Encryption\Keys\IStorage { * @return mixed key */ public function getSystemUserKey($keyId) { - $path = $this->encryption_base_dir . '/' . $this->encryptionModuleId . '/' . $keyId; + $path = $this->constructUserKeyPath($keyId); return $this->getKey($path); } @@ -106,8 +105,7 @@ class Storage implements \OCP\Encryption\Keys\IStorage { * @param mixed $key */ public function setUserKey($uid, $keyId, $key) { - $path = '/' . $uid . $this->encryption_base_dir . '/' - . $this->encryptionModuleId . '/' . $uid . '.' . $keyId; + $path = $this->constructUserKeyPath($keyId, $uid); return $this->setKey($path, $key); } @@ -133,11 +131,68 @@ class Storage implements \OCP\Encryption\Keys\IStorage { * @return mixed key */ public function setSystemUserKey($keyId, $key) { - $path = $this->encryption_base_dir . '/' - . $this->encryptionModuleId . '/' . $keyId; + $path = $this->constructUserKeyPath($keyId); return $this->setKey($path, $key); } + /** + * delete user specific key + * + * @param string $uid ID if the user for whom we want to delete the key + * @param string $keyId id of the key + * + * @return boolean + */ + public function deleteUserKey($uid, $keyId) { + $path = $this->constructUserKeyPath($keyId, $uid); + return $this->view->unlink($path); + } + + /** + * delete file specific key + * + * @param string $path path to file + * @param string $keyId id of the key + * + * @return boolean + */ + public function deleteFileKey($path, $keyId) { + $keyDir = $this->getFileKeyDir($path); + return $this->view->unlink($keyDir . $keyId); + } + + /** + * delete system-wide encryption keys not related to a specific user, + * e.g something like a key for public link shares + * + * @param string $keyId id of the key + * + * @return boolean + */ + public function deleteSystemUserKey($keyId) { + $path = $this->constructUserKeyPath($keyId); + return $this->view->unlink($path); + } + + + /** + * construct path to users key + * + * @param string $keyId + * @param string $uid + * @return string + */ + protected function constructUserKeyPath($keyId, $uid = null) { + + if ($uid === null) { + $path = $this->encryption_base_dir . '/' . $this->encryptionModuleId . '/' . $keyId; + } else { + $path = '/' . $uid . $this->encryption_base_dir . '/' + . $this->encryptionModuleId . '/' . $uid . '.' . $keyId; + } + + return $path; + } /** * read key from hard disk diff --git a/lib/public/encryption/keys/istorage.php b/lib/public/encryption/keys/istorage.php index c4c970804e9..3a2562102ce 100644 --- a/lib/public/encryption/keys/istorage.php +++ b/lib/public/encryption/keys/istorage.php @@ -113,6 +113,7 @@ interface IStorage { public function deleteAllFileKeys($path); /** + * delete system-wide encryption keys not related to a specific user, * e.g something like a key for public link shares * -- cgit v1.2.3 From 810ca9105ca7b25c98d7bc265dfb4c8e37b9b8e8 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 26 Mar 2015 09:24:28 +0100 Subject: implement rename and delete of encryption keys --- lib/private/encryption/keys/storage.php | 34 ++++++++++++++++++++++++ lib/private/files/storage/wrapper/encryption.php | 1 + 2 files changed, 35 insertions(+) (limited to 'lib/private/encryption') diff --git a/lib/private/encryption/keys/storage.php b/lib/private/encryption/keys/storage.php index 8f1822ca492..c8afcbbd213 100644 --- a/lib/private/encryption/keys/storage.php +++ b/lib/private/encryption/keys/storage.php @@ -161,6 +161,17 @@ class Storage implements \OCP\Encryption\Keys\IStorage { return $this->view->unlink($keyDir . $keyId); } + /** + * delete all file keys for a given file + * + * @param string $path to the file + * @return boolean + */ + public function deleteAllFileKeys($path) { + $keyDir = $this->getFileKeyDir($path); + return $this->view->deleteAll(dirname($keyDir)); + } + /** * delete system-wide encryption keys not related to a specific user, * e.g something like a key for public link shares @@ -264,6 +275,29 @@ class Storage implements \OCP\Encryption\Keys\IStorage { return \OC\Files\Filesystem::normalizePath($keyPath . $this->encryptionModuleId . '/', false); } + /** + * move keys if a file was renamed + * + * @param string $source + * @param string $target + * @param string $owner + * @param bool $systemWide + */ + public function renameKeys($source, $target, $owner, $systemWide) { + if ($systemWide) { + $sourcePath = $this->keys_base_dir . $source . '/'; + $targetPath = $this->keys_base_dir . $target . '/'; + } else { + $sourcePath = '/' . $owner . $this->keys_base_dir . $source . '/'; + $targetPath = '/' . $owner . $this->keys_base_dir . $target . '/'; + } + + if ($this->view->file_exists($sourcePath)) { + $this->keySetPreparation(dirname($targetPath)); + $this->view->rename($sourcePath, $targetPath); + } + } + /** * Make preparations to filesystem for saving a keyfile * diff --git a/lib/private/files/storage/wrapper/encryption.php b/lib/private/files/storage/wrapper/encryption.php index 0e70c99c8d7..2a5b9926f68 100644 --- a/lib/private/files/storage/wrapper/encryption.php +++ b/lib/private/files/storage/wrapper/encryption.php @@ -62,6 +62,7 @@ class Encryption extends Wrapper { $this->mountPoint = $parameters['mountPoint']; $this->encryptionManager = $encryptionManager; + $this->keyStorage = $keyStorage; $this->util = $util; $this->logger = $logger; $this->uid = $uid; -- cgit v1.2.3 From 2244ea998da0b49ef76144979f4bce02393eac89 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 26 Mar 2015 13:37:34 +0100 Subject: core: documentation fixes --- lib/private/encryption/keys/storage.php | 2 +- lib/public/encryption/keys/istorage.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/private/encryption') diff --git a/lib/private/encryption/keys/storage.php b/lib/private/encryption/keys/storage.php index c8afcbbd213..041db2a2cb8 100644 --- a/lib/private/encryption/keys/storage.php +++ b/lib/private/encryption/keys/storage.php @@ -114,7 +114,7 @@ class Storage implements \OCP\Encryption\Keys\IStorage { * * @param string $path path to file * @param string $keyId id of the key - * @param mixed $key + * @param boolean */ public function setFileKey($path, $keyId, $key) { $keyDir = $this->getFileKeyDir($path); diff --git a/lib/public/encryption/keys/istorage.php b/lib/public/encryption/keys/istorage.php index 3a2562102ce..426057b80d0 100644 --- a/lib/public/encryption/keys/istorage.php +++ b/lib/public/encryption/keys/istorage.php @@ -69,7 +69,7 @@ interface IStorage { * * @param string $path path to file * @param string $keyId id of the key - * @param mixed $key + * @param boolean */ public function setFileKey($path, $keyId, $key); -- cgit v1.2.3 From c64e0af4fb44b1464ca3433e99b12b729a2084b2 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Sat, 28 Mar 2015 11:02:26 +0100 Subject: check if recovery key exists and encrypt the file with the recovery key if needed --- apps/encryption/appinfo/encryption.php | 5 +++- apps/encryption/lib/crypto/encryption.php | 39 +++++++++++++++++++++++++++---- apps/encryption/lib/keymanager.php | 20 +++++++++++++++- lib/private/encryption/util.php | 23 +++++++++++++++++- 4 files changed, 80 insertions(+), 7 deletions(-) (limited to 'lib/private/encryption') diff --git a/apps/encryption/appinfo/encryption.php b/apps/encryption/appinfo/encryption.php index d97aa07738c..dd8004a4880 100644 --- a/apps/encryption/appinfo/encryption.php +++ b/apps/encryption/appinfo/encryption.php @@ -102,7 +102,10 @@ class Encryption extends \OCP\AppFramework\App { public function registerEncryptionModule() { $container = $this->getContainer(); $container->registerService('EncryptionModule', function (IAppContainer $c) { - return new \OCA\Encryption\Crypto\Encryption($c->query('Crypt'), $c->query('KeyManager')); + return new \OCA\Encryption\Crypto\Encryption( + $c->query('Crypt'), + $c->query('KeyManager'), + $c->query('Util')); }); $module = $container->query('EncryptionModule'); $this->encryptionManager->registerEncryptionModule($module); diff --git a/apps/encryption/lib/crypto/encryption.php b/apps/encryption/lib/crypto/encryption.php index da805892eaf..8c00077729e 100644 --- a/apps/encryption/lib/crypto/encryption.php +++ b/apps/encryption/lib/crypto/encryption.php @@ -46,9 +46,19 @@ class Encryption implements IEncryptionModule { /** @var boolean */ private $isWriteOperation; - public function __construct(Crypt $crypt, KeyManager $keymanager) { + /** @var \OC\Encryption\Util */ + private $util; + + /** + * + * @param \OCA\Encryption\Crypto\Crypt $crypt + * @param KeyManager $keymanager + * @param \OC\Encryption\Util $util + */ + public function __construct(Crypt $crypt, KeyManager $keymanager, \OC\Encryption\Util $util) { $this->crypt = $crypt; $this->keymanager = $keymanager; + $this->util = $util; } /** @@ -225,9 +235,7 @@ class Encryption implements IEncryptionModule { $publicKeys[$user] = $this->keymanager->getPublicKey($user); } - if (!empty($accessList['public'])) { - $publicKeys[$this->keymanager->getPublicShareKeyId()] = $this->keymanager->getPublicShareKey(); - } + $publicKeys = $this->addSystemKeys($accessList, $publicKeys); $encryptedFileKey = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys); @@ -238,6 +246,29 @@ class Encryption implements IEncryptionModule { return true; } + /** + * add system keys such as the public share key and the recovery key + * + * @param array $accessList + * @param array $publicKeys + * @return array + */ + public function addSystemKeys(array $accessList, array $publicKeys) { + if (!empty($accessList['public'])) { + $publicKeys[$this->keymanager->getPublicShareKeyId()] = $this->keymanager->getPublicShareKey(); + } + + if ($this->keymanager->recoveryKeyExists() && + $this->util->recoveryEnabled($this->user)) { + + $publicKeys[$this->keymanager->getRecoveryKeyId()] = $this->keymanager->getRecoveryKey(); + } + + + return $publicKeys; + } + + /** * should the file be encrypted or not * diff --git a/apps/encryption/lib/keymanager.php b/apps/encryption/lib/keymanager.php index 44a46458692..ea338f88ea7 100644 --- a/apps/encryption/lib/keymanager.php +++ b/apps/encryption/lib/keymanager.php @@ -141,7 +141,25 @@ class KeyManager { * @return bool */ public function recoveryKeyExists() { - return (strlen($this->keyStorage->getSystemUserKey($this->recoveryKeyId)) !== 0); + return (!empty($this->keyStorage->getSystemUserKey($this->recoveryKeyId))); + } + + /** + * get recovery key + * + * @return string + */ + public function getRecoveryKey() { + return $this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.publicKey'); + } + + /** + * get recovery key ID + * + * @return string + */ + public function getRecoveryKeyId() { + return $this->recoveryKeyId; } /** diff --git a/lib/private/encryption/util.php b/lib/private/encryption/util.php index 85e852ec2c9..e3390f155d4 100644 --- a/lib/private/encryption/util.php +++ b/lib/private/encryption/util.php @@ -26,6 +26,7 @@ namespace OC\Encryption; use OC\Encryption\Exceptions\EncryptionHeaderToLargeException; use OC\Encryption\Exceptions\EncryptionHeaderKeyExistsException; use OCP\Encryption\IEncryptionModule; +use OCP\IConfig; class Util { @@ -58,19 +59,27 @@ class Util { /** @var \OC\User\Manager */ protected $userManager; + /** @var IConfig */ + protected $config; + /** @var array paths excluded from encryption */ protected $excludedPaths; /** * @param \OC\Files\View $view root view */ - public function __construct(\OC\Files\View $view, \OC\User\Manager $userManager) { + public function __construct( + \OC\Files\View $view, + \OC\User\Manager $userManager, + IConfig $config) { + $this->ocHeaderKeys = [ self::HEADER_ENCRYPTION_MODULE_KEY ]; $this->view = $view; $this->userManager = $userManager; + $this->config = $config; $this->excludedPaths[] = 'files_encryption'; } @@ -411,4 +420,16 @@ class Util { return false; } + /** + * check if recovery key is enabled for user + * + * @param string $uid + * @return boolean + */ + public function recoveryEnabled($uid) { + $enabled = $this->config->getUserValue($uid, 'encryption', 'recovery_enabled', '0'); + + return ($enabled === '1') ? true : false; + } + } -- cgit v1.2.3 From c266b3b5b7c382c34c8ffaad5746b3251bb4fbb5 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Sat, 28 Mar 2015 11:27:21 +0100 Subject: remove debug code from core --- lib/private/encryption/util.php | 3 --- 1 file changed, 3 deletions(-) (limited to 'lib/private/encryption') diff --git a/lib/private/encryption/util.php b/lib/private/encryption/util.php index e3390f155d4..961e7eceb2d 100644 --- a/lib/private/encryption/util.php +++ b/lib/private/encryption/util.php @@ -407,9 +407,6 @@ class Util { return true; } - $v1 = $this->userManager->userExists($root[1]); - $v2 = in_array($root[2], $this->excludedPaths); - // detect user specific folders if ($this->userManager->userExists($root[1]) && in_array($root[2], $this->excludedPaths)) { -- cgit v1.2.3 From 937efe856d5f65706f2074a45d781d5944ba2494 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Mon, 30 Mar 2015 10:37:31 +0200 Subject: fix lib/private/encryption/util.php call --- lib/base.php | 30 ++++++++++++++++++------------ lib/private/encryption/util.php | 5 ++++- lib/private/server.php | 2 +- 3 files changed, 23 insertions(+), 14 deletions(-) (limited to 'lib/private/encryption') diff --git a/lib/base.php b/lib/base.php index 98da75b61a8..5d1e16296c0 100644 --- a/lib/base.php +++ b/lib/base.php @@ -704,17 +704,20 @@ class OC { $enabled = self::$server->getEncryptionManager()->isEnabled(); if ($enabled) { \OC\Files\Filesystem::addStorageWrapper('oc_encryption', function ($mountPoint, $storage, \OCP\Files\Mount\IMountPoint $mount) { - if($mount->getOption('encrypt', true)) { - $parameters = array('storage' => $storage, 'mountPoint' => $mountPoint); - $manager = \OC::$server->getEncryptionManager(); - $util = new \OC\Encryption\Util(new \OC\Files\View(), \OC::$server->getUserManager()); - $user = \OC::$server->getUserSession()->getUser(); - $logger = \OC::$server->getLogger(); - $uid = $user ? $user->getUID() : null; - return new \OC\Files\Storage\Wrapper\Encryption($parameters, $manager, $util, $logger, $uid); - } else { - return $storage; - } + + $parameters = [ + 'storage' => $storage, + 'mountPoint' => $mountPoint, + 'mount' => $mount]; + $manager = \OC::$server->getEncryptionManager(); + $util = new \OC\Encryption\Util( + new \OC\Files\View(), + \OC::$server->getUserManager(), + \OC::$server->getConfig()); + $user = \OC::$server->getUserSession()->getUser(); + $logger = \OC::$server->getLogger(); + $uid = $user ? $user->getUID() : null; + return new \OC\Files\Storage\Wrapper\Encryption($parameters, $manager, $util, $logger, $uid); }); } @@ -730,7 +733,10 @@ class OC { } $updater = new \OC\Encryption\Update( new \OC\Files\View(), - new \OC\Encryption\Util(new \OC\Files\View(), \OC::$server->getUserManager()), + new \OC\Encryption\Util( + new \OC\Files\View(), + \OC::$server->getUserManager(), + \OC::$server->getConfig()), \OC\Files\Filesystem::getMountManager(), \OC::$server->getEncryptionManager(), $uid diff --git a/lib/private/encryption/util.php b/lib/private/encryption/util.php index 961e7eceb2d..d983c92781c 100644 --- a/lib/private/encryption/util.php +++ b/lib/private/encryption/util.php @@ -66,7 +66,10 @@ class Util { protected $excludedPaths; /** - * @param \OC\Files\View $view root view + * + * @param \OC\Files\View $view + * @param \OC\User\Manager $userManager + * @param IConfig $config */ public function __construct( \OC\Files\View $view, diff --git a/lib/private/server.php b/lib/private/server.php index 6a2e45aa59d..d9c580c0f0c 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -414,7 +414,7 @@ class Server extends SimpleContainer implements IServerContainer { */ function getEncryptionKeyStorage($encryptionModuleId) { $view = new \OC\Files\View(); - $util = new \OC\Encryption\Util($view, \OC::$server->getUserManager()); + $util = new \OC\Encryption\Util($view, \OC::$server->getUserManager(), \OC::$server->getConfig()); return $this->query('EncryptionKeyStorageFactory')->get($encryptionModuleId, $view, $util); } -- cgit v1.2.3 From a85e2e0bfdb86de029f7b5fde42ead60498aed82 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Mon, 30 Mar 2015 11:49:03 +0200 Subject: make recovery settings work --- apps/encryption/appinfo/app.php | 11 +- apps/encryption/appinfo/application.php | 196 +++++++++++++++++++++++++++ apps/encryption/appinfo/encryption.php | 194 -------------------------- apps/encryption/appinfo/routes.php | 8 +- apps/encryption/js/settings-admin.js | 4 +- apps/encryption/lib/keymanager.php | 2 +- apps/encryption/settings/settings-admin.php | 3 - apps/encryption/templates/settings-admin.php | 6 +- lib/private/encryption/manager.php | 5 +- lib/public/iservercontainer.php | 12 ++ 10 files changed, 226 insertions(+), 215 deletions(-) create mode 100644 apps/encryption/appinfo/application.php delete mode 100644 apps/encryption/appinfo/encryption.php (limited to 'lib/private/encryption') diff --git a/apps/encryption/appinfo/app.php b/apps/encryption/appinfo/app.php index 72e7fc42ca0..38f9ff2f040 100644 --- a/apps/encryption/appinfo/app.php +++ b/apps/encryption/appinfo/app.php @@ -19,15 +19,10 @@ * */ -use OCA\Encryption\AppInfo\Encryption; +namespace OCA\Encryption\AppInfo; -if (!OC::$CLI) { +if (!\OC::$CLI) { $di = \OC::$server; - $app = new Encryption('encryption', - [], - $di->getEncryptionManager(), - $di->getConfig()); - - $app->boot(); + $app = new Application(); } diff --git a/apps/encryption/appinfo/application.php b/apps/encryption/appinfo/application.php new file mode 100644 index 00000000000..606c0cc5c49 --- /dev/null +++ b/apps/encryption/appinfo/application.php @@ -0,0 +1,196 @@ + + * @since 3/11/15, 11:03 AM + * @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 + * + */ +namespace OCA\Encryption\AppInfo; + + +use OC\Files\Filesystem; +use OC\Files\View; +use OCA\Encryption\Crypto\Crypt; +use OCA\Encryption\HookManager; +use OCA\Encryption\Hooks\UserHooks; +use OCA\Encryption\KeyManager; +use OCA\Encryption\Recovery; +use OCA\Encryption\Users\Setup; +use OCA\Encryption\Util; +use OCP\App; +use OCP\AppFramework\IAppContainer; +use OCP\Encryption\IManager; +use OCP\IConfig; + + +class Application extends \OCP\AppFramework\App { + /** + * @var IManager + */ + private $encryptionManager; + /** + * @var IConfig + */ + private $config; + + /** + * @param $appName + * @param array $urlParams + */ + public function __construct($urlParams = array()) { + parent::__construct('encryption', $urlParams); + $this->encryptionManager = \OC::$server->getEncryptionManager(); + $this->config = \OC::$server->getConfig(); + $this->registerServices(); + $this->registerEncryptionModule(); + $this->registerHooks(); + $this->registerSettings(); + } + + /** + * + */ + 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->getLogger(), + $container->query('UserSetup'), + $server->getUserSession(), + new \OCP\Util(), + $container->query('Util'), + $server->getSession()), + ]); + + $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(); + $container->registerService('EncryptionModule', function (IAppContainer $c) { + return new \OCA\Encryption\Crypto\Encryption( + $c->query('Crypt'), + $c->query('KeyManager'), + $c->query('Util')); + }); + $module = $container->query('EncryptionModule'); + $this->encryptionManager->registerEncryptionModule($module); + } + + /** + * + */ + public function registerServices() { + $container = $this->getContainer(); + + $container->registerService('Crypt', + function (IAppContainer $c) { + $server = $c->getServer(); + return new Crypt($server->getLogger(), + $server->getUserSession(), + $server->getConfig()); + }); + + $container->registerService('KeyManager', + function (IAppContainer $c) { + $server = $c->getServer(); + + return new KeyManager($server->getEncryptionKeyStorage(\OCA\Encryption\Crypto\Encryption::ID), + $c->query('Crypt'), + $server->getConfig(), + $server->getUserSession(), + $server->getSession(), + $server->getLogger() + ); + }); + + + $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(\OCA\Encryption\Crypto\Encryption::ID)); + }); + + $container->registerService('RecoveryController', function (IAppContainer $c) { + $server = $c->getServer(); + return new \OCA\Encryption\Controller\RecoveryController( + $c->getAppName(), + $server->getRequest(), + $server->getConfig(), + $server->getL10N($c->getAppName()), + $c->query('Recovery')); + }); + + $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(), + new Filesystem(), + $c->query('Crypt'), + $c->query('KeyManager'), + $server->getLogger(), + $server->getUserSession(), + $server->getConfig() + ); + }); + + } + + /** + * + */ + public function registerSettings() { + +// script('encryption', 'encryption'); +// script('encryption', 'detect-migration'); + + + // Register settings scripts + App::registerAdmin('encryption', 'settings/settings-admin'); + App::registerPersonal('encryption', 'settings/settings-personal'); + } +} diff --git a/apps/encryption/appinfo/encryption.php b/apps/encryption/appinfo/encryption.php deleted file mode 100644 index 6aad9219025..00000000000 --- a/apps/encryption/appinfo/encryption.php +++ /dev/null @@ -1,194 +0,0 @@ - - * @since 3/11/15, 11:03 AM - * @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 - * - */ -namespace OCA\Encryption\AppInfo; - - -use OC\Files\Filesystem; -use OC\Files\View; -use OCA\Encryption\Crypto\Crypt; -use OCA\Encryption\HookManager; -use OCA\Encryption\Hooks\UserHooks; -use OCA\Encryption\KeyManager; -use OCA\Encryption\Recovery; -use OCA\Encryption\Users\Setup; -use OCA\Encryption\Util; -use OCP\App; -use OCP\AppFramework\IAppContainer; -use OCP\Encryption\IManager; -use OCP\IConfig; - - -class Encryption extends \OCP\AppFramework\App { - /** - * @var IManager - */ - private $encryptionManager; - /** - * @var IConfig - */ - private $config; - - /** - * @param $appName - * @param array $urlParams - * @param IManager $encryptionManager - * @param IConfig $config - */ - public function __construct($appName, $urlParams = array(), IManager $encryptionManager, IConfig $config) { - parent::__construct($appName, $urlParams); - $this->encryptionManager = $encryptionManager; - $this->config = $config; - } - - /** - * - */ - public function boot() { - $this->registerServices(); - $this->registerEncryptionModule(); - $this->registerHooks(); - $this->registerSettings(); - } - - /** - * - */ - 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->getLogger(), - $container->query('UserSetup'), - $server->getUserSession(), - new \OCP\Util(), - $container->query('Util'), - $server->getSession()), - ]); - - $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(); - $container->registerService('EncryptionModule', function (IAppContainer $c) { - return new \OCA\Encryption\Crypto\Encryption( - $c->query('Crypt'), - $c->query('KeyManager'), - $c->query('Util')); - }); - $module = $container->query('EncryptionModule'); - $this->encryptionManager->registerEncryptionModule($module); - } - - /** - * - */ - public function registerServices() { - $container = $this->getContainer(); - - $container->registerService('Crypt', - function (IAppContainer $c) { - $server = $c->getServer(); - return new Crypt($server->getLogger(), - $server->getUserSession(), - $server->getConfig()); - }); - - $container->registerService('KeyManager', - function (IAppContainer $c) { - $server = $c->getServer(); - - return new KeyManager($server->getEncryptionKeyStorage(\OCA\Encryption\Crypto\Encryption::ID), - $c->query('Crypt'), - $server->getConfig(), - $server->getUserSession(), - $server->getSession(), - $server->getLogger() - ); - }); - - - $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(\OCA\Encryption\Crypto\Encryption::ID)); - }); - - $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(), - new Filesystem(), - $c->query('Crypt'), - $c->query('KeyManager'), - $server->getLogger(), - $server->getUserSession(), - $server->getConfig() - ); - }); - - } - - /** - * - */ - public function registerSettings() { - -// script('encryption', 'encryption'); -// script('encryption', 'detect-migration'); - - - // Register settings scripts - App::registerAdmin('encryption', 'settings/settings-admin'); - App::registerPersonal('encryption', 'settings/settings-personal'); - } -} diff --git a/apps/encryption/appinfo/routes.php b/apps/encryption/appinfo/routes.php index a86f3717ce9..b2c00c83349 100644 --- a/apps/encryption/appinfo/routes.php +++ b/apps/encryption/appinfo/routes.php @@ -20,17 +20,17 @@ */ -use OCP\AppFramework\App; +namespace OCA\Encryption\AppInfo; -(new App('encryption'))->registerRoutes($this, array('routes' => array( +(new Application())->registerRoutes($this, array('routes' => array( [ - 'name' => 'recovery#adminRecovery', + 'name' => 'Recovery#adminRecovery', 'url' => '/ajax/adminRecovery', 'verb' => 'POST' ], [ - 'name' => 'recovery#userRecovery', + 'name' => 'Recovery#userRecovery', 'url' => '/ajax/userRecovery', 'verb' => 'POST' ] diff --git a/apps/encryption/js/settings-admin.js b/apps/encryption/js/settings-admin.js index 2242c1f7124..e5d3bebb208 100644 --- a/apps/encryption/js/settings-admin.js +++ b/apps/encryption/js/settings-admin.js @@ -17,7 +17,7 @@ $(document).ready(function(){ var confirmPassword = $( '#repeatEncryptionRecoveryPassword' ).val(); OC.msg.startSaving('#encryptionSetRecoveryKey .msg'); $.post( - OC.filePath( 'files_encryption', 'ajax', 'adminrecovery.php' ) + OC.generateUrl('/apps/encryption/ajax/adminRecovery') , { adminEnableRecovery: recoveryStatus, recoveryPassword: recoveryPassword, confirmPassword: confirmPassword } , function( result ) { OC.msg.finishedSaving('#encryptionSetRecoveryKey .msg', result); @@ -44,7 +44,7 @@ $(document).ready(function(){ var confirmNewPassword = $('#repeatedNewEncryptionRecoveryPassword').val(); OC.msg.startSaving('#encryptionChangeRecoveryKey .msg'); $.post( - OC.filePath( 'files_encryption', 'ajax', 'changeRecoveryPassword.php' ) + OC.filePath( 'encryption', 'ajax', 'changeRecoveryPassword.php' ) , { oldPassword: oldRecoveryPassword, newPassword: newRecoveryPassword, confirmPassword: confirmNewPassword } , function( data ) { OC.msg.finishedSaving('#encryptionChangeRecoveryKey .msg', data); diff --git a/apps/encryption/lib/keymanager.php b/apps/encryption/lib/keymanager.php index b3961c8566e..68fb722c5ea 100644 --- a/apps/encryption/lib/keymanager.php +++ b/apps/encryption/lib/keymanager.php @@ -193,7 +193,7 @@ class KeyManager { if ($encryptedKey) { $this->setPrivateKey($uid, $encryptedKey); - $this->config->setAppValue('encryption', 'recoveryAdminEnabled', 1); + $this->config->setAppValue('encryption', 'recoveryAdminEnabled', 0); return true; } return false; diff --git a/apps/encryption/settings/settings-admin.php b/apps/encryption/settings/settings-admin.php index 813956aa0af..a34d30d1de5 100644 --- a/apps/encryption/settings/settings-admin.php +++ b/apps/encryption/settings/settings-admin.php @@ -18,7 +18,4 @@ $recoveryAdminEnabled = \OC::$server->getConfig()->getAppValue('encryption', 're $tmpl->assign('recoveryEnabled', $recoveryAdminEnabled); $tmpl->assign('initStatus', KeyManager::$session->get('initStatus')); -\OCP\Util::addscript('files_encryption', 'settings-admin'); -\OCP\Util::addscript('core', 'multiselect'); - return $tmpl->fetchPage(); diff --git a/apps/encryption/templates/settings-admin.php b/apps/encryption/templates/settings-admin.php index 252701e9ed0..616c593f6fb 100644 --- a/apps/encryption/templates/settings-admin.php +++ b/apps/encryption/templates/settings-admin.php @@ -1,6 +1,8 @@

t('ownCloud basic encryption module')); ?>

diff --git a/lib/private/encryption/manager.php b/lib/private/encryption/manager.php index fa50d32218d..7cd49d1c0e2 100644 --- a/lib/private/encryption/manager.php +++ b/lib/private/encryption/manager.php @@ -66,12 +66,15 @@ class Manager implements \OCP\Encryption\IManager { public function registerEncryptionModule(IEncryptionModule $module) { $id = $module->getId(); $name = $module->getDisplayName(); + + // FIXME why do we load the same encryption module multiple times + /* if (isset($this->encryptionModules[$id])) { $message = 'Id "' . $id . '" already used by encryption module "' . $name . '"'; throw new Exceptions\ModuleAlreadyExistsException($message); } - +*/ $defaultEncryptionModuleId = $this->getDefaultEncryptionModuleId(); if (empty($defaultEncryptionModuleId)) { diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index d7df884adf8..2db1fc32499 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -172,6 +172,18 @@ interface IServerContainer { */ function getL10N($app, $lang = null); + /** + * @return \OC\Encryption\Manager + */ + function getEncryptionManager(); + + /** + * @param string $encryptionModuleId encryption module ID + * + * @return \OCP\Encryption\Keys\IStorage + */ + function getEncryptionKeyStorage($encryptionModuleId); + /** * Returns the URL generator * -- cgit v1.2.3 From a905f641b3e619838c945caa29a1604f5b3ab8ba Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 30 Mar 2015 13:23:10 +0200 Subject: various fixes & start to unit test the encryption storage wrapper --- apps/encryption_dummy/lib/dummymodule.php | 28 ++++++------ .../encryptionheaderkeyexistsexception.php | 6 ++- lib/private/encryption/util.php | 33 +++++++------- lib/private/files/storage/wrapper/encryption.php | 6 ++- tests/lib/files/storage/wrapper/encryption.php | 50 ++++++++++++++++++++++ tests/lib/files/storage/wrapper/jail.php | 4 -- 6 files changed, 91 insertions(+), 36 deletions(-) create mode 100644 tests/lib/files/storage/wrapper/encryption.php (limited to 'lib/private/encryption') diff --git a/apps/encryption_dummy/lib/dummymodule.php b/apps/encryption_dummy/lib/dummymodule.php index 8ca9cd4f9af..55e8f26af95 100644 --- a/apps/encryption_dummy/lib/dummymodule.php +++ b/apps/encryption_dummy/lib/dummymodule.php @@ -23,7 +23,9 @@ namespace OCA\Encryption_Dummy; -class DummyModule implements \OCP\Encryption\IEncryptionModule { +use OCP\Encryption\IEncryptionModule; + +class DummyModule implements IEncryptionModule { /** @var boolean */ protected $isWriteOperation; @@ -103,17 +105,6 @@ class DummyModule implements \OCP\Encryption\IEncryptionModule { return $data; } - /** - * update encrypted file, e.g. give additional users access to the file - * - * @param string $path path to the file which should be updated - * @param array $accessList who has access to the file contains the key 'users' and 'public' - * @return boolean - */ - public function update($path, $accessList) { - return true; - } - /** * should the file be encrypted or not * @@ -142,4 +133,15 @@ class DummyModule implements \OCP\Encryption\IEncryptionModule { return 6126; } -} \ No newline at end of file + /** + * update encrypted file, e.g. give additional users access to the file + * + * @param string $path path to the file which should be updated + * @param string $uid of the user who performs the operation + * @param array $accessList who has access to the file contains the key 'users' and 'public' + * @return boolean + */ + public function update($path, $uid, $accessList) { + return true; + } +} diff --git a/lib/private/encryption/exceptions/encryptionheaderkeyexistsexception.php b/lib/private/encryption/exceptions/encryptionheaderkeyexistsexception.php index d401f0323ba..23103b90c4f 100644 --- a/lib/private/encryption/exceptions/encryptionheaderkeyexistsexception.php +++ b/lib/private/encryption/exceptions/encryptionheaderkeyexistsexception.php @@ -26,4 +26,8 @@ namespace OC\Encryption\Exceptions; class EncryptionHeaderKeyExistsException extends \Exception { -} \ No newline at end of file +} + +class EncryptionHeaderToLargeException extends \Exception { + +} diff --git a/lib/private/encryption/util.php b/lib/private/encryption/util.php index d983c92781c..1308d27c924 100644 --- a/lib/private/encryption/util.php +++ b/lib/private/encryption/util.php @@ -23,8 +23,9 @@ namespace OC\Encryption; -use OC\Encryption\Exceptions\EncryptionHeaderToLargeException; use OC\Encryption\Exceptions\EncryptionHeaderKeyExistsException; +use OC\Encryption\Exceptions\EncryptionHeaderToLargeException; +use OC\Files\View; use OCP\Encryption\IEncryptionModule; use OCP\IConfig; @@ -50,13 +51,13 @@ class Util { */ protected $blockSize = 8192; - /** @var \OC\Files\View */ + /** @var View */ protected $view; /** @var array */ protected $ocHeaderKeys; - /** @var \OC\User\Manager */ + /** @var Manager */ protected $userManager; /** @var IConfig */ @@ -93,7 +94,7 @@ class Util { * @param array $header * @return string */ - public function getEncryptionModuleId(array $header) { + public function getEncryptionModuleId(array $header = null) { $id = ''; $encryptionModuleKey = self::HEADER_ENCRYPTION_MODULE_KEY; @@ -153,7 +154,7 @@ class Util { $header .= self::HEADER_END; if (strlen($header) > $this->getHeaderSize()) { - throw new EncryptionHeaderToLargeException('max header size exceeded', EncryptionException::ENCRYPTION_HEADER_TO_LARGE); + throw new EncryptionHeaderToLargeException('max header size exceeded'); } $paddedHeader = str_pad($header, $this->headerSize, self::HEADER_PADDING_CHAR, STR_PAD_RIGHT); @@ -208,7 +209,7 @@ class Util { * go recursively through a dir and collect all files and sub files. * * @param string $dir relative to the users files folder - * @param strinf $mountPoint + * @param string $mountPoint * @return array with list of files relative to the users files folder */ public function getAllFiles($dir, $mountPoint = '') { @@ -285,19 +286,19 @@ class Util { throw new \BadMethodCallException('path needs to be relative to the system wide data folder and point to a user specific file'); } - $pathinfo = pathinfo($path); - $partfile = false; + $pathInfo = pathinfo($path); + $partFile = false; $parentFolder = false; - if (array_key_exists('extension', $pathinfo) && $pathinfo['extension'] === 'part') { + if (array_key_exists('extension', $pathInfo) && $pathInfo['extension'] === 'part') { // if the real file exists we check this file - $filePath = $pathinfo['dirname'] . '/' . $pathinfo['filename']; + $filePath = $pathInfo['dirname'] . '/' . $pathInfo['filename']; if ($this->view->file_exists($filePath)) { - $pathToCheck = $pathinfo['dirname'] . '/' . $pathinfo['filename']; + $pathToCheck = $pathInfo['dirname'] . '/' . $pathInfo['filename']; } else { // otherwise we look for the parent - $pathToCheck = $pathinfo['dirname']; + $pathToCheck = $pathInfo['dirname']; $parentFolder = true; } - $partfile = true; + $partFile = true; } else { $pathToCheck = $path; } @@ -320,11 +321,11 @@ class Util { $this->view->chroot('/'); if ($parentFolder) { - $ownerPath = $ownerPath . '/'. $pathinfo['filename']; + $ownerPath = $ownerPath . '/'. $pathInfo['filename']; } - if ($partfile) { - $ownerPath = $ownerPath . '.' . $pathinfo['extension']; + if ($partFile) { + $ownerPath = $ownerPath . '.' . $pathInfo['extension']; } return array( diff --git a/lib/private/files/storage/wrapper/encryption.php b/lib/private/files/storage/wrapper/encryption.php index 0e70c99c8d7..a9e65a00147 100644 --- a/lib/private/files/storage/wrapper/encryption.php +++ b/lib/private/files/storage/wrapper/encryption.php @@ -295,7 +295,9 @@ class Encryption extends Wrapper { * read encryption module needed to read/write the file located at $path * * @param string $path - * @return \OCP\Encryption\IEncryptionModule|null + * @return null|\OCP\Encryption\IEncryptionModule + * @throws ModuleDoesNotExistsException + * @throws \Exception */ protected function getEncryptionModule($path) { $encryptionModule = null; @@ -305,7 +307,7 @@ class Encryption extends Wrapper { try { $encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId); } catch (ModuleDoesNotExistsException $e) { - $this->logger->critical('Encryption module defined in "' . $path . '" mot loaded!'); + $this->logger->critical('Encryption module defined in "' . $path . '" not loaded!'); throw $e; } } diff --git a/tests/lib/files/storage/wrapper/encryption.php b/tests/lib/files/storage/wrapper/encryption.php new file mode 100644 index 00000000000..b8d4e962c54 --- /dev/null +++ b/tests/lib/files/storage/wrapper/encryption.php @@ -0,0 +1,50 @@ +getMockBuilder('\OC\Encryption\Manager') + ->disableOriginalConstructor() + ->setMethods(['getDefaultEncryptionModule', 'getEncryptionModule']) + ->getMock(); + $encryptionManager->expects($this->any()) + ->method('getDefaultEncryptionModule') + ->willReturn(new DummyModule()); + + $util = new \OC\Encryption\Util(new View(), new \OC\User\Manager()); + + $logger = $this->getMock('\OC\Log'); + + $this->sourceStorage = new \OC\Files\Storage\Temporary(array()); + $this->instance = new \OC\Files\Storage\Wrapper\Encryption([ + 'storage' => $this->sourceStorage, + 'root' => 'foo', + 'mountPoint' => '/' + ], + $encryptionManager, $util, $logger + ); + } + +// public function testMkDirRooted() { +// $this->instance->mkdir('bar'); +// $this->assertTrue($this->sourceStorage->is_dir('foo/bar')); +// } +// +// public function testFilePutContentsRooted() { +// $this->instance->file_put_contents('bar', 'asd'); +// $this->assertEquals('asd', $this->sourceStorage->file_get_contents('foo/bar')); +// } +} diff --git a/tests/lib/files/storage/wrapper/jail.php b/tests/lib/files/storage/wrapper/jail.php index 270ce750ecf..a7bd684df44 100644 --- a/tests/lib/files/storage/wrapper/jail.php +++ b/tests/lib/files/storage/wrapper/jail.php @@ -9,10 +9,6 @@ namespace Test\Files\Storage\Wrapper; class Jail extends \Test\Files\Storage\Storage { - /** - * @var string tmpDir - */ - private $tmpDir; /** * @var \OC\Files\Storage\Temporary -- cgit v1.2.3 From dbdd754c3fc37dc3100a9741f956d913e6d64576 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 30 Mar 2015 22:36:48 +0200 Subject: Further cleanup of files_encryption --- apps/encryption/lib/crypto/crypt.php | 10 +--------- build/license.php | 2 +- lib/base.php | 3 --- lib/private/app.php | 2 +- lib/private/connector/sabre/file.php | 4 +++- lib/private/encryption/keys/storage.php | 6 +++--- tests/enable_all.php | 1 - 7 files changed, 9 insertions(+), 19 deletions(-) (limited to 'lib/private/encryption') diff --git a/apps/encryption/lib/crypto/crypt.php b/apps/encryption/lib/crypto/crypt.php index c9f02bfa1cc..ea7f9e1cdf5 100644 --- a/apps/encryption/lib/crypto/crypt.php +++ b/apps/encryption/lib/crypto/crypt.php @@ -25,9 +25,6 @@ namespace OCA\Encryption\Crypto; use OC\Encryption\Exceptions\DecryptionFailedException; use OC\Encryption\Exceptions\EncryptionFailedException; use OC\Encryption\Exceptions\GenericEncryptionException; -use OCA\Encryption\KeyManager; -use OCA\Files_Encryption\Exception\MultiKeyDecryptException; -use OCA\Files_Encryption\Exception\MultiKeyEncryptException; use OCP\IConfig; use OCP\ILogger; use OCP\IUser; @@ -35,11 +32,6 @@ use OCP\IUserSession; class Crypt { - const ENCRYPTION_UKNOWN_ERROR = -1; - const ENCRYPTION_NOT_INIALIZED_ERROR = 1; - const ENCRYPTIION_PRIVATE_KEY_NOT_VALID_ERROR = 2; - const ENCRYPTION_NO_SHARE_KEY_FOUND = 3; - const BLOCKSIZE = 8192; const DEFAULT_CIPHER = 'AES-256-CFB'; @@ -97,7 +89,7 @@ class Crypt { 'privateKey' => $privateKey ]; } - $log->error('Encryption library couldn\'t export users private key, please check your servers openSSL configuration.' . $user->getUID(), + $log->error('Encryption library couldn\'t export users private key, please check your servers openSSL configuration.' . $this->user->getUID(), ['app' => 'encryption']); if (openssl_error_string()) { $log->error('Encryption Library:' . openssl_error_string(), diff --git a/build/license.php b/build/license.php index a8d82b084e6..6e3806e1464 100644 --- a/build/license.php +++ b/build/license.php @@ -166,7 +166,7 @@ if (isset($argv[1])) { } else { $licenses->exec([ '../apps/files', - '../apps/files_encryption', + '../apps/encryption', '../apps/files_external', '../apps/files_sharing', '../apps/files_trashbin', diff --git a/lib/base.php b/lib/base.php index 5d1e16296c0..44395be627d 100644 --- a/lib/base.php +++ b/lib/base.php @@ -743,9 +743,6 @@ class OC { ); \OCP\Util::connectHook('OCP\Share', 'post_shared', $updater, 'postShared'); \OCP\Util::connectHook('OCP\Share', 'post_unshare', $updater, 'postUnshared'); - - //\OCP\Util::connectHook('OC_Filesystem', 'post_umount', 'OCA\Files_Encryption\Hooks', 'postUnmount'); - //\OCP\Util::connectHook('OC_Filesystem', 'umount', 'OCA\Files_Encryption\Hooks', 'preUnmount'); } } diff --git a/lib/private/app.php b/lib/private/app.php index 84bc23608fb..4b3d4b82b82 100644 --- a/lib/private/app.php +++ b/lib/private/app.php @@ -207,7 +207,7 @@ class OC_App { self::$shippedApps = json_decode(file_get_contents($shippedJson), true); self::$shippedApps = self::$shippedApps['shippedApps']; } else { - self::$shippedApps = ['files', 'files_encryption', 'files_external', + self::$shippedApps = ['files', 'encryption', 'files_external', 'files_sharing', 'files_trashbin', 'files_versions', 'provisioning_api', 'user_ldap', 'user_webdavauth']; } diff --git a/lib/private/connector/sabre/file.php b/lib/private/connector/sabre/file.php index 5b8cb17a81c..58579f42dfc 100644 --- a/lib/private/connector/sabre/file.php +++ b/lib/private/connector/sabre/file.php @@ -35,6 +35,8 @@ namespace OC\Connector\Sabre; +use OC\Encryption\Exceptions\GenericEncryptionException; + class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile { /** @@ -125,7 +127,7 @@ class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile { } catch (\OCP\Files\LockNotAcquiredException $e) { // the file is currently being written to by another process throw new \OC\Connector\Sabre\Exception\FileLocked($e->getMessage(), $e->getCode(), $e); - } catch (\OCA\Files_Encryption\Exception\EncryptionException $e) { + } catch (GenericEncryptionException $e) { throw new \Sabre\DAV\Exception\Forbidden($e->getMessage()); } catch (\OCP\Files\StorageNotAvailableException $e) { throw new \Sabre\DAV\Exception\ServiceUnavailable("Failed to write file contents: ".$e->getMessage()); diff --git a/lib/private/encryption/keys/storage.php b/lib/private/encryption/keys/storage.php index 041db2a2cb8..82753df1dc7 100644 --- a/lib/private/encryption/keys/storage.php +++ b/lib/private/encryption/keys/storage.php @@ -23,9 +23,9 @@ namespace OC\Encryption\Keys; +use OC\Encryption\Exceptions\GenericEncryptionException; use OC\Encryption\Util; use OC\Files\View; -use OCA\Files_Encryption\Exception\EncryptionException; class Storage implements \OCP\Encryption\Keys\IStorage { @@ -253,13 +253,13 @@ class Storage implements \OCP\Encryption\Keys\IStorage { * * @param string $path path to the file, relative to data/ * @return string - * @throws EncryptionException + * @throws GenericEncryptionException * @internal param string $keyId */ private function getFileKeyDir($path) { if ($this->view->is_dir($path)) { - throw new EncryptionException('file was expected but directory was given', EncryptionException::GENERIC); + throw new GenericEncryptionException('file was expected but directory was given'); } list($owner, $filename) = $this->util->getUidAndFilename($path); diff --git a/tests/enable_all.php b/tests/enable_all.php index 61c94e6effe..464155b1f39 100644 --- a/tests/enable_all.php +++ b/tests/enable_all.php @@ -18,7 +18,6 @@ function enableApp($app) { enableApp('files_sharing'); enableApp('files_trashbin'); -enableApp('files_encryption'); enableApp('encryption'); enableApp('user_ldap'); enableApp('files_versions'); -- cgit v1.2.3 From 0f28d538a0af769220bcba120f0a7340dd0aba5f Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Tue, 31 Mar 2015 11:15:47 +0200 Subject: add session class to handle all session operations --- apps/encryption/appinfo/application.php | 5 +- apps/encryption/hooks/userhooks.php | 11 +-- .../lib/exceptions/privatekeymissingexception.php | 28 ++++++ apps/encryption/lib/keymanager.php | 28 ++---- apps/encryption/lib/session.php | 103 +++++++++++++++++++++ apps/encryption/settings/settings-personal.php | 12 +-- .../exceptions/privatekeymissingexception.php | 28 ------ 7 files changed, 153 insertions(+), 62 deletions(-) create mode 100644 apps/encryption/lib/exceptions/privatekeymissingexception.php create mode 100644 apps/encryption/lib/session.php delete mode 100644 lib/private/encryption/exceptions/privatekeymissingexception.php (limited to 'lib/private/encryption') diff --git a/apps/encryption/appinfo/application.php b/apps/encryption/appinfo/application.php index f9b7a1c60da..21d7f3e737f 100644 --- a/apps/encryption/appinfo/application.php +++ b/apps/encryption/appinfo/application.php @@ -76,9 +76,8 @@ class Application extends \OCP\AppFramework\App { $server->getLogger(), $container->query('UserSetup'), $server->getUserSession(), - new \OCP\Util(), $container->query('Util'), - $server->getSession()), + new \OCA\Encryption\Session($server->getSession())), ]); $hookManager->fireHooks(); @@ -126,7 +125,7 @@ class Application extends \OCP\AppFramework\App { $c->query('Crypt'), $server->getConfig(), $server->getUserSession(), - $server->getSession(), + new \OCA\Encryption\Session($server->getSession()), $server->getLogger(), $c->query('Recovery') ); diff --git a/apps/encryption/hooks/userhooks.php b/apps/encryption/hooks/userhooks.php index 1629aca0f55..27780cccfbf 100644 --- a/apps/encryption/hooks/userhooks.php +++ b/apps/encryption/hooks/userhooks.php @@ -22,7 +22,6 @@ namespace OCA\Encryption\Hooks; -use OCP\ISession; use OCP\Util as OCUtil; use OCA\Encryption\Hooks\Contracts\IHook; use OCA\Encryption\KeyManager; @@ -31,7 +30,7 @@ use OCP\App; use OCP\ILogger; use OCP\IUserSession; use OCA\Encryption\Util; -use Test\User; +use OCA\Encryption\Session; class UserHooks implements IHook { /** @@ -55,7 +54,7 @@ class UserHooks implements IHook { */ private $util; /** - * @var ISession + * @var Session */ private $session; @@ -66,17 +65,15 @@ class UserHooks implements IHook { * @param ILogger $logger * @param Setup $userSetup * @param IUserSession $user - * @param OCUtil $ocUtil * @param Util $util - * @param ISession $session + * @param Session $session */ public function __construct(KeyManager $keyManager, ILogger $logger, Setup $userSetup, IUserSession $user, - OCUtil $ocUtil, Util $util, - ISession $session) { + Session $session) { $this->keyManager = $keyManager; $this->logger = $logger; diff --git a/apps/encryption/lib/exceptions/privatekeymissingexception.php b/apps/encryption/lib/exceptions/privatekeymissingexception.php new file mode 100644 index 00000000000..e06940f7ac8 --- /dev/null +++ b/apps/encryption/lib/exceptions/privatekeymissingexception.php @@ -0,0 +1,28 @@ + + * @since 2/25/15, 9:39 AM + * @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 + * + */ + + +namespace OCA\Encryption\Exceptions; + + +class PrivateKeyMissingException extends GenericEncryptionException{ + +} diff --git a/apps/encryption/lib/keymanager.php b/apps/encryption/lib/keymanager.php index cd983be17f9..6c5f2348027 100644 --- a/apps/encryption/lib/keymanager.php +++ b/apps/encryption/lib/keymanager.php @@ -30,14 +30,14 @@ use OCP\Encryption\Keys\IStorage; use OCP\IConfig; use OCP\ILogger; use OCP\IUserSession; -use \OCP\ISession; +use \OCA\Encryption\Session; class KeyManager { /** - * @var ISession + * @var Session */ - public static $session; + protected $session; /** * @var IStorage */ @@ -84,17 +84,13 @@ class KeyManager { * @var ILogger */ private $log; - /** - * @var Recovery - */ - private $recovery; /** * @param IStorage $keyStorage * @param Crypt $crypt * @param IConfig $config * @param IUserSession $userSession - * @param \OCP\ISession $session + * @param Session $session * @param ILogger $log * @param Recovery $recovery */ @@ -103,12 +99,12 @@ class KeyManager { Crypt $crypt, IConfig $config, IUserSession $userSession, - ISession $session, + Session $session, ILogger $log, Recovery $recovery ) { - self::$session = $session; + $this->session = $session; $this->keyStorage = $keyStorage; $this->crypt = $crypt; $this->config = $config; @@ -271,7 +267,6 @@ class KeyManager { * * @param string $uid userid * @param string $passPhrase users password - * @return ISession */ public function init($uid, $passPhrase) { try { @@ -284,11 +279,8 @@ class KeyManager { return false; } - - self::$session->set('privateKey', $privateKey); - self::$session->set('initStatus', true); - - return self::$session; + $this->session->setPrivateKey($privateKey); + $this->session->setStatus(Session::INIT_SUCCESSFUL); } /** @@ -316,7 +308,7 @@ class KeyManager { $encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId); $shareKey = $this->getShareKey($path, $uid); - $privateKey = self::$session->get('privateKey'); + $privateKey = $this->session->getPrivateKey(); if ($encryptedFileKey && $shareKey && $privateKey) { $key = $this->crypt->multiKeyDecrypt($encryptedFileKey, @@ -348,7 +340,7 @@ class KeyManager { public function setPassphrase($params, IUserSession $user, Util $util) { // Get existing decrypted private key - $privateKey = self::$session->get('privateKey'); + $privateKey = $this->session->getPrivateKey(); if ($params['uid'] === $user->getUser()->getUID() && $privateKey) { diff --git a/apps/encryption/lib/session.php b/apps/encryption/lib/session.php new file mode 100644 index 00000000000..e049a8fe403 --- /dev/null +++ b/apps/encryption/lib/session.php @@ -0,0 +1,103 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library 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 library. If not, see . + */ + +namespace OCA\Encryption; + +use \OCP\ISession; + +class Session { + + /** @var ISession */ + protected $session; + + const NOT_INITIALIZED = '0'; + const INIT_EXECUTED = '1'; + const INIT_SUCCESSFUL = '2'; + + public function __construct(ISession $session) { + $this->session = $session; + } + + /** + * Sets status of encryption app + * + * @param string $status INIT_SUCCESSFUL, INIT_EXECUTED, NOT_INITIALIZED + */ + public function setStatus($status) { + $this->session->set('encryptionInitialized', $status); + } + + /** + * Gets status if we already tried to initialize the encryption app + * + * @return string init status INIT_SUCCESSFUL, INIT_EXECUTED, NOT_INITIALIZED + */ + public function getStatus() { + $status = $this->session->get('encryptionInitialized'); + if (is_null($status)) { + $status = self::NOT_INITIALIZED; + } + + return $status; + } + + /** + * Gets user or public share private key from session + * + * @return string $privateKey The user's plaintext private key + * @throws Exceptions\PrivateKeyMissingException + */ + public function getPrivateKey() { + $key = $this->session->get('privateKey'); + if (is_null($key)) { + throw new Exceptions\PrivateKeyMissingException('no private key stored in session'); + } + return $key; + } + + /** + * check if private key is set + * + * @return boolean + */ + public function isPrivateKeySet() { + $key = $this->session->get('privateKey'); + if (is_null($key)) { + return false; + } + + return true; + } + + /** + * Sets user private key to session + * + * @param string $key users private key + * + * @note this should only be set on login + */ + public function setPrivateKey($key) { + $this->session->set('privateKey', $key); + } + +} \ No newline at end of file diff --git a/apps/encryption/settings/settings-personal.php b/apps/encryption/settings/settings-personal.php index 540897b829d..83594b8467e 100644 --- a/apps/encryption/settings/settings-personal.php +++ b/apps/encryption/settings/settings-personal.php @@ -9,6 +9,8 @@ // Add CSS stylesheet \OC_Util::addStyle('encryption', 'settings-personal'); +$session = new \OCA\Encryption\Session(\OC::$server->getSession()); + $tmpl = new OCP\Template('encryption', 'settings-personal'); $crypt = new \OCA\Encryption\Crypto\Crypt( \OC::$server->getLogger(), @@ -19,8 +21,8 @@ $keymanager = new \OCA\Encryption\KeyManager( $crypt, \OC::$server->getConfig(), \OC::$server->getUserSession(), - \OC::$server->getSession(), - \OC::$server->getLogger(),); + $session, + \OC::$server->getLogger()); $user = \OCP\User::getUser(); @@ -29,11 +31,9 @@ $view = new \OC\Files\View('/'); $util = new \OCA\Encryption\Util( new \OC\Files\View(), $crypt, $keymanager, \OC::$server->getLogger(), \OC::$server->getUserSession(), \OC::$server->getConfig()); -$session = \OC::$server->getSession(); - -$privateKeySet = $session->get('privateKey') !== false; +$privateKeySet = $session->isPrivateKeySet(); // did we tried to initialize the keys for this session? -$initialized = $session->getInitialized(); +$initialized = $session->getStatus(); $recoveryAdminEnabled = \OC::$server->getConfig()->getAppValue('encryption', 'recoveryAdminEnabled'); $recoveryEnabledForUser = $util->recoveryEnabledForUser(); diff --git a/lib/private/encryption/exceptions/privatekeymissingexception.php b/lib/private/encryption/exceptions/privatekeymissingexception.php deleted file mode 100644 index 878b83d240c..00000000000 --- a/lib/private/encryption/exceptions/privatekeymissingexception.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @since 2/25/15, 9:39 AM - * @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 - * - */ - - -namespace OC\Encryption\Exceptions; - - -class PrivateKeyMissingException extends GenericEncryptionException{ - -} -- cgit v1.2.3 From 4db75e34074fa34d5558754e751b726338180e28 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 31 Mar 2015 13:25:11 +0200 Subject: Setting up the encryption wrapper in a setup hook - temporarily fixes the wrapping order --- lib/base.php | 18 +----------------- lib/private/encryption/manager.php | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 18 deletions(-) (limited to 'lib/private/encryption') diff --git a/lib/base.php b/lib/base.php index 44395be627d..a5ca08123ac 100644 --- a/lib/base.php +++ b/lib/base.php @@ -703,24 +703,8 @@ class OC { private static function registerEncryptionWrapper() { $enabled = self::$server->getEncryptionManager()->isEnabled(); if ($enabled) { - \OC\Files\Filesystem::addStorageWrapper('oc_encryption', function ($mountPoint, $storage, \OCP\Files\Mount\IMountPoint $mount) { - - $parameters = [ - 'storage' => $storage, - 'mountPoint' => $mountPoint, - 'mount' => $mount]; - $manager = \OC::$server->getEncryptionManager(); - $util = new \OC\Encryption\Util( - new \OC\Files\View(), - \OC::$server->getUserManager(), - \OC::$server->getConfig()); - $user = \OC::$server->getUserSession()->getUser(); - $logger = \OC::$server->getLogger(); - $uid = $user ? $user->getUID() : null; - return new \OC\Files\Storage\Wrapper\Encryption($parameters, $manager, $util, $logger, $uid); - }); + \OCP\Util::connectHook('OC_Filesystem', 'setup', 'OC\Encryption\Manager', 'setupStorage'); } - } private static function registerEncryptionHooks() { diff --git a/lib/private/encryption/manager.php b/lib/private/encryption/manager.php index 7cd49d1c0e2..bf411ea95e9 100644 --- a/lib/private/encryption/manager.php +++ b/lib/private/encryption/manager.php @@ -23,7 +23,9 @@ namespace OC\Encryption; +use OC\Files\Storage\Wrapper\Encryption; use OCP\Encryption\IEncryptionModule; +use OCP\Files\Mount\IMountPoint; class Manager implements \OCP\Encryption\IManager { @@ -181,5 +183,21 @@ class Manager implements \OCP\Encryption\IManager { } } - + public static function setupStorage() { + \OC\Files\Filesystem::addStorageWrapper('oc_encryption', function ($mountPoint, $storage, IMountPoint $mount) { + $parameters = [ + 'storage' => $storage, + 'mountPoint' => $mountPoint, + 'mount' => $mount]; + $manager = \OC::$server->getEncryptionManager(); + $util = new \OC\Encryption\Util( + new \OC\Files\View(), + \OC::$server->getUserManager(), + \OC::$server->getConfig()); + $user = \OC::$server->getUserSession()->getUser(); + $logger = \OC::$server->getLogger(); + $uid = $user ? $user->getUID() : null; + return new Encryption($parameters, $manager, $util, $logger, $uid); + }); + } } -- cgit v1.2.3 From a98b7dbf6fc3a190d995326ea97f88296ed89080 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 31 Mar 2015 13:48:27 +0200 Subject: Fix double registration of encryption module --- apps/encryption/appinfo/app.php | 7 ++----- apps/encryption/appinfo/application.php | 2 +- lib/private/encryption/manager.php | 5 +---- 3 files changed, 4 insertions(+), 10 deletions(-) (limited to 'lib/private/encryption') diff --git a/apps/encryption/appinfo/app.php b/apps/encryption/appinfo/app.php index 38f9ff2f040..8573f8d605d 100644 --- a/apps/encryption/appinfo/app.php +++ b/apps/encryption/appinfo/app.php @@ -21,8 +21,5 @@ namespace OCA\Encryption\AppInfo; -if (!\OC::$CLI) { - $di = \OC::$server; - $app = new Application(); -} - +$app = new Application(); +$app->registerEncryptionModule(); diff --git a/apps/encryption/appinfo/application.php b/apps/encryption/appinfo/application.php index be432b1a5a8..30962e83ada 100644 --- a/apps/encryption/appinfo/application.php +++ b/apps/encryption/appinfo/application.php @@ -55,7 +55,7 @@ class Application extends \OCP\AppFramework\App { $this->encryptionManager = \OC::$server->getEncryptionManager(); $this->config = \OC::$server->getConfig(); $this->registerServices(); - $this->registerEncryptionModule(); +// $this->registerEncryptionModule(); $this->registerHooks(); $this->registerSettings(); } diff --git a/lib/private/encryption/manager.php b/lib/private/encryption/manager.php index bf411ea95e9..cf11c3cf335 100644 --- a/lib/private/encryption/manager.php +++ b/lib/private/encryption/manager.php @@ -69,14 +69,11 @@ class Manager implements \OCP\Encryption\IManager { $id = $module->getId(); $name = $module->getDisplayName(); - // FIXME why do we load the same encryption module multiple times - /* if (isset($this->encryptionModules[$id])) { $message = 'Id "' . $id . '" already used by encryption module "' . $name . '"'; throw new Exceptions\ModuleAlreadyExistsException($message); - } -*/ + $defaultEncryptionModuleId = $this->getDefaultEncryptionModuleId(); if (empty($defaultEncryptionModuleId)) { -- cgit v1.2.3 From e4895bda01f9c94fc33e094ae9466e1cf5502916 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Tue, 31 Mar 2015 16:23:31 +0200 Subject: add helper class accessible for encryption modules to ask for a list of users with access to a file, needed to apply the recovery key to all files --- apps/encryption/appinfo/application.php | 4 +- apps/encryption/appinfo/routes.php | 5 ++ apps/encryption/controller/recoverycontroller.php | 61 ++++++++++++---- apps/encryption/js/settings-personal.js | 29 +------- apps/encryption/lib/recovery.php | 87 +++++++++++++++++++---- apps/encryption/settings/settings-personal.php | 6 +- apps/encryption/templates/settings-personal.php | 2 + lib/base.php | 1 + lib/private/encryption/file.php | 81 +++++++++++++++++++++ lib/private/encryption/update.php | 8 ++- lib/private/encryption/util.php | 47 +----------- lib/private/files/stream/encryption.php | 9 ++- lib/private/server.php | 12 ++++ lib/public/encryption/ifile.php | 36 ++++++++++ lib/public/encryption/imanager.php | 4 +- lib/public/iservercontainer.php | 5 ++ 16 files changed, 290 insertions(+), 107 deletions(-) create mode 100644 lib/private/encryption/file.php create mode 100644 lib/public/encryption/ifile.php (limited to 'lib/private/encryption') diff --git a/apps/encryption/appinfo/application.php b/apps/encryption/appinfo/application.php index e8f10798bb4..372d49e5ef7 100644 --- a/apps/encryption/appinfo/application.php +++ b/apps/encryption/appinfo/application.php @@ -139,7 +139,9 @@ class Application extends \OCP\AppFramework\App { $server->getSecureRandom(), $c->query('KeyManager'), $server->getConfig(), - $server->getEncryptionKeyStorage(\OCA\Encryption\Crypto\Encryption::ID)); + $server->getEncryptionKeyStorage(\OCA\Encryption\Crypto\Encryption::ID), + $server->getEncryptionFilesHelper(), + new \OC\Files\View()); }); $container->registerService('RecoveryController', function (IAppContainer $c) { diff --git a/apps/encryption/appinfo/routes.php b/apps/encryption/appinfo/routes.php index 030e7617816..1a6cf18fbed 100644 --- a/apps/encryption/appinfo/routes.php +++ b/apps/encryption/appinfo/routes.php @@ -38,6 +38,11 @@ namespace OCA\Encryption\AppInfo; 'name' => 'Recovery#changeRecoveryPassword', 'url' => '/ajax/changeRecoveryPassword', 'verb' => 'POST' + ], + [ + 'name' => 'Recovery#userSetRecovery', + 'url' => '/ajax/userSetRecovery', + 'verb' => 'POST' ] diff --git a/apps/encryption/controller/recoverycontroller.php b/apps/encryption/controller/recoverycontroller.php index e7bfd374903..d115feb8e39 100644 --- a/apps/encryption/controller/recoverycontroller.php +++ b/apps/encryption/controller/recoverycontroller.php @@ -61,61 +61,72 @@ class RecoveryController extends Controller { public function adminRecovery($recoveryPassword, $confirmPassword, $adminEnableRecovery) { // Check if both passwords are the same if (empty($recoveryPassword)) { - $errorMessage = $this->l->t('Missing recovery key password'); + $errorMessage = (string) $this->l->t('Missing recovery key password'); return new DataResponse(['data' => ['message' => $errorMessage]], 500); } if (empty($confirmPassword)) { - $errorMessage = $this->l->t('Please repeat the recovery key password'); + $errorMessage = (string) $this->l->t('Please repeat the recovery key password'); return new DataResponse(['data' => ['message' => $errorMessage]], 500); } if ($recoveryPassword !== $confirmPassword) { - $errorMessage = $this->l->t('Repeated recovery key password does not match the provided recovery key password'); + $errorMessage = (string) $this->l->t('Repeated recovery key password does not match the provided recovery key password'); return new DataResponse(['data' => ['message' => $errorMessage]], 500); } if (isset($adminEnableRecovery) && $adminEnableRecovery === '1') { if ($this->recovery->enableAdminRecovery($recoveryPassword)) { - return new DataResponse(['status' =>'success', 'data' => array('message' => $this->l->t('Recovery key successfully enabled'))]); + return new DataResponse(['status' =>'success', 'data' => array('message' => (string) $this->l->t('Recovery key successfully enabled'))]); } - return new DataResponse(['data' => array('message' => $this->l->t('Could not enable recovery key. Please check your recovery key password!'))]); + return new DataResponse(['data' => array('message' => (string) $this->l->t('Could not enable recovery key. Please check your recovery key password!'))]); } elseif (isset($adminEnableRecovery) && $adminEnableRecovery === '0') { if ($this->recovery->disableAdminRecovery($recoveryPassword)) { - return new DataResponse(['data' => array('message' => $this->l->t('Recovery key successfully disabled'))]); + return new DataResponse(['data' => array('message' => (string) $this->l->t('Recovery key successfully disabled'))]); } - return new DataResponse(['data' => array('message' => $this->l->t('Could not disable recovery key. Please check your recovery key password!'))]); + return new DataResponse(['data' => array('message' => (string) $this->l->t('Could not disable recovery key. Please check your recovery key password!'))]); } } public function changeRecoveryPassword($newPassword, $oldPassword, $confirmPassword) { //check if both passwords are the same if (empty($oldPassword)) { - $errorMessage = $this->l->t('Please provide the old recovery password'); + $errorMessage = (string) $this->l->t('Please provide the old recovery password'); return new DataResponse(array('data' => array('message' => $errorMessage))); } if (empty($newPassword)) { - $errorMessage = $this->l->t('Please provide a new recovery password'); + $errorMessage = (string) $this->l->t('Please provide a new recovery password'); return new DataResponse (array('data' => array('message' => $errorMessage))); } if (empty($confirmPassword)) { - $errorMessage = $this->l->t('Please repeat the new recovery password'); + $errorMessage = (string) $this->l->t('Please repeat the new recovery password'); return new DataResponse(array('data' => array('message' => $errorMessage))); } if ($newPassword !== $confirmPassword) { - $errorMessage = $this->l->t('Repeated recovery key password does not match the provided recovery key password'); + $errorMessage = (string) $this->l->t('Repeated recovery key password does not match the provided recovery key password'); return new DataResponse(array('data' => array('message' => $errorMessage))); } $result = $this->recovery->changeRecoveryKeyPassword($newPassword, $oldPassword); if ($result) { - return new DataResponse(array('status' => 'success' ,'data' => array('message' => $this->l->t('Password successfully changed.')))); + return new DataResponse( + array( + 'status' => 'success' , + 'data' => array( + 'message' => (string) $this->l->t('Password successfully changed.')) + ) + ); } else { - return new DataResponse(array('data' => array('message' => $this->l->t('Could not change the password. Maybe the old password was not correct.')))); + return new DataResponse( + array( + 'data' => array + ('message' => (string) $this->l->t('Could not change the password. Maybe the old password was not correct.')) + ) + ); } } @@ -131,4 +142,28 @@ class RecoveryController extends Controller { } } + public function userSetRecovery($userEnableRecovery) { + if ($userEnableRecovery === '0' || $userEnableRecovery === '1') { + + $result = $this->recovery->setRecoveryForUser($userEnableRecovery); + + if ($result) { + return new DataResponse( + array( + 'status' => 'success', + 'data' => array( + 'message' => (string) $this->l->t('Recovery Key enabled')) + ) + ); + } else { + return new DataResponse( + array( + 'data' => array + ('message' => (string) $this->l->t('Could not enable the recovery key, please try again or contact your administrator')) + ) + ); + } + } + } + } diff --git a/apps/encryption/js/settings-personal.js b/apps/encryption/js/settings-personal.js index b798ba7e4e1..7f0f4c6c26d 100644 --- a/apps/encryption/js/settings-personal.js +++ b/apps/encryption/js/settings-personal.js @@ -29,7 +29,7 @@ $(document).ready(function(){ var recoveryStatus = $( this ).val(); OC.msg.startAction('#userEnableRecovery .msg', 'Updating recovery keys. This can take some time...'); $.post( - OC.filePath( 'files_encryption', 'ajax', 'userrecovery.php' ) + OC.generateUrl('/apps/encryption/ajax/userSetRecovery') , { userEnableRecovery: recoveryStatus } , function( data ) { OC.msg.finishedAction('#userEnableRecovery .msg', data); @@ -40,33 +40,6 @@ $(document).ready(function(){ } ); - $("#encryptAll").click( - function(){ - - // Hide feedback messages in case they're already visible - $('#encryptAllSuccess').hide(); - $('#encryptAllError').hide(); - - var userPassword = $( '#userPassword' ).val(); - var encryptAll = $( '#encryptAll' ).val(); - - $.post( - OC.filePath( 'files_encryption', 'ajax', 'encryptall.php' ) - , { encryptAll: encryptAll, userPassword: userPassword } - , function( data ) { - if ( data.status == "success" ) { - $('#encryptAllSuccess').show(); - } else { - $('#encryptAllError').show(); - } - } - ); - // Ensure page is not reloaded on form submit - return false; - } - - ); - // update private key password $('input:password[name="changePrivateKeyPassword"]').keyup(function(event) { diff --git a/apps/encryption/lib/recovery.php b/apps/encryption/lib/recovery.php index 0426c3746ed..701c0934c95 100644 --- a/apps/encryption/lib/recovery.php +++ b/apps/encryption/lib/recovery.php @@ -29,7 +29,8 @@ use OCP\IUser; use OCP\IUserSession; use OCP\PreConditionNotMetException; use OCP\Security\ISecureRandom; -use OCP\Share; +use OC\Files\View; +use OCP\Encryption\IFile; class Recovery { @@ -58,7 +59,17 @@ class Recovery { * @var IStorage */ private $keyStorage; - + /** + * @var View + */ + private $view; + /** + * @var IFile + */ + private $file; + /** + * @var string + */ private $recoveryKeyId; /** @@ -68,19 +79,25 @@ class Recovery { * @param KeyManager $keyManager * @param IConfig $config * @param IStorage $keyStorage + * @param IFile $file + * @param View $view */ public function __construct(IUserSession $user, Crypt $crypt, ISecureRandom $random, KeyManager $keyManager, IConfig $config, - IStorage $keyStorage) { + IStorage $keyStorage, + IFile $file, + View $view) { $this->user = $user && $user->isLoggedIn() ? $user->getUser() : false; $this->crypt = $crypt; $this->random = $random; $this->keyManager = $keyManager; $this->config = $config; $this->keyStorage = $keyStorage; + $this->view = $view; + $this->file = $file; } /** @@ -138,14 +155,6 @@ class Recovery { return false; } - public function addRecoveryKeys($keyId) { - // No idea new way to do this.... - } - - public function removeRecoveryKeys() { - // No idea new way to do this.... - } - /** * @return bool */ @@ -159,23 +168,73 @@ class Recovery { } /** - * @param $enabled + * @param string $value * @return bool */ - public function setRecoveryForUser($enabled) { - $value = $enabled ? '1' : '0'; + public function setRecoveryForUser($value) { try { $this->config->setUserValue($this->user->getUID(), 'encryption', 'recoveryEnabled', $value); + + if ($value === '1') { + $this->addRecoveryKeys('/' . $this->user . '/files/'); + } else { + $this->removeRecoveryKeys(); + } + return true; } catch (PreConditionNotMetException $e) { return false; } } + /** + * add recovery key to all encrypted files + */ + private function addRecoveryKeys($path = '/') { + $dirContent = $this->view->getDirectoryContent($path); + foreach ($dirContent as $item) { + // get relative path from files_encryption/keyfiles/ + $filePath = $item['path']; + if ($item['type'] === 'dir') { + $this->addRecoveryKeys($filePath . '/'); + } else { + $fileKey = $this->keyManager->getFileKey($filePath, $this->user); + if (!empty($fileKey)) { + $accessList = $this->file->getAccessList($path); + $publicKeys = array(); + foreach ($accessList['users'] as $uid) { + $publicKeys[$uid] = $this->keymanager->getPublicKey($uid); + } + + $encryptedKeyfiles = $this->crypt->multiKeyEncrypt($fileKey, $publicKeys); + $this->keymanager->setAllFileKeys($path, $encryptedKeyfiles); + } + } + } + } + + /** + * remove recovery key to all encrypted files + */ + private function removeRecoveryKeys($path = '/') { + $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path); + foreach ($dirContent as $item) { + // get relative path from files_encryption/keyfiles + $filePath = substr($item['path'], strlen('files_encryption/keyfiles')); + if ($item['type'] === 'dir') { + $this->removeRecoveryKeys($filePath . '/'); + } else { + // remove '.key' extension from path e.g. 'file.txt.key' to 'file.txt' + $file = substr($filePath, 0, -4); + $this->view->unlink($this->shareKeysPath . '/' . $file . '.' . $this->recoveryKeyId . '.shareKey'); + } + } + } + /** * @param $recoveryPassword */ diff --git a/apps/encryption/settings/settings-personal.php b/apps/encryption/settings/settings-personal.php index a4173dbd40f..8caacbd19ca 100644 --- a/apps/encryption/settings/settings-personal.php +++ b/apps/encryption/settings/settings-personal.php @@ -29,7 +29,11 @@ $user = \OCP\User::getUser(); $view = new \OC\Files\View('/'); $util = new \OCA\Encryption\Util( - new \OC\Files\View(), $crypt, $keymanager, \OC::$server->getLogger(), \OC::$server->getUserSession(), \OC::$server->getConfig()); + new \OC\Files\View(), + $crypt, $keymanager, + \OC::$server->getLogger(), + \OC::$server->getUserSession(), + \OC::$server->getConfig()); $privateKeySet = $session->isPrivateKeySet(); // did we tried to initialize the keys for this session? diff --git a/apps/encryption/templates/settings-personal.php b/apps/encryption/templates/settings-personal.php index cefd6f4ad5c..6b8821ca8a8 100644 --- a/apps/encryption/templates/settings-personal.php +++ b/apps/encryption/templates/settings-personal.php @@ -1,6 +1,8 @@

t('ownCloud basic encryption module')); ?>

diff --git a/lib/base.php b/lib/base.php index a5ca08123ac..1d536464153 100644 --- a/lib/base.php +++ b/lib/base.php @@ -723,6 +723,7 @@ class OC { \OC::$server->getConfig()), \OC\Files\Filesystem::getMountManager(), \OC::$server->getEncryptionManager(), + \OC::$server->getEncryptionFilesHelper(), $uid ); \OCP\Util::connectHook('OCP\Share', 'post_shared', $updater, 'postShared'); diff --git a/lib/private/encryption/file.php b/lib/private/encryption/file.php new file mode 100644 index 00000000000..f231500fb02 --- /dev/null +++ b/lib/private/encryption/file.php @@ -0,0 +1,81 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library 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 library. If not, see . + */ + +namespace OC\Encryption; + +use OC\Encryption\Util; + +class File implements \OCP\Encryption\IFile { + + /** @var Util */ + protected $util; + + public function __construct(Util $util) { + $this->util = $util; + } + + + /** + * get list of users with access to the file + * + * @param $path to the file + * @return array + */ + public function getAccessList($path) { + + // Make sure that a share key is generated for the owner too + list($owner, $ownerPath) = $this->util->getUidAndFilename($path); + + // always add owner to the list of users with access to the file + $userIds = array($owner); + + if (!$this->util->isFile($ownerPath)) { + return array('users' => $userIds, 'public' => false); + } + + $ownerPath = substr($ownerPath, strlen('/files')); + $ownerPath = $this->util->stripPartialFileExtension($ownerPath); + + // Find out who, if anyone, is sharing the file + $result = \OCP\Share::getUsersSharingFile($ownerPath, $owner); + $userIds = \array_merge($userIds, $result['users']); + $public = $result['public'] || $result['remote']; + + // check if it is a group mount + if (\OCP\App::isEnabled("files_external")) { + $mounts = \OC_Mount_Config::getSystemMountPoints(); + foreach ($mounts as $mount) { + if ($mount['mountpoint'] == substr($ownerPath, 1, strlen($mount['mountpoint']))) { + $mountedFor = $this->util->getUserWithAccessToMountPoint($mount['applicable']['users'], $mount['applicable']['groups']); + $userIds = array_merge($userIds, $mountedFor); + } + } + } + + // Remove duplicate UIDs + $uniqueUserIds = array_unique($userIds); + + return array('users' => $uniqueUserIds, 'public' => $public); + } + +} \ No newline at end of file diff --git a/lib/private/encryption/update.php b/lib/private/encryption/update.php index 06dc330151e..21cedde6140 100644 --- a/lib/private/encryption/update.php +++ b/lib/private/encryption/update.php @@ -46,12 +46,16 @@ class Update { /** @var string */ protected $uid; + /** @var \OC\Encryption\File */ + protected $file; + /** * * @param \OC\Files\View $view * @param \OC\Encryption\Util $util * @param \OC\Files\Mount\Manager $mountManager * @param \OC\Encryption\Manager $encryptionManager + * @param \OC\Encryption\File $file * @param string $uid */ public function __construct( @@ -59,6 +63,7 @@ class Update { Util $util, Mount\Manager $mountManager, Manager $encryptionManager, + File $file, $uid ) { @@ -66,6 +71,7 @@ class Update { $this->util = $util; $this->mountManager = $mountManager; $this->encryptionManager = $encryptionManager; + $this->file = $file; $this->uid = $uid; } @@ -103,7 +109,7 @@ class Update { $encryptionModule = $this->encryptionManager->getDefaultEncryptionModule(); foreach ($allFiles as $path) { - $usersSharing = $this->util->getSharingUsersArray($path); + $usersSharing = $this->file->getAccessList($path); $encryptionModule->update($absPath, $this->uid, $usersSharing); } } diff --git a/lib/private/encryption/util.php b/lib/private/encryption/util.php index 1308d27c924..734da741fdd 100644 --- a/lib/private/encryption/util.php +++ b/lib/private/encryption/util.php @@ -162,49 +162,6 @@ class Util { return $paddedHeader; } - /** - * Find, sanitise and format users sharing a file - * @note This wraps other methods into a portable bundle - * @param string $path path relative to current users files folder - * @return array - */ - public function getSharingUsersArray($path) { - - // Make sure that a share key is generated for the owner too - list($owner, $ownerPath) = $this->getUidAndFilename($path); - - // always add owner to the list of users with access to the file - $userIds = array($owner); - - if (!$this->isFile($ownerPath)) { - return array('users' => $userIds, 'public' => false); - } - - $ownerPath = substr($ownerPath, strlen('/files')); - $ownerPath = $this->stripPartialFileExtension($ownerPath); - - // Find out who, if anyone, is sharing the file - $result = \OCP\Share::getUsersSharingFile($ownerPath, $owner); - $userIds = \array_merge($userIds, $result['users']); - $public = $result['public'] || $result['remote']; - - // check if it is a group mount - if (\OCP\App::isEnabled("files_external")) { - $mounts = \OC_Mount_Config::getSystemMountPoints(); - foreach ($mounts as $mount) { - if ($mount['mountpoint'] == substr($ownerPath, 1, strlen($mount['mountpoint']))) { - $mountedFor = $this->getUserWithAccessToMountPoint($mount['applicable']['users'], $mount['applicable']['groups']); - $userIds = array_merge($userIds, $mountedFor); - } - } - } - - // Remove duplicate UIDs - $uniqueUserIds = array_unique($userIds); - - return array('users' => $uniqueUserIds, 'public' => $public); - } - /** * go recursively through a dir and collect all files and sub files. * @@ -243,7 +200,7 @@ class Util { * @param string $path * @return boolean */ - protected function isFile($path) { + public function isFile($path) { if (substr($path, 0, strlen('/files/')) === '/files/') { return true; } @@ -361,7 +318,7 @@ class Util { } } - protected function getUserWithAccessToMountPoint($users, $groups) { + public function getUserWithAccessToMountPoint($users, $groups) { $result = array(); if (in_array('all', $users)) { $result = \OCP\User::getUsers(); diff --git a/lib/private/files/stream/encryption.php b/lib/private/files/stream/encryption.php index e3927edff2c..a96d573723c 100644 --- a/lib/private/files/stream/encryption.php +++ b/lib/private/files/stream/encryption.php @@ -31,6 +31,9 @@ class Encryption extends Wrapper { /** @var \OC\Encryption\Util */ protected $util; + /** @var \OC\Encryption\File */ + protected $file; + /** @var \OCP\Encryption\IEncryptionModule */ protected $encryptionModule; @@ -97,6 +100,7 @@ class Encryption extends Wrapper { 'encryptionModule', 'header', 'uid', + 'file', 'util', 'size', 'unencryptedSize', @@ -117,6 +121,7 @@ class Encryption extends Wrapper { * @param \OC\Files\Storage\Storage $storage * @param \OC\Files\Storage\Wrapper\Encryption $encStorage * @param \OC\Encryption\Util $util + * @param \OC\Encryption\File $file * @param string $mode * @param int $size * @param int $unencryptedSize @@ -130,6 +135,7 @@ class Encryption extends Wrapper { \OC\Files\Storage\Storage $storage, \OC\Files\Storage\Wrapper\Encryption $encStorage, \OC\Encryption\Util $util, + \OC\Encryption\File $file, $mode, $size, $unencryptedSize) { @@ -144,6 +150,7 @@ class Encryption extends Wrapper { 'header' => $header, 'uid' => $uid, 'util' => $util, + 'file' => $file, 'size' => $size, 'unencryptedSize' => $unencryptedSize, 'encryptionStorage' => $encStorage @@ -229,7 +236,7 @@ class Encryption extends Wrapper { $sharePath = dirname($path); } - $accessList = $this->util->getSharingUsersArray($sharePath); + $accessList = $this->file->getAccessList($sharePath); $this->newHeader = $this->encryptionModule->begin($this->fullPath, $this->uid, $this->header, $accessList); return true; diff --git a/lib/private/server.php b/lib/private/server.php index a38096cf740..661aaf6786d 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -87,6 +87,11 @@ class Server extends SimpleContainer implements IServerContainer { return new Encryption\Manager($c->getConfig()); }); + $this->registerService('EncryptionFileHelper', function (Server $c) { + $util = new \OC\Encryption\Util(new \OC\Files\View(), $c->getUserManager(), $c->getConfig()); + return new Encryption\File($util); + }); + $this->registerService('EncryptionKeyStorageFactory', function ($c) { return new Encryption\Keys\Factory(); }); @@ -407,6 +412,13 @@ class Server extends SimpleContainer implements IServerContainer { return $this->query('EncryptionManager'); } + /** + * @return \OC\Encryption\File + */ + function getEncryptionFilesHelper() { + return $this->query('EncryptionFileHelper'); + } + /** * @param string $encryptionModuleId encryption module ID * diff --git a/lib/public/encryption/ifile.php b/lib/public/encryption/ifile.php new file mode 100644 index 00000000000..cb4faea0625 --- /dev/null +++ b/lib/public/encryption/ifile.php @@ -0,0 +1,36 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library 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 library. If not, see . + */ + +namespace OCP\Encryption; + +interface IFile { + + /** + * get list of users with access to the file + * + * @param $path to the file + * @return array + */ + public function getAccessList($path); + +} \ No newline at end of file diff --git a/lib/public/encryption/imanager.php b/lib/public/encryption/imanager.php index 9a12e401593..2691604ac37 100644 --- a/lib/public/encryption/imanager.php +++ b/lib/public/encryption/imanager.php @@ -22,9 +22,7 @@ */ namespace OCP\Encryption; -// -// TODO: move exceptions to OCP -// + use OC\Encryption\Exceptions\ModuleDoesNotExistsException; use OC\Encryption\Exceptions\ModuleAlreadyExistsException; diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 9e36bc31bed..509e5894d47 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -183,6 +183,11 @@ interface IServerContainer { */ function getEncryptionManager(); + /** + * @return \OC\Encryption\File + */ + function getEncryptionFilesHelper(); + /** * @param string $encryptionModuleId encryption module ID * -- cgit v1.2.3 From 83cb382b3fb919bc7ce2d4e7f1fea027c3867460 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Wed, 1 Apr 2015 10:37:48 +0200 Subject: pass file helper to encryption wrapper --- lib/private/encryption/manager.php | 3 ++- lib/private/files/storage/wrapper/encryption.php | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'lib/private/encryption') diff --git a/lib/private/encryption/manager.php b/lib/private/encryption/manager.php index cf11c3cf335..77f02b0c489 100644 --- a/lib/private/encryption/manager.php +++ b/lib/private/encryption/manager.php @@ -194,7 +194,8 @@ class Manager implements \OCP\Encryption\IManager { $user = \OC::$server->getUserSession()->getUser(); $logger = \OC::$server->getLogger(); $uid = $user ? $user->getUID() : null; - return new Encryption($parameters, $manager, $util, $logger, $uid); + $fileHelper = \OC::$server->getEncryptionFilesHelper(); + return new Encryption($parameters, $manager, $util, $logger, $fileHelper, $uid); }); } } diff --git a/lib/private/files/storage/wrapper/encryption.php b/lib/private/files/storage/wrapper/encryption.php index cea7a38d41b..43052af8448 100644 --- a/lib/private/files/storage/wrapper/encryption.php +++ b/lib/private/files/storage/wrapper/encryption.php @@ -45,11 +45,15 @@ class Encryption extends Wrapper { /** @var array */ private $unencryptedSize; + /** @var \OC\Encryption\File */ + private $fileHelper; + /** * @param array $parameters * @param \OC\Encryption\Manager $encryptionManager * @param \OC\Encryption\Util $util * @param \OC\Log $logger + * @param \OC\Encryption\File $fileHelper * @param string $uid user who perform the read/write operation (null for public access) */ public function __construct( @@ -57,6 +61,7 @@ class Encryption extends Wrapper { \OC\Encryption\Manager $encryptionManager = null, \OC\Encryption\Util $util = null, \OC\Log $logger = null, + \OC\Encryption\File $fileHelper = null, $uid = null ) { @@ -65,6 +70,7 @@ class Encryption extends Wrapper { $this->util = $util; $this->logger = $logger; $this->uid = $uid; + $this->fileHelper = $fileHelper; $this->unencryptedSize = array(); parent::__construct($parameters); } @@ -250,7 +256,7 @@ class Encryption extends Wrapper { $uid = $owner; } $handle = \OC\Files\Stream\Encryption::wrap($source, $path, $fullPath, $header, - $uid, $encryptionModule, $this->storage, $this, $this->util, $mode, + $uid, $encryptionModule, $this->storage, $this, $this->util, $this->fileHelper, $mode, $size, $unencryptedSize); return $handle; } else { -- cgit v1.2.3 From f20844ac89f9c9d0860660b5cd5db352c6a38f80 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 1 Apr 2015 12:31:28 +0200 Subject: PHPDoc --- lib/private/encryption/file.php | 6 ++---- lib/public/encryption/ifile.php | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'lib/private/encryption') diff --git a/lib/private/encryption/file.php b/lib/private/encryption/file.php index f231500fb02..3600936ed0e 100644 --- a/lib/private/encryption/file.php +++ b/lib/private/encryption/file.php @@ -23,8 +23,6 @@ namespace OC\Encryption; -use OC\Encryption\Util; - class File implements \OCP\Encryption\IFile { /** @var Util */ @@ -38,7 +36,7 @@ class File implements \OCP\Encryption\IFile { /** * get list of users with access to the file * - * @param $path to the file + * @param string $path to the file * @return array */ public function getAccessList($path) { @@ -78,4 +76,4 @@ class File implements \OCP\Encryption\IFile { return array('users' => $uniqueUserIds, 'public' => $public); } -} \ No newline at end of file +} diff --git a/lib/public/encryption/ifile.php b/lib/public/encryption/ifile.php index cb4faea0625..464f41509d2 100644 --- a/lib/public/encryption/ifile.php +++ b/lib/public/encryption/ifile.php @@ -28,9 +28,9 @@ interface IFile { /** * get list of users with access to the file * - * @param $path to the file + * @param string $path to the file * @return array */ public function getAccessList($path); -} \ No newline at end of file +} -- cgit v1.2.3 From cac83642f2df98497ecedcded1716c28fa676313 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 1 Apr 2015 13:59:29 +0200 Subject: Finally fixing encryption with public share --- apps/encryption/lib/keymanager.php | 58 ++++++++++++++++++--------------- lib/private/encryption/update.php | 32 +++++++++--------- lib/private/files/stream/encryption.php | 2 +- 3 files changed, 48 insertions(+), 44 deletions(-) (limited to 'lib/private/encryption') diff --git a/apps/encryption/lib/keymanager.php b/apps/encryption/lib/keymanager.php index f96c426a725..f3f96b9ef21 100644 --- a/apps/encryption/lib/keymanager.php +++ b/apps/encryption/lib/keymanager.php @@ -23,6 +23,7 @@ namespace OCA\Encryption; use OC\Encryption\Exceptions\DecryptionFailedException; +use OCA\Encryption\Exceptions\FileKeyMissingException; use OCA\Encryption\Exceptions\PrivateKeyMissingException; use OC\Encryption\Exceptions\PublicKeyMissingException; use OCA\Encryption\Crypto\Crypt; @@ -114,6 +115,8 @@ class KeyManager { $this->keyStorage = $keyStorage; $this->crypt = $crypt; $this->config = $config; + $this->log = $log; + $this->recoveryKeyId = $this->config->getAppValue('encryption', 'recoveryKeyId'); if (empty($this->recoveryKeyId)) { @@ -123,34 +126,24 @@ class KeyManager { $this->recoveryKeyId); } - $this->publicShareKeyId = $this->config->getAppValue('encryption', 'publicShareKeyId'); - $this->log = $log; - if (empty($this->publicShareKeyId)) { $this->publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8); - $this->config->setAppValue('encryption', - 'publicShareKeyId', - $this->publicShareKeyId); + $this->config->setAppValue('encryption', 'publicShareKeyId', $this->publicShareKeyId); + } + $shareKey = $this->getPublicShareKey(); + if (empty($shareKey)) { $keyPair = $this->crypt->createKeyPair(); // Save public key $this->keyStorage->setSystemUserKey( - $this->publicShareKeyId . '.publicKey', - $keyPair['publicKey']); + $this->publicShareKeyId . '.publicKey', $keyPair['publicKey']); // Encrypt private key empty passphrase - $encryptedKey = $this->crypt->symmetricEncryptFileContent($keyPair['privateKey'], - ''); - if ($encryptedKey) { - $this->keyStorage->setSystemUserKey($this->publicShareKeyId . '.privateKey', - $encryptedKey); - } else { - $this->log->error('Could not create public share keys'); - } - + $encryptedKey = $this->crypt->symmetricEncryptFileContent($keyPair['privateKey'], ''); + $this->keyStorage->setSystemUserKey($this->publicShareKeyId . '.privateKey', $encryptedKey); } $this->keyId = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : false; @@ -161,7 +154,8 @@ class KeyManager { * @return bool */ public function recoveryKeyExists() { - return (!empty($this->keyStorage->getSystemUserKey($this->recoveryKeyId . '.publicKey'))); + $key = $this->getRecoveryKey(); + return (!empty($key)); } /** @@ -340,19 +334,25 @@ class KeyManager { * @return string */ public function getFileKey($path, $uid) { - $key = ''; - $encryptedFileKey = $this->keyStorage->getFileKey($path, - $this->fileKeyId); - $shareKey = $this->getShareKey($path, $uid); - $privateKey = $this->session->getPrivateKey(); + $encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId); + + if (is_null($uid)) { + $uid = $this->getPublicShareKeyId(); + $shareKey = $this->getShareKey($path, $uid); + $privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey'); + $privateKey = $this->crypt->symmetricDecryptFileContent($privateKey); + } else { + $shareKey = $this->getShareKey($path, $uid); + $privateKey = $this->session->getPrivateKey(); + } if ($encryptedFileKey && $shareKey && $privateKey) { - $key = $this->crypt->multiKeyDecrypt($encryptedFileKey, + return $this->crypt->multiKeyDecrypt($encryptedFileKey, $shareKey, $privateKey); } - return $key; + throw new FileKeyMissingException(); } /** @@ -412,7 +412,7 @@ class KeyManager { } /** - * get public key for public link shares + * get public key for public link shares * * @return string */ @@ -504,7 +504,11 @@ class KeyManager { */ public function addSystemKeys(array $accessList, array $publicKeys) { if (!empty($accessList['public'])) { - $publicKeys[$this->getPublicShareKeyId()] = $this->getPublicShareKey(); + $publicShareKey = $this->getPublicShareKey(); + if (empty($publicShareKey)) { + throw new PublicKeyMissingException(); + } + $publicKeys[$this->getPublicShareKeyId()] = $publicShareKey; } if ($this->recoveryKeyExists() && diff --git a/lib/private/encryption/update.php b/lib/private/encryption/update.php index 21cedde6140..e838e870502 100644 --- a/lib/private/encryption/update.php +++ b/lib/private/encryption/update.php @@ -93,25 +93,25 @@ class Update { * @param int $fileSource file source id */ private function update($fileSource) { - $path = \OC\Files\Filesystem::getPath($fileSource); - $absPath = '/' . $this->uid . '/files' . $path; + $path = \OC\Files\Filesystem::getPath($fileSource); + $absPath = '/' . $this->uid . '/files' . $path; - $mount = $this->mountManager->find($path); - $mountPoint = $mount->getMountPoint(); + $mount = $this->mountManager->find($path); + $mountPoint = $mount->getMountPoint(); - // if a folder was shared, get a list of all (sub-)folders - if ($this->view->is_dir($absPath)) { - $allFiles = $this->util->getAllFiles($absPath, $mountPoint); - } else { - $allFiles = array($absPath); - } + // if a folder was shared, get a list of all (sub-)folders + if ($this->view->is_dir($absPath)) { + $allFiles = $this->util->getAllFiles($absPath, $mountPoint); + } else { + $allFiles = array($absPath); + } - $encryptionModule = $this->encryptionManager->getDefaultEncryptionModule(); + $encryptionModule = $this->encryptionManager->getDefaultEncryptionModule(); - foreach ($allFiles as $path) { - $usersSharing = $this->file->getAccessList($path); - $encryptionModule->update($absPath, $this->uid, $usersSharing); - } + foreach ($allFiles as $path) { + $usersSharing = $this->file->getAccessList($path); + $encryptionModule->update($absPath, $this->uid, $usersSharing); + } } -} \ No newline at end of file +} diff --git a/lib/private/files/stream/encryption.php b/lib/private/files/stream/encryption.php index a96d573723c..88957825de0 100644 --- a/lib/private/files/stream/encryption.php +++ b/lib/private/files/stream/encryption.php @@ -198,7 +198,7 @@ class Encryption extends Wrapper { $context = parent::loadContext($name); foreach ($this->expectedContextProperties as $property) { - if (isset($context[$property])) { + if (array_key_exists($property, $context)) { $this->{$property} = $context[$property]; } else { throw new \BadMethodCallException('Invalid context, "' . $property . '" options not set'); -- cgit v1.2.3 From 51302d58120e9050fb8842cf63cef88620f74203 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Wed, 1 Apr 2015 14:24:42 +0200 Subject: getUidAndFilename() always get uid from path --- lib/private/encryption/util.php | 52 +++++------------------------------------ 1 file changed, 6 insertions(+), 46 deletions(-) (limited to 'lib/private/encryption') diff --git a/lib/private/encryption/util.php b/lib/private/encryption/util.php index 734da741fdd..1183e6622bb 100644 --- a/lib/private/encryption/util.php +++ b/lib/private/encryption/util.php @@ -226,7 +226,7 @@ class Util { } /** - * get the owner and the path for the owner + * get the owner and the path for the file relative to the owners files folder * * @param string $path * @return array @@ -240,55 +240,15 @@ class Util { $uid = $parts[1]; } if (!$this->userManager->userExists($uid)) { - throw new \BadMethodCallException('path needs to be relative to the system wide data folder and point to a user specific file'); + throw new \BadMethodCallException( + 'path needs to be relative to the system wide data folder and point to a user specific file' + ); } - $pathInfo = pathinfo($path); - $partFile = false; - $parentFolder = false; - if (array_key_exists('extension', $pathInfo) && $pathInfo['extension'] === 'part') { - // if the real file exists we check this file - $filePath = $pathInfo['dirname'] . '/' . $pathInfo['filename']; - if ($this->view->file_exists($filePath)) { - $pathToCheck = $pathInfo['dirname'] . '/' . $pathInfo['filename']; - } else { // otherwise we look for the parent - $pathToCheck = $pathInfo['dirname']; - $parentFolder = true; - } - $partFile = true; - } else { - $pathToCheck = $path; - } - - $pathToCheck = substr($pathToCheck, strlen('/' . $uid)); - - $this->view->chroot('/' . $uid); - $owner = $this->view->getOwner($pathToCheck); - - // Check that UID is valid - if (!$this->userManager->userExists($owner)) { - throw new \BadMethodCallException('path needs to be relative to the system wide data folder and point to a user specific file'); - } - - \OC\Files\Filesystem::initMountPoints($owner); - - $info = $this->view->getFileInfo($pathToCheck); - $this->view->chroot('/' . $owner); - $ownerPath = $this->view->getPath($info->getId()); - $this->view->chroot('/'); + $ownerPath = implode('/', array_slice($parts, 2)); - if ($parentFolder) { - $ownerPath = $ownerPath . '/'. $pathInfo['filename']; - } - - if ($partFile) { - $ownerPath = $ownerPath . '.' . $pathInfo['extension']; - } + return array($uid, \OC\Files\Filesystem::normalizePath($ownerPath)); - return array( - $owner, - \OC\Files\Filesystem::normalizePath($ownerPath) - ); } /** -- cgit v1.2.3 From 664b2bb7af2c8253aa0bbade42531ad4a3ef6bab Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 1 Apr 2015 16:36:08 +0200 Subject: cleaning up exception mess --- apps/encryption/lib/crypto/crypt.php | 2 +- .../lib/exceptions/multikeydecryptexception.php | 4 ++- .../lib/exceptions/multikeyencryptexception.php | 4 ++- .../lib/exceptions/privatekeymissingexception.php | 14 +++++++-- .../lib/exceptions/publickeymissingexception.php | 20 +++++++++++++ apps/encryption/lib/keymanager.php | 8 ++--- apps/encryption/lib/session.php | 2 +- lib/private/connector/sabre/file.php | 4 +-- .../exceptions/decryptionfailedexception.php | 1 + .../exceptions/emptyencryptiondataexception.php | 1 + .../exceptions/encryptionfailedexception.php | 1 + .../encryptionheaderkeyexistsexception.php | 13 +++++---- .../encryptionheadertolargeexception.php | 5 ++++ .../exceptions/genericencryptionexception.php | 27 ----------------- .../exceptions/modulealreadyexistsexception.php | 12 +++++++- .../exceptions/moduledoesnotexistsexception.php | 4 ++- .../exceptions/publickeymissingexception.php | 28 ------------------ .../exceptions/unexpectedblocksizeexception.php | 28 ------------------ .../unexpectedendofencryptionheaderexception.php | 28 ------------------ .../exceptions/unknowncipherexception.php | 3 +- lib/private/encryption/keys/storage.php | 4 +-- lib/private/encryption/manager.php | 3 +- lib/private/encryption/util.php | 4 +-- .../exceptions/genericencryptionexception.php | 34 ++++++++++++++++++++++ 24 files changed, 117 insertions(+), 137 deletions(-) create mode 100644 apps/encryption/lib/exceptions/publickeymissingexception.php delete mode 100644 lib/private/encryption/exceptions/genericencryptionexception.php delete mode 100644 lib/private/encryption/exceptions/publickeymissingexception.php delete mode 100644 lib/private/encryption/exceptions/unexpectedblocksizeexception.php delete mode 100644 lib/private/encryption/exceptions/unexpectedendofencryptionheaderexception.php create mode 100644 lib/public/encryption/exceptions/genericencryptionexception.php (limited to 'lib/private/encryption') diff --git a/apps/encryption/lib/crypto/crypt.php b/apps/encryption/lib/crypto/crypt.php index 6b79057fe7e..80878b3ddb2 100644 --- a/apps/encryption/lib/crypto/crypt.php +++ b/apps/encryption/lib/crypto/crypt.php @@ -24,9 +24,9 @@ namespace OCA\Encryption\Crypto; use OC\Encryption\Exceptions\DecryptionFailedException; use OC\Encryption\Exceptions\EncryptionFailedException; -use OC\Encryption\Exceptions\GenericEncryptionException; use OCA\Encryption\Exceptions\MultiKeyDecryptException; use OCA\Encryption\Exceptions\MultiKeyEncryptException; +use OCP\Encryption\Exceptions\GenericEncryptionException; use OCP\IConfig; use OCP\ILogger; use OCP\IUser; diff --git a/apps/encryption/lib/exceptions/multikeydecryptexception.php b/apps/encryption/lib/exceptions/multikeydecryptexception.php index 36a95544e61..1466d35eda3 100644 --- a/apps/encryption/lib/exceptions/multikeydecryptexception.php +++ b/apps/encryption/lib/exceptions/multikeydecryptexception.php @@ -2,6 +2,8 @@ namespace OCA\Encryption\Exceptions; -class MultiKeyDecryptException extends \Exception { +use OCP\Encryption\Exceptions\GenericEncryptionException; + +class MultiKeyDecryptException extends GenericEncryptionException { } diff --git a/apps/encryption/lib/exceptions/multikeyencryptexception.php b/apps/encryption/lib/exceptions/multikeyencryptexception.php index e518a09d1cc..daf528e2cf7 100644 --- a/apps/encryption/lib/exceptions/multikeyencryptexception.php +++ b/apps/encryption/lib/exceptions/multikeyencryptexception.php @@ -2,6 +2,8 @@ namespace OCA\Encryption\Exceptions; -class MultiKeyEncryptException extends \Exception { +use OCP\Encryption\Exceptions\GenericEncryptionException; + +class MultiKeyEncryptException extends GenericEncryptionException { } diff --git a/apps/encryption/lib/exceptions/privatekeymissingexception.php b/apps/encryption/lib/exceptions/privatekeymissingexception.php index ddc3d11cdbc..50d75870b20 100644 --- a/apps/encryption/lib/exceptions/privatekeymissingexception.php +++ b/apps/encryption/lib/exceptions/privatekeymissingexception.php @@ -19,10 +19,20 @@ * */ - namespace OCA\Encryption\Exceptions; +use OCP\Encryption\Exceptions\GenericEncryptionException; + +class PrivateKeyMissingException extends GenericEncryptionException { -class PrivateKeyMissingException extends \Exception{ + /** + * @param string $userId + */ + public function __construct($userId) { + if(empty($userId)) { + $userId = ""; + } + parent::__construct("Private Key missing for user: $userId"); + } } diff --git a/apps/encryption/lib/exceptions/publickeymissingexception.php b/apps/encryption/lib/exceptions/publickeymissingexception.php new file mode 100644 index 00000000000..9638c28e427 --- /dev/null +++ b/apps/encryption/lib/exceptions/publickeymissingexception.php @@ -0,0 +1,20 @@ +"; + } + parent::__construct("Public Key missing for user: $userId"); + } + +} diff --git a/apps/encryption/lib/keymanager.php b/apps/encryption/lib/keymanager.php index c7e0f2617f5..d2659f55a77 100644 --- a/apps/encryption/lib/keymanager.php +++ b/apps/encryption/lib/keymanager.php @@ -4,7 +4,7 @@ namespace OCA\Encryption; use OC\Encryption\Exceptions\DecryptionFailedException; use OCA\Encryption\Exceptions\PrivateKeyMissingException; -use OC\Encryption\Exceptions\PublicKeyMissingException; +use OCA\Encryption\Exceptions\PublicKeyMissingException; use OCA\Encryption\Crypto\Crypt; use OCP\Encryption\Keys\IStorage; use OCP\IConfig; @@ -301,7 +301,7 @@ class KeyManager { if (strlen($privateKey) !== 0) { return $privateKey; } - throw new PrivateKeyMissingException(); + throw new PrivateKeyMissingException($userId); } /** @@ -393,7 +393,7 @@ class KeyManager { if (strlen($publicKey) !== 0) { return $publicKey; } - throw new PublicKeyMissingException(); + throw new PublicKeyMissingException($userId); } public function getPublicShareKeyId() { @@ -496,7 +496,7 @@ class KeyManager { if (!empty($accessList['public'])) { $publicShareKey = $this->getPublicShareKey(); if (empty($publicShareKey)) { - throw new PublicKeyMissingException(); + throw new PublicKeyMissingException($this->getPublicShareKeyId()); } $publicKeys[$this->getPublicShareKeyId()] = $publicShareKey; } diff --git a/apps/encryption/lib/session.php b/apps/encryption/lib/session.php index 5e973913769..82c7829ecbd 100644 --- a/apps/encryption/lib/session.php +++ b/apps/encryption/lib/session.php @@ -70,7 +70,7 @@ class Session { public function getPrivateKey() { $key = $this->session->get('privateKey'); if (is_null($key)) { - throw new Exceptions\PrivateKeyMissingException('no private key stored in session'); + throw new Exceptions\PrivateKeyMissingException('no private key stored in session', 0); } return $key; } diff --git a/lib/private/connector/sabre/file.php b/lib/private/connector/sabre/file.php index a436973ba91..f6f5daf2074 100644 --- a/lib/private/connector/sabre/file.php +++ b/lib/private/connector/sabre/file.php @@ -35,7 +35,7 @@ namespace OC\Connector\Sabre; -use OC\Encryption\Exceptions\GenericEncryptionException; +use OCP\Encryption\Exceptions\GenericEncryptionException; class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile { @@ -184,7 +184,7 @@ class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile { //throw exception if encryption is disabled but files are still encrypted try { return $this->fileView->fopen(ltrim($this->path, '/'), 'rb'); - } catch (\OCP\Encryption\Exception\EncryptionException $e) { + } catch (\OCP\Encryption\Exceptions\GenericEncryptionException $e) { throw new \Sabre\DAV\Exception\Forbidden($e->getMessage()); } catch (\OCP\Files\StorageNotAvailableException $e) { throw new \Sabre\DAV\Exception\ServiceUnavailable("Failed to open file: ".$e->getMessage()); diff --git a/lib/private/encryption/exceptions/decryptionfailedexception.php b/lib/private/encryption/exceptions/decryptionfailedexception.php index 43fea90fed8..f8b4fdf07fa 100644 --- a/lib/private/encryption/exceptions/decryptionfailedexception.php +++ b/lib/private/encryption/exceptions/decryptionfailedexception.php @@ -22,6 +22,7 @@ namespace OC\Encryption\Exceptions; +use OCP\Encryption\Exceptions\GenericEncryptionException; class DecryptionFailedException extends GenericEncryptionException { diff --git a/lib/private/encryption/exceptions/emptyencryptiondataexception.php b/lib/private/encryption/exceptions/emptyencryptiondataexception.php index ea181809856..d3dc9230047 100644 --- a/lib/private/encryption/exceptions/emptyencryptiondataexception.php +++ b/lib/private/encryption/exceptions/emptyencryptiondataexception.php @@ -22,6 +22,7 @@ namespace OC\Encryption\Exceptions; +use OCP\Encryption\Exceptions\GenericEncryptionException; class EmptyEncryptionDataException extends GenericEncryptionException{ diff --git a/lib/private/encryption/exceptions/encryptionfailedexception.php b/lib/private/encryption/exceptions/encryptionfailedexception.php index 9e6648f7bf5..ac489c73254 100644 --- a/lib/private/encryption/exceptions/encryptionfailedexception.php +++ b/lib/private/encryption/exceptions/encryptionfailedexception.php @@ -22,6 +22,7 @@ namespace OC\Encryption\Exceptions; +use OCP\Encryption\Exceptions\GenericEncryptionException; class EncryptionFailedException extends GenericEncryptionException{ diff --git a/lib/private/encryption/exceptions/encryptionheaderkeyexistsexception.php b/lib/private/encryption/exceptions/encryptionheaderkeyexistsexception.php index 23103b90c4f..5e8e48efd78 100644 --- a/lib/private/encryption/exceptions/encryptionheaderkeyexistsexception.php +++ b/lib/private/encryption/exceptions/encryptionheaderkeyexistsexception.php @@ -23,11 +23,14 @@ namespace OC\Encryption\Exceptions; +use OCP\Encryption\Exceptions\GenericEncryptionException; -class EncryptionHeaderKeyExistsException extends \Exception { - -} - -class EncryptionHeaderToLargeException extends \Exception { +class EncryptionHeaderKeyExistsException extends GenericEncryptionException { + /** + * @param string $key + */ + public function __construct($key) { + parent::__construct('header key "'. $key . '" already reserved by ownCloud'); + } } diff --git a/lib/private/encryption/exceptions/encryptionheadertolargeexception.php b/lib/private/encryption/exceptions/encryptionheadertolargeexception.php index cc980aa4beb..94a130d792d 100644 --- a/lib/private/encryption/exceptions/encryptionheadertolargeexception.php +++ b/lib/private/encryption/exceptions/encryptionheadertolargeexception.php @@ -22,7 +22,12 @@ namespace OC\Encryption\Exceptions; +use OCP\Encryption\Exceptions\GenericEncryptionException; class EncryptionHeaderToLargeException extends GenericEncryptionException { + public function __construct($key) { + parent::__construct('max header size exceeded'); + } + } diff --git a/lib/private/encryption/exceptions/genericencryptionexception.php b/lib/private/encryption/exceptions/genericencryptionexception.php deleted file mode 100644 index 608e5e6010a..00000000000 --- a/lib/private/encryption/exceptions/genericencryptionexception.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @since 2/25/15, 9:30 AM - * @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 - * - */ - -namespace OC\Encryption\Exceptions; - - -class GenericEncryptionException extends \Exception { - -} diff --git a/lib/private/encryption/exceptions/modulealreadyexistsexception.php b/lib/private/encryption/exceptions/modulealreadyexistsexception.php index 41fc0188e24..fa1e70a5c36 100644 --- a/lib/private/encryption/exceptions/modulealreadyexistsexception.php +++ b/lib/private/encryption/exceptions/modulealreadyexistsexception.php @@ -23,6 +23,16 @@ namespace OC\Encryption\Exceptions; -class ModuleAlreadyExistsException extends \Exception { +use OCP\Encryption\Exceptions\GenericEncryptionException; + +class ModuleAlreadyExistsException extends GenericEncryptionException { + + /** + * @param string $id + * @param string $name + */ + public function __construct($id, $name) { + parent::__construct('Id "' . $id . '" already used by encryption module "' . $name . '"'); + } } diff --git a/lib/private/encryption/exceptions/moduledoesnotexistsexception.php b/lib/private/encryption/exceptions/moduledoesnotexistsexception.php index 5507bd03dab..2c699e8dc2d 100644 --- a/lib/private/encryption/exceptions/moduledoesnotexistsexception.php +++ b/lib/private/encryption/exceptions/moduledoesnotexistsexception.php @@ -23,6 +23,8 @@ namespace OC\Encryption\Exceptions; -class ModuleDoesNotExistsException extends \Exception { +use OCP\Encryption\Exceptions\GenericEncryptionException; + +class ModuleDoesNotExistsException extends GenericEncryptionException { } diff --git a/lib/private/encryption/exceptions/publickeymissingexception.php b/lib/private/encryption/exceptions/publickeymissingexception.php deleted file mode 100644 index d5f2aae42cc..00000000000 --- a/lib/private/encryption/exceptions/publickeymissingexception.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @since 2/25/15, 9:39 AM - * @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 - * - */ - - -namespace OC\Encryption\Exceptions; - - -class PublicKeyMissingException extends GenericEncryptionException { - -} diff --git a/lib/private/encryption/exceptions/unexpectedblocksizeexception.php b/lib/private/encryption/exceptions/unexpectedblocksizeexception.php deleted file mode 100644 index 799d08e6bab..00000000000 --- a/lib/private/encryption/exceptions/unexpectedblocksizeexception.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @since 2/25/15, 9:35 AM - * @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 - * - */ - - -namespace OC\Encryption\Exceptions; - - -interface UnexpectedBlockSize { - -} diff --git a/lib/private/encryption/exceptions/unexpectedendofencryptionheaderexception.php b/lib/private/encryption/exceptions/unexpectedendofencryptionheaderexception.php deleted file mode 100644 index 04f65cf7626..00000000000 --- a/lib/private/encryption/exceptions/unexpectedendofencryptionheaderexception.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @since 2/25/15, 9:34 AM - * @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 - * - */ - - -namespace OC\Encryption\Exceptions; - - -class UnexpectedEndOfEncryptionHeaderException extends GenericEncryptionException { - -} diff --git a/lib/private/encryption/exceptions/unknowncipherexception.php b/lib/private/encryption/exceptions/unknowncipherexception.php index 5177af6106b..188f7403848 100644 --- a/lib/private/encryption/exceptions/unknowncipherexception.php +++ b/lib/private/encryption/exceptions/unknowncipherexception.php @@ -22,7 +22,8 @@ namespace OC\Encryption\Exceptions; +use OCP\Encryption\Exceptions\GenericEncryptionException; -class UnknownCipherException extends GenericEncryptionException{ +class UnknownCipherException extends GenericEncryptionException { } diff --git a/lib/private/encryption/keys/storage.php b/lib/private/encryption/keys/storage.php index 82753df1dc7..e4e3fb084f3 100644 --- a/lib/private/encryption/keys/storage.php +++ b/lib/private/encryption/keys/storage.php @@ -23,9 +23,9 @@ namespace OC\Encryption\Keys; -use OC\Encryption\Exceptions\GenericEncryptionException; use OC\Encryption\Util; use OC\Files\View; +use OCP\Encryption\Exceptions\GenericEncryptionException; class Storage implements \OCP\Encryption\Keys\IStorage { @@ -259,7 +259,7 @@ class Storage implements \OCP\Encryption\Keys\IStorage { private function getFileKeyDir($path) { if ($this->view->is_dir($path)) { - throw new GenericEncryptionException('file was expected but directory was given'); + throw new GenericEncryptionException("file was expected but directory was given: $path"); } list($owner, $filename) = $this->util->getUidAndFilename($path); diff --git a/lib/private/encryption/manager.php b/lib/private/encryption/manager.php index 77f02b0c489..f8ac174479e 100644 --- a/lib/private/encryption/manager.php +++ b/lib/private/encryption/manager.php @@ -70,8 +70,7 @@ class Manager implements \OCP\Encryption\IManager { $name = $module->getDisplayName(); if (isset($this->encryptionModules[$id])) { - $message = 'Id "' . $id . '" already used by encryption module "' . $name . '"'; - throw new Exceptions\ModuleAlreadyExistsException($message); + throw new Exceptions\ModuleAlreadyExistsException($id, $name); } $defaultEncryptionModuleId = $this->getDefaultEncryptionModuleId(); diff --git a/lib/private/encryption/util.php b/lib/private/encryption/util.php index 1183e6622bb..e2c7fa26e66 100644 --- a/lib/private/encryption/util.php +++ b/lib/private/encryption/util.php @@ -147,14 +147,14 @@ class Util { $header = self::HEADER_START . ':' . self::HEADER_ENCRYPTION_MODULE_KEY . ':' . $encryptionModule->getId() . ':'; foreach ($headerData as $key => $value) { if (in_array($key, $this->ocHeaderKeys)) { - throw new EncryptionHeaderKeyExistsException('header key "'. $key . '" already reserved by ownCloud'); + throw new EncryptionHeaderKeyExistsException($key); } $header .= $key . ':' . $value . ':'; } $header .= self::HEADER_END; if (strlen($header) > $this->getHeaderSize()) { - throw new EncryptionHeaderToLargeException('max header size exceeded'); + throw new EncryptionHeaderToLargeException(); } $paddedHeader = str_pad($header, $this->headerSize, self::HEADER_PADDING_CHAR, STR_PAD_RIGHT); diff --git a/lib/public/encryption/exceptions/genericencryptionexception.php b/lib/public/encryption/exceptions/genericencryptionexception.php new file mode 100644 index 00000000000..b7addd3b0c1 --- /dev/null +++ b/lib/public/encryption/exceptions/genericencryptionexception.php @@ -0,0 +1,34 @@ + + * @since 2/25/15, 9:30 AM + * @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 + * + */ + +namespace OCP\Encryption\Exceptions; + + +class GenericEncryptionException extends \Exception { + + public function __construct($message = "", $code = 0, \Exception $previous = null) { + if (empty($message)) { + $message = 'Unspecified encryption exception'; + } + parent::__construct($message, $code, $previous); + } + +} -- cgit v1.2.3 From a74ee674768cec92c85d313a27ea0c2de5aa29c1 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Wed, 1 Apr 2015 17:22:29 +0200 Subject: don't wrap share storages --- lib/private/encryption/manager.php | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'lib/private/encryption') diff --git a/lib/private/encryption/manager.php b/lib/private/encryption/manager.php index f8ac174479e..484e0f540b2 100644 --- a/lib/private/encryption/manager.php +++ b/lib/private/encryption/manager.php @@ -185,16 +185,19 @@ class Manager implements \OCP\Encryption\IManager { 'storage' => $storage, 'mountPoint' => $mountPoint, 'mount' => $mount]; - $manager = \OC::$server->getEncryptionManager(); - $util = new \OC\Encryption\Util( - new \OC\Files\View(), - \OC::$server->getUserManager(), - \OC::$server->getConfig()); - $user = \OC::$server->getUserSession()->getUser(); - $logger = \OC::$server->getLogger(); - $uid = $user ? $user->getUID() : null; - $fileHelper = \OC::$server->getEncryptionFilesHelper(); - return new Encryption($parameters, $manager, $util, $logger, $fileHelper, $uid); - }); + + if (!($storage instanceof \OC\Files\Storage\Shared)) { + $manager = \OC::$server->getEncryptionManager(); + $util = new \OC\Encryption\Util( + new \OC\Files\View(), \OC::$server->getUserManager(), \OC::$server->getConfig()); + $user = \OC::$server->getUserSession()->getUser(); + $logger = \OC::$server->getLogger(); + $uid = $user ? $user->getUID() : null; + $fileHelper = \OC::$server->getEncryptionFilesHelper(); + return new Encryption($parameters, $manager, $util, $logger, $fileHelper, $uid); + } else { + return $storage; + } + }, 2); } } -- cgit v1.2.3 From fac7ec3fc445ed528d84b258717e856e3638d734 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 2 Apr 2015 12:03:37 +0200 Subject: fix re-shares with encryption --- apps/files_sharing/tests/testcase.php | 2 +- lib/private/encryption/update.php | 8 ++++++-- lib/private/encryption/util.php | 6 +++--- 3 files changed, 10 insertions(+), 6 deletions(-) (limited to 'lib/private/encryption') diff --git a/apps/files_sharing/tests/testcase.php b/apps/files_sharing/tests/testcase.php index 69f68f7dfe8..b9f8658a69e 100644 --- a/apps/files_sharing/tests/testcase.php +++ b/apps/files_sharing/tests/testcase.php @@ -157,7 +157,7 @@ abstract class TestCase extends \Test\TestCase { $storage = new \ReflectionClass('\OC\Files\Storage\Shared'); $isInitialized = $storage->getProperty('isInitialized'); $isInitialized->setAccessible(true); - $isInitialized->setValue(false); + $isInitialized->setValue(array()); $isInitialized->setAccessible(false); } diff --git a/lib/private/encryption/update.php b/lib/private/encryption/update.php index e838e870502..1cfe935e584 100644 --- a/lib/private/encryption/update.php +++ b/lib/private/encryption/update.php @@ -94,7 +94,11 @@ class Update { */ private function update($fileSource) { $path = \OC\Files\Filesystem::getPath($fileSource); - $absPath = '/' . $this->uid . '/files' . $path; + $info = \OC\Files\Filesystem::getFileInfo($path); + $owner = \OC\Files\Filesystem::getOwner($path); + $view = new \OC\Files\View('/' . $owner . '/files'); + $ownerPath = $view->getPath($info->getId()); + $absPath = '/' . $owner . '/files' . $ownerPath; $mount = $this->mountManager->find($path); $mountPoint = $mount->getMountPoint(); @@ -110,7 +114,7 @@ class Update { foreach ($allFiles as $path) { $usersSharing = $this->file->getAccessList($path); - $encryptionModule->update($absPath, $this->uid, $usersSharing); + $encryptionModule->update($path, $this->uid, $usersSharing); } } diff --git a/lib/private/encryption/util.php b/lib/private/encryption/util.php index e2c7fa26e66..54d587715bf 100644 --- a/lib/private/encryption/util.php +++ b/lib/private/encryption/util.php @@ -180,11 +180,11 @@ class Util { foreach ($content as $c) { // getDirectoryContent() returns the paths relative to the mount points, so we need // to re-construct the complete path - $path = ($mountPoint !== '') ? $mountPoint . '/' . $c['path'] : $c['path']; + $path = ($mountPoint !== '') ? $mountPoint . '/' . $c->getPath() : $c->getPath(); if ($c['type'] === 'dir') { - $dirList[] = $path; + $dirList[] = \OC\Files\Filesystem::normalizePath($path); } else { - $result[] = $path; + $result[] = \OC\Files\Filesystem::normalizePath($path); } } -- cgit v1.2.3 From 104d11ec4c5d359c54985e01c171ba1845537632 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Thu, 2 Apr 2015 14:44:58 +0200 Subject: Fixing encryption storage wrapper tests --- .../encryptionheadertolargeexception.php | 2 +- lib/private/files/storage/wrapper/encryption.php | 69 +++++++++++++++++++++- tests/lib/files/storage/storage.php | 2 +- tests/lib/files/storage/wrapper/encryption.php | 69 ++++++++++++++++++++-- 4 files changed, 133 insertions(+), 9 deletions(-) (limited to 'lib/private/encryption') diff --git a/lib/private/encryption/exceptions/encryptionheadertolargeexception.php b/lib/private/encryption/exceptions/encryptionheadertolargeexception.php index 94a130d792d..cdb5f940800 100644 --- a/lib/private/encryption/exceptions/encryptionheadertolargeexception.php +++ b/lib/private/encryption/exceptions/encryptionheadertolargeexception.php @@ -26,7 +26,7 @@ use OCP\Encryption\Exceptions\GenericEncryptionException; class EncryptionHeaderToLargeException extends GenericEncryptionException { - public function __construct($key) { + public function __construct() { parent::__construct('max header size exceeded'); } diff --git a/lib/private/files/storage/wrapper/encryption.php b/lib/private/files/storage/wrapper/encryption.php index 7cc488aa914..58d963613aa 100644 --- a/lib/private/files/storage/wrapper/encryption.php +++ b/lib/private/files/storage/wrapper/encryption.php @@ -24,9 +24,12 @@ namespace OC\Files\Storage\Wrapper; use OC\Encryption\Exceptions\ModuleDoesNotExistsException; +use OC\Files\Storage\LocalTempFileTrait; class Encryption extends Wrapper { + use LocalTempFileTrait; + /** @var string */ private $mountPoint; @@ -156,8 +159,8 @@ class Encryption extends Wrapper { $encryptionModule = $this->getEncryptionModule($path); if ($encryptionModule) { - $keyStorage = \OC::$server->getEncryptionKeyStorage($encryptionModule->getId()); - $keyStorage->deleteAllFileKeys($this->getFullPath($path)); + $keyStorage = $this->getKeyStorage($encryptionModule->getId()); + $keyStorage->deleteAllFileKeys($this->getFullPath($path)); } return $this->storage->unlink($path); @@ -184,7 +187,7 @@ class Encryption extends Wrapper { list(, $target) = $this->util->getUidAndFilename($fullPath2); $encryptionModule = $this->getEncryptionModule($path2); if ($encryptionModule) { - $keyStorage = \OC::$server->getEncryptionKeyStorage($encryptionModule->getId()); + $keyStorage = $this->getKeyStorage($encryptionModule->getId()); $keyStorage->renameKeys($source, $target, $owner, $systemWide); } } @@ -269,6 +272,57 @@ class Encryption extends Wrapper { } } + /** + * get the path to a local version of the file. + * The local version of the file can be temporary and doesn't have to be persistent across requests + * + * @param string $path + * @return string + */ + public function getLocalFile($path) { + return $this->getCachedFile($path); + } + + /** + * Returns the wrapped storage's value for isLocal() + * + * @return bool wrapped storage's isLocal() value + */ + public function isLocal() { + return false; + } + + /** + * see http://php.net/manual/en/function.stat.php + * only the following keys are required in the result: size and mtime + * + * @param string $path + * @return array + */ + public function stat($path) { + $stat = $this->storage->stat($path); + $fileSize = $this->filesize($path); + $stat['size'] = $fileSize; + $stat[7] = $fileSize; + return $stat; + } + + /** + * see http://php.net/manual/en/function.hash.php + * + * @param string $type + * @param string $path + * @param bool $raw + * @return string + */ + public function hash($type, $path, $raw = false) { + $fh = $this->fopen($path, 'rb'); + $ctx = hash_init($type); + hash_update_stream($ctx, $fh); + fclose($fh); + return hash_final($ctx, $raw); + } + /** * return full path, including mount point * @@ -322,4 +376,13 @@ class Encryption extends Wrapper { $this->unencryptedSize[$path] = $unencryptedSize; } + /** + * @param string $encryptionModule + * @return \OCP\Encryption\Keys\IStorage + */ + protected function getKeyStorage($encryptionModuleId) { + $keyStorage = \OC::$server->getEncryptionKeyStorage($encryptionModuleId); + return $keyStorage; + } + } diff --git a/tests/lib/files/storage/storage.php b/tests/lib/files/storage/storage.php index ad7522f1ea8..938fecb5bf3 100644 --- a/tests/lib/files/storage/storage.php +++ b/tests/lib/files/storage/storage.php @@ -253,7 +253,7 @@ abstract class Storage extends \Test\TestCase { $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile)); $localFile = $this->instance->getLocalFile('/lorem.txt'); $this->assertTrue(file_exists($localFile)); - $this->assertEquals(file_get_contents($localFile), file_get_contents($textFile)); + $this->assertEquals(file_get_contents($textFile), file_get_contents($localFile)); $this->instance->mkdir('/folder'); $this->instance->file_put_contents('/folder/lorem.txt', file_get_contents($textFile)); diff --git a/tests/lib/files/storage/wrapper/encryption.php b/tests/lib/files/storage/wrapper/encryption.php index eea6a53e043..9f681a34298 100644 --- a/tests/lib/files/storage/wrapper/encryption.php +++ b/tests/lib/files/storage/wrapper/encryption.php @@ -16,6 +16,7 @@ class Encryption extends \Test\Files\Storage\Storage { parent::setUp(); + $mockModule = $this->buildMockModule(); $encryptionManager = $this->getMockBuilder('\OC\Encryption\Manager') ->disableOriginalConstructor() ->setMethods(['getDefaultEncryptionModule', 'getEncryptionModule']) @@ -25,22 +26,57 @@ class Encryption extends \Test\Files\Storage\Storage { ->getMock(); $encryptionManager->expects($this->any()) ->method('getDefaultEncryptionModule') - ->willReturn(new DummyModule()); + ->willReturn($mockModule); + $encryptionManager->expects($this->any()) + ->method('getEncryptionModule') + ->willReturn($mockModule); - $util = new \OC\Encryption\Util(new View(), new \OC\User\Manager(), $config); + $util = $this->getMock('\OC\Encryption\Util', ['getUidAndFilename'], [new View(), new \OC\User\Manager(), $config]); + $util->expects($this->any()) + ->method('getUidAndFilename') + ->willReturnCallback(function ($path) { + return ['user1', $path]; + }); + $file = $this->getMockBuilder('\OC\Encryption\File') + ->disableOriginalConstructor() + ->getMock(); $logger = $this->getMock('\OC\Log'); $this->sourceStorage = new \OC\Files\Storage\Temporary(array()); - $this->instance = new \OC\Files\Storage\Wrapper\Encryption([ + $keyStore = $this->getMockBuilder('\OC\Encryption\Keys\Storage') + ->disableOriginalConstructor()->getMock(); + $this->instance = new EncryptionWrapper([ 'storage' => $this->sourceStorage, 'root' => 'foo', 'mountPoint' => '/' ], - $encryptionManager, $util, $logger + $encryptionManager, $util, $logger, $file, null, $keyStore ); } + /** + * @return \PHPUnit_Framework_MockObject_MockObject + */ + protected function buildMockModule() { + $encryptionModule = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule') + ->disableOriginalConstructor() + ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'calculateUnencryptedSize', 'getUnencryptedBlockSize']) + ->getMock(); + + $encryptionModule->expects($this->any())->method('getId')->willReturn('UNIT_TEST_MODULE'); + $encryptionModule->expects($this->any())->method('getDisplayName')->willReturn('Unit test module'); + $encryptionModule->expects($this->any())->method('begin')->willReturn([]); + $encryptionModule->expects($this->any())->method('end')->willReturn(''); + $encryptionModule->expects($this->any())->method('encrypt')->willReturnArgument(0); + $encryptionModule->expects($this->any())->method('decrypt')->willReturnArgument(0); + $encryptionModule->expects($this->any())->method('update')->willReturn(true); + $encryptionModule->expects($this->any())->method('shouldEncrypt')->willReturn(true); + $encryptionModule->expects($this->any())->method('calculateUnencryptedSize')->willReturn(42); + $encryptionModule->expects($this->any())->method('getUnencryptedBlockSize')->willReturn(6126); + return $encryptionModule; + } + // public function testMkDirRooted() { // $this->instance->mkdir('bar'); // $this->assertTrue($this->sourceStorage->is_dir('foo/bar')); @@ -51,3 +87,28 @@ class Encryption extends \Test\Files\Storage\Storage { // $this->assertEquals('asd', $this->sourceStorage->file_get_contents('foo/bar')); // } } + +// +// FIXME: this is too bad and needs adjustment +// +class EncryptionWrapper extends \OC\Files\Storage\Wrapper\Encryption { + private $keyStore; + + public function __construct( + $parameters, + \OC\Encryption\Manager $encryptionManager = null, + \OC\Encryption\Util $util = null, + \OC\Log $logger = null, + \OC\Encryption\File $fileHelper = null, + $uid = null, + $keyStore = null + ) { + $this->keyStore = $keyStore; + parent::__construct($parameters, $encryptionManager, $util, $logger, $fileHelper, $uid); + } + + protected function getKeyStorage($encryptionModuleId) { + return $this->keyStore; + } + +} -- cgit v1.2.3 From fe74a0cb4f319ac9dccfce8c296365c3535ef84e Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 2 Apr 2015 16:25:01 +0200 Subject: implement webdav copy --- lib/private/encryption/keys/storage.php | 35 ++++++++++- lib/private/files/storage/wrapper/encryption.php | 28 ++++++--- lib/public/encryption/keys/istorage.php | 12 +++- tests/lib/encryption/keys/storage.php | 76 ++++++++++++++++++++++++ 4 files changed, 138 insertions(+), 13 deletions(-) (limited to 'lib/private/encryption') diff --git a/lib/private/encryption/keys/storage.php b/lib/private/encryption/keys/storage.php index e4e3fb084f3..7d0612ae30e 100644 --- a/lib/private/encryption/keys/storage.php +++ b/lib/private/encryption/keys/storage.php @@ -283,7 +283,12 @@ class Storage implements \OCP\Encryption\Keys\IStorage { * @param string $owner * @param bool $systemWide */ - public function renameKeys($source, $target, $owner, $systemWide) { + public function renameKeys($source, $target) { + + list($owner, $source) = $this->util->getUidAndFilename($source); + list(, $target) = $this->util->getUidAndFilename($target); + $systemWide = $this->util->isSystemWideMountPoint($target); + if ($systemWide) { $sourcePath = $this->keys_base_dir . $source . '/'; $targetPath = $this->keys_base_dir . $target . '/'; @@ -298,6 +303,34 @@ class Storage implements \OCP\Encryption\Keys\IStorage { } } + /** + * copy keys if a file was renamed + * + * @param string $source + * @param string $target + * @param string $owner + * @param bool $systemWide + */ + public function copyKeys($source, $target) { + + list($owner, $source) = $this->util->getUidAndFilename($source); + list(, $target) = $this->util->getUidAndFilename($target); + $systemWide = $this->util->isSystemWideMountPoint($target); + + if ($systemWide) { + $sourcePath = $this->keys_base_dir . $source . '/'; + $targetPath = $this->keys_base_dir . $target . '/'; + } else { + $sourcePath = '/' . $owner . $this->keys_base_dir . $source . '/'; + $targetPath = '/' . $owner . $this->keys_base_dir . $target . '/'; + } + + if ($this->view->file_exists($sourcePath)) { + $this->keySetPreparation(dirname($targetPath)); + $this->view->copy($sourcePath, $targetPath); + } + } + /** * Make preparations to filesystem for saving a keyfile * diff --git a/lib/private/files/storage/wrapper/encryption.php b/lib/private/files/storage/wrapper/encryption.php index 3ea3b987d4c..2e5bbfd97be 100644 --- a/lib/private/files/storage/wrapper/encryption.php +++ b/lib/private/files/storage/wrapper/encryption.php @@ -173,17 +173,14 @@ class Encryption extends Wrapper { return $this->storage->rename($path1, $path2); } - $fullPath1 = $this->getFullPath($path1); - list($owner, $source) = $this->util->getUidAndFilename($fullPath1); + $source = $this->getFullPath($path1); $result = $this->storage->rename($path1, $path2); if ($result) { - $fullPath2 = $this->getFullPath($path2); - $systemWide = $this->util->isSystemWideMountPoint($this->mountPoint); - list(, $target) = $this->util->getUidAndFilename($fullPath2); + $target = $this->getFullPath($path2); $encryptionModule = $this->getEncryptionModule($path2); if ($encryptionModule) { $keyStorage = $this->getKeyStorage($encryptionModule->getId()); - $keyStorage->renameKeys($source, $target, $owner, $systemWide); + $keyStorage->renameKeys($source, $target); } } @@ -198,9 +195,22 @@ class Encryption extends Wrapper { * @return bool */ public function copy($path1, $path2) { - // todo copy encryption keys, get users with access to the file and reencrypt - // or is this to encryption module specific? Then we can hand this over - return $this->storage->copy($path1, $path2); + if ($this->util->isExcluded($path1)) { + return $this->storage->rename($path1, $path2); + } + + $source = $this->getFullPath($path1); + $result = $this->storage->copy($path1, $path2); + if ($result) { + $target = $this->getFullPath($path2); + $encryptionModule = $this->getEncryptionModule($path2); + if ($encryptionModule) { + $keyStorage = $this->getKeyStorage($encryptionModule->getId()); + $keyStorage->copyKeys($source, $target); + } + } + + return $result; } /** diff --git a/lib/public/encryption/keys/istorage.php b/lib/public/encryption/keys/istorage.php index 0a3ed44d378..2d1672face5 100644 --- a/lib/public/encryption/keys/istorage.php +++ b/lib/public/encryption/keys/istorage.php @@ -122,14 +122,20 @@ interface IStorage { */ public function deleteSystemUserKey($keyId); + /** + * copy keys if a file was renamed + * + * @param string $source + * @param string $target + */ + public function renameKeys($source, $target); + /** * move keys if a file was renamed * * @param string $source * @param string $target - * @param string $owner - * @param bool $systemWide */ - public function renameKeys($source, $target, $owner, $systemWide); + public function copyKeys($source, $target); } diff --git a/tests/lib/encryption/keys/storage.php b/tests/lib/encryption/keys/storage.php index c2e5bdbd3d1..be32f0e44a1 100644 --- a/tests/lib/encryption/keys/storage.php +++ b/tests/lib/encryption/keys/storage.php @@ -277,4 +277,80 @@ class StorageTest extends TestCase { ); } + /** + * @dataProvider dataProviderCopyRename + */ + public function testRenameKeys($source, $target, $systemWideMount, $expectedSource, $expectedTarget) { + $this->view->expects($this->any()) + ->method('file_exists') + ->willReturn(true); + $this->view->expects($this->any()) + ->method('is_dir') + ->willReturn(true); + $this->view->expects($this->once()) + ->method('rename') + ->with( + $this->equalTo($expectedSource), + $this->equalTo($expectedTarget)) + ->willReturn(true); + $this->util->expects($this->any()) + ->method('getUidAndFilename') + ->will($this->returnCallback(array($this, 'getUidAndFilenameCallback'))); + $this->util->expects($this->any()) + ->method('isSystemWideMountPoint') + ->willReturn($systemWideMount); + + $storage = new Storage('encModule', $this->view, $this->util); + $storage->renameKeys($source, $target); + } + + /** + * @dataProvider dataProviderCopyRename + */ + public function testCopyKeys($source, $target, $systemWideMount, $expectedSource, $expectedTarget) { + $this->view->expects($this->any()) + ->method('file_exists') + ->willReturn(true); + $this->view->expects($this->any()) + ->method('is_dir') + ->willReturn(true); + $this->view->expects($this->once()) + ->method('copy') + ->with( + $this->equalTo($expectedSource), + $this->equalTo($expectedTarget)) + ->willReturn(true); + $this->util->expects($this->any()) + ->method('getUidAndFilename') + ->will($this->returnCallback(array($this, 'getUidAndFilenameCallback'))); + $this->util->expects($this->any()) + ->method('isSystemWideMountPoint') + ->willReturn($systemWideMount); + + $storage = new Storage('encModule', $this->view, $this->util); + $storage->copyKeys($source, $target); + } + + public function getUidAndFilenameCallback() { + $args = func_get_args(); + + $path = $args[0]; + $parts = explode('/', $path); + + return array($parts[1], '/' . implode('/', array_slice($parts, 2))); + } + + public function dataProviderCopyRename() { + return array( + array('/user1/files/foo.txt', '/user1/files/bar.txt', false, + '/user1/files_encryption/keys/files/foo.txt/', '/user1/files_encryption/keys/files/bar.txt/'), + array('/user1/files/foo/foo.txt', '/user1/files/bar.txt', false, + '/user1/files_encryption/keys/files/foo/foo.txt/', '/user1/files_encryption/keys/files/bar.txt/'), + array('/user1/files/foo.txt', '/user1/files/foo/bar.txt', false, + '/user1/files_encryption/keys/files/foo.txt/', '/user1/files_encryption/keys/files/foo/bar.txt/'), + array('/user1/files/foo.txt', '/user1/files/foo/bar.txt', true, + '/files_encryption/keys/files/foo.txt/', '/files_encryption/keys/files/foo/bar.txt/'), + ); + } + } -- cgit v1.2.3 From 3d7404fe68474e72a520cb804d7c493e00215752 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 2 Apr 2015 16:42:28 +0200 Subject: add unit tests to the keystorage --- lib/private/encryption/keys/storage.php | 2 +- tests/lib/encryption/keys/storage.php | 85 +++++++++++++++++---------------- 2 files changed, 46 insertions(+), 41 deletions(-) (limited to 'lib/private/encryption') diff --git a/lib/private/encryption/keys/storage.php b/lib/private/encryption/keys/storage.php index 7d0612ae30e..42610bd0b41 100644 --- a/lib/private/encryption/keys/storage.php +++ b/lib/private/encryption/keys/storage.php @@ -339,7 +339,7 @@ class Storage implements \OCP\Encryption\Keys\IStorage { protected function keySetPreparation($path) { // If the file resides within a subdirectory, create it if (!$this->view->file_exists($path)) { - $sub_dirs = explode('/', $path); + $sub_dirs = explode('/', ltrim($path, '/')); $dir = ''; foreach ($sub_dirs as $sub_dir) { $dir .= '/' . $sub_dir; diff --git a/tests/lib/encryption/keys/storage.php b/tests/lib/encryption/keys/storage.php index be32f0e44a1..8ab46987f8c 100644 --- a/tests/lib/encryption/keys/storage.php +++ b/tests/lib/encryption/keys/storage.php @@ -28,6 +28,9 @@ use Test\TestCase; class StorageTest extends TestCase { + /** @var Storage */ + protected $storage; + /** @var \PHPUnit_Framework_MockObject_MockObject */ protected $util; @@ -45,6 +48,8 @@ class StorageTest extends TestCase { ->disableOriginalConstructor() ->getMock(); + $this->storage = new Storage('encModule', $this->view, $this->util); + } public function testSetFileKey() { @@ -63,10 +68,8 @@ class StorageTest extends TestCase { $this->equalTo('key')) ->willReturn(strlen('key')); - $storage = new Storage('encModule', $this->view, $this->util); - $this->assertTrue( - $storage->setFileKey('user1/files/foo.txt', 'fileKey', 'key') + $this->storage->setFileKey('user1/files/foo.txt', 'fileKey', 'key') ); } @@ -89,10 +92,8 @@ class StorageTest extends TestCase { ->with($this->equalTo('/user1/files_encryption/keys/files/foo.txt/encModule/fileKey')) ->willReturn(true); - $storage = new Storage('encModule', $this->view, $this->util); - $this->assertSame('key', - $storage->getFileKey('user1/files/foo.txt', 'fileKey') + $this->storage->getFileKey('user1/files/foo.txt', 'fileKey') ); } @@ -112,10 +113,8 @@ class StorageTest extends TestCase { $this->equalTo('key')) ->willReturn(strlen('key')); - $storage = new Storage('encModule', $this->view, $this->util); - $this->assertTrue( - $storage->setFileKey('user1/files/foo.txt', 'fileKey', 'key') + $this->storage->setFileKey('user1/files/foo.txt', 'fileKey', 'key') ); } @@ -138,10 +137,8 @@ class StorageTest extends TestCase { ->with($this->equalTo('/files_encryption/keys/files/foo.txt/encModule/fileKey')) ->willReturn(true); - $storage = new Storage('encModule', $this->view, $this->util); - $this->assertSame('key', - $storage->getFileKey('user1/files/foo.txt', 'fileKey') + $this->storage->getFileKey('user1/files/foo.txt', 'fileKey') ); } @@ -152,10 +149,8 @@ class StorageTest extends TestCase { $this->equalTo('key')) ->willReturn(strlen('key')); - $storage = new Storage('encModule', $this->view, $this->util); - $this->assertTrue( - $storage->setSystemUserKey('shareKey_56884', 'key') + $this->storage->setSystemUserKey('shareKey_56884', 'key') ); } @@ -166,10 +161,8 @@ class StorageTest extends TestCase { $this->equalTo('key')) ->willReturn(strlen('key')); - $storage = new Storage('encModule', $this->view, $this->util); - $this->assertTrue( - $storage->setUserKey('user1', 'publicKey', 'key') + $this->storage->setUserKey('user1', 'publicKey', 'key') ); } @@ -183,10 +176,8 @@ class StorageTest extends TestCase { ->with($this->equalTo('/files_encryption/encModule/shareKey_56884')) ->willReturn(true); - $storage = new Storage('encModule', $this->view, $this->util); - $this->assertSame('key', - $storage->getSystemUserKey('shareKey_56884') + $this->storage->getSystemUserKey('shareKey_56884') ); } @@ -200,10 +191,8 @@ class StorageTest extends TestCase { ->with($this->equalTo('/user1/files_encryption/encModule/user1.publicKey')) ->willReturn(true); - $storage = new Storage('encModule', $this->view, $this->util); - $this->assertSame('key', - $storage->getUserKey('user1', 'publicKey') + $this->storage->getUserKey('user1', 'publicKey') ); } @@ -213,10 +202,8 @@ class StorageTest extends TestCase { ->with($this->equalTo('/user1/files_encryption/encModule/user1.publicKey')) ->willReturn(true); - $storage = new Storage('encModule', $this->view, $this->util); - $this->assertTrue( - $storage->deleteUserKey('user1', 'publicKey') + $this->storage->deleteUserKey('user1', 'publicKey') ); } @@ -226,10 +213,8 @@ class StorageTest extends TestCase { ->with($this->equalTo('/files_encryption/encModule/shareKey_56884')) ->willReturn(true); - $storage = new Storage('encModule', $this->view, $this->util); - $this->assertTrue( - $storage->deleteSystemUserKey('shareKey_56884') + $this->storage->deleteSystemUserKey('shareKey_56884') ); } @@ -248,10 +233,8 @@ class StorageTest extends TestCase { ->with($this->equalTo('/files_encryption/keys/files/foo.txt/encModule/fileKey')) ->willReturn(true); - $storage = new Storage('encModule', $this->view, $this->util); - $this->assertTrue( - $storage->deleteFileKey('user1/files/foo.txt', 'fileKey') + $this->storage->deleteFileKey('user1/files/foo.txt', 'fileKey') ); } @@ -270,10 +253,8 @@ class StorageTest extends TestCase { ->with($this->equalTo('/user1/files_encryption/keys/files/foo.txt/encModule/fileKey')) ->willReturn(true); - $storage = new Storage('encModule', $this->view, $this->util); - $this->assertTrue( - $storage->deleteFileKey('user1/files/foo.txt', 'fileKey') + $this->storage->deleteFileKey('user1/files/foo.txt', 'fileKey') ); } @@ -300,8 +281,7 @@ class StorageTest extends TestCase { ->method('isSystemWideMountPoint') ->willReturn($systemWideMount); - $storage = new Storage('encModule', $this->view, $this->util); - $storage->renameKeys($source, $target); + $this->storage->renameKeys($source, $target); } /** @@ -327,8 +307,7 @@ class StorageTest extends TestCase { ->method('isSystemWideMountPoint') ->willReturn($systemWideMount); - $storage = new Storage('encModule', $this->view, $this->util); - $storage->copyKeys($source, $target); + $this->storage->copyKeys($source, $target); } public function getUidAndFilenameCallback() { @@ -353,4 +332,30 @@ class StorageTest extends TestCase { ); } + public function testKeySetPreparation() { + $this->view->expects($this->any()) + ->method('file_exists') + ->willReturn(false); + $this->view->expects($this->any()) + ->method('is_dir') + ->willReturn(false); + $this->view->expects($this->any()) + ->method('mkdir') + ->will($this->returnCallback(array($this, 'mkdirCallback'))); + + $this->mkdirStack = array( + '/user1/files_encryption/keys/foo', + '/user1/files_encryption/keys', + '/user1/files_encryption', + '/user1'); + + \Test_Helper::invokePrivate($this->storage, 'keySetPreparation', array('/user1/files_encryption/keys/foo')); + } + + public function mkdirCallback() { + $args = func_get_args(); + $expected = array_pop($this->mkdirStack); + $this->assertSame($expected, $args[0]); + } + } -- cgit v1.2.3 From 111fbabfb4772310cfae7037dfc3b71dcb881cc5 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Thu, 2 Apr 2015 17:53:40 +0200 Subject: PHPDoc cleanup - clean code \o/ --- apps/encryption/hooks/userhooks.php | 2 -- apps/encryption/lib/crypto/crypt.php | 37 ++++++++++++------------ lib/private/encryption/util.php | 2 +- lib/private/files/storage/wrapper/encryption.php | 2 +- lib/private/hook.php | 29 ++++++++++--------- lib/public/util.php | 13 +++++---- 6 files changed, 42 insertions(+), 43 deletions(-) (limited to 'lib/private/encryption') diff --git a/apps/encryption/hooks/userhooks.php b/apps/encryption/hooks/userhooks.php index 742c7d7580b..1ec0950d941 100644 --- a/apps/encryption/hooks/userhooks.php +++ b/apps/encryption/hooks/userhooks.php @@ -205,8 +205,6 @@ class UserHooks implements IHook { * Change a user's encryption passphrase * * @param array $params keys: uid, password - * @param IUserSession $user - * @param Util $util * @return bool */ public function setPassphrase($params) { diff --git a/apps/encryption/lib/crypto/crypt.php b/apps/encryption/lib/crypto/crypt.php index 80878b3ddb2..c0b737a3daa 100644 --- a/apps/encryption/lib/crypto/crypt.php +++ b/apps/encryption/lib/crypto/crypt.php @@ -34,11 +34,10 @@ use OCP\IUserSession; class Crypt { - const BLOCKSIZE = 8192; const DEFAULT_CIPHER = 'AES-256-CFB'; - const HEADERSTART = 'HBEGIN'; - const HEADEREND = 'HEND'; + const HEADER_START = 'HBEGIN'; + const HEADER_END = 'HEND'; /** * @var ILogger */ @@ -64,7 +63,7 @@ class Crypt { } /** - * + * @return array|bool */ public function createKeyPair() { @@ -121,8 +120,8 @@ class Crypt { } /** - * @param $plainContent - * @param $passPhrase + * @param string $plainContent + * @param string $passPhrase * @return bool|string * @throws GenericEncryptionException */ @@ -148,8 +147,8 @@ class Crypt { } /** - * @param $plainContent - * @param $iv + * @param string $plainContent + * @param string $iv * @param string $passPhrase * @param string $cipher * @return string @@ -187,8 +186,8 @@ class Crypt { } /** - * @param $encryptedContent - * @param $iv + * @param string $encryptedContent + * @param string $iv * @return string */ private function concatIV($encryptedContent, $iv) { @@ -204,20 +203,20 @@ class Crypt { } /** - * @param $recoveryKey - * @param $password + * @param string $recoveryKey + * @param string $password * @return bool|string */ public function decryptPrivateKey($recoveryKey, $password) { $header = $this->parseHeader($recoveryKey); - $cipher = $this->getCipher($header); + $cipher = $this->getCipher(); // If we found a header we need to remove it from the key we want to decrypt if (!empty($header)) { $recoveryKey = substr($recoveryKey, strpos($recoveryKey, - self::HEADEREND) + strlen(self::HEADERSTART)); + self::HEADER_END) + strlen(self::HEADER_START)); } $plainKey = $this->symmetricDecryptFileContent($recoveryKey, @@ -318,17 +317,17 @@ class Crypt { private function parseHeader($data) { $result = []; - if (substr($data, 0, strlen(self::HEADERSTART)) === self::HEADERSTART) { - $endAt = strpos($data, self::HEADEREND); - $header = substr($data, 0, $endAt + strlen(self::HEADEREND)); + if (substr($data, 0, strlen(self::HEADER_START)) === self::HEADER_START) { + $endAt = strpos($data, self::HEADER_END); + $header = substr($data, 0, $endAt + strlen(self::HEADER_END)); // +1 not to start with an ':' which would result in empty element at the beginning $exploded = explode(':', - substr($header, strlen(self::HEADERSTART) + 1)); + substr($header, strlen(self::HEADER_START) + 1)); $element = array_shift($exploded); - while ($element != self::HEADEREND) { + while ($element != self::HEADER_END) { $result[$element] = array_shift($exploded); $element = array_shift($exploded); } diff --git a/lib/private/encryption/util.php b/lib/private/encryption/util.php index 54d587715bf..6312d8813e3 100644 --- a/lib/private/encryption/util.php +++ b/lib/private/encryption/util.php @@ -57,7 +57,7 @@ class Util { /** @var array */ protected $ocHeaderKeys; - /** @var Manager */ + /** @var \OC\User\Manager */ protected $userManager; /** @var IConfig */ diff --git a/lib/private/files/storage/wrapper/encryption.php b/lib/private/files/storage/wrapper/encryption.php index 946e7bfbe40..bc0b5c87adc 100644 --- a/lib/private/files/storage/wrapper/encryption.php +++ b/lib/private/files/storage/wrapper/encryption.php @@ -394,7 +394,7 @@ class Encryption extends Wrapper { } /** - * @param string $encryptionModule + * @param string $encryptionModuleId * @return \OCP\Encryption\Keys\IStorage */ protected function getKeyStorage($encryptionModuleId) { diff --git a/lib/private/hook.php b/lib/private/hook.php index 824bb725077..c4ea1999b09 100644 --- a/lib/private/hook.php +++ b/lib/private/hook.php @@ -32,38 +32,39 @@ class OC_Hook{ /** * connects a function to a hook - * @param string $signalclass class name of emitter - * @param string $signalname name of signal - * @param string $slotclass class name of slot - * @param string $slotname name of slot + * + * @param string $signalClass class name of emitter + * @param string $signalName name of signal + * @param string|object $slotClass class name of slot + * @param string $slotName name of slot * @return bool * * This function makes it very easy to connect to use hooks. * * TODO: write example */ - static public function connect( $signalclass, $signalname, $slotclass, $slotname ) { + static public function connect($signalClass, $signalName, $slotClass, $slotName ) { // If we're trying to connect to an emitting class that isn't // yet registered, register it - if( !array_key_exists( $signalclass, self::$registered )) { - self::$registered[$signalclass] = array(); + if( !array_key_exists($signalClass, self::$registered )) { + self::$registered[$signalClass] = array(); } // If we're trying to connect to an emitting method that isn't // yet registered, register it with the emitting class - if( !array_key_exists( $signalname, self::$registered[$signalclass] )) { - self::$registered[$signalclass][$signalname] = array(); + if( !array_key_exists( $signalName, self::$registered[$signalClass] )) { + self::$registered[$signalClass][$signalName] = array(); } // dont connect hooks twice - foreach (self::$registered[$signalclass][$signalname] as $hook) { - if ($hook['class'] === $slotclass and $hook['name'] === $slotname) { + foreach (self::$registered[$signalClass][$signalName] as $hook) { + if ($hook['class'] === $slotClass and $hook['name'] === $slotName) { return false; } } // Connect the hook handler to the requested emitter - self::$registered[$signalclass][$signalname][] = array( - "class" => $slotclass, - "name" => $slotname + self::$registered[$signalClass][$signalName][] = array( + "class" => $slotClass, + "name" => $slotName ); // No chance for failure ;-) diff --git a/lib/public/util.php b/lib/public/util.php index 37cb1b54485..721bcaadb62 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -394,18 +394,19 @@ class Util { /** * connects a function to a hook - * @param string $signalclass class name of emitter - * @param string $signalname name of signal - * @param string $slotclass class name of slot - * @param string $slotname name of slot + * + * @param string $signalClass class name of emitter + * @param string $signalName name of signal + * @param string|object $slotClass class name of slot + * @param string $slotName name of slot * @return bool * * This function makes it very easy to connect to use hooks. * * TODO: write example */ - static public function connectHook( $signalclass, $signalname, $slotclass, $slotname ) { - return(\OC_Hook::connect( $signalclass, $signalname, $slotclass, $slotname )); + static public function connectHook($signalClass, $signalName, $slotClass, $slotName ) { + return(\OC_Hook::connect($signalClass, $signalName, $slotClass, $slotName )); } /** -- cgit v1.2.3