diff options
author | Clark Tomlinson <fallen013@gmail.com> | 2015-02-24 13:05:19 -0500 |
---|---|---|
committer | Thomas Müller <thomas.mueller@tmit.eu> | 2015-04-07 13:30:27 +0200 |
commit | 39733c8da1c12cc79b7d650edf2ea1074330ee5f (patch) | |
tree | 9d072f0ebd7c0a185c5d6afeb345b5d0ae55295e /apps/encryption/hooks | |
parent | 63e7fe608a5f507c5d2b417c45cf26589d091ebc (diff) | |
download | nextcloud-server-39733c8da1c12cc79b7d650edf2ea1074330ee5f.tar.gz nextcloud-server-39733c8da1c12cc79b7d650edf2ea1074330ee5f.zip |
Initial commit
Diffstat (limited to 'apps/encryption/hooks')
-rw-r--r-- | apps/encryption/hooks/apphooks.php | 37 | ||||
-rw-r--r-- | apps/encryption/hooks/contracts/ihook.php | 32 | ||||
-rw-r--r-- | apps/encryption/hooks/filesystemhooks.php | 46 | ||||
-rw-r--r-- | apps/encryption/hooks/sharehooks.php | 40 | ||||
-rw-r--r-- | apps/encryption/hooks/userhooks.php | 304 |
5 files changed, 459 insertions, 0 deletions
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 @@ +<?php +/** + * @author Clark Tomlinson <clark@owncloud.com> + * @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 <http://www.gnu.org/licenses/> + * + */ + +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 @@ +<?php +/** + * @author Clark Tomlinson <clark@owncloud.com> + * @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 <http://www.gnu.org/licenses/> + * + */ + +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 @@ +<?php +/** + * @author Clark Tomlinson <clark@owncloud.com> + * @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 <http://www.gnu.org/licenses/> + * + */ + +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 @@ +<?php +/** + * @author Clark Tomlinson <clark@owncloud.com> + * @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 <http://www.gnu.org/licenses/> + * + */ + +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 @@ +<?php +/** + * @author Clark Tomlinson <clark@owncloud.com> + * @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 <http://www.gnu.org/licenses/> + * + */ + +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); + } +} |