diff options
author | Clark Tomlinson <fallen013@gmail.com> | 2015-03-24 17:29:10 -0400 |
---|---|---|
committer | Thomas Müller <thomas.mueller@tmit.eu> | 2015-04-07 13:30:27 +0200 |
commit | 0c2f9ca849ef41232511cf576cc9a9de2caa43f0 (patch) | |
tree | a75194b573985da4a68684cb5a74c9891db34696 /apps/files_encryption | |
parent | 506222567e71fc0d77fa77ee7805c93fa7655b6c (diff) | |
download | nextcloud-server-0c2f9ca849ef41232511cf576cc9a9de2caa43f0.tar.gz nextcloud-server-0c2f9ca849ef41232511cf576cc9a9de2caa43f0.zip |
Updating keystorage movement and fixing hooks
Diffstat (limited to 'apps/files_encryption')
-rw-r--r-- | apps/files_encryption/lib/hooks.php | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/apps/files_encryption/lib/hooks.php b/apps/files_encryption/lib/hooks.php index 536e512bdb2..4a29ffaaedf 100644 --- a/apps/files_encryption/lib/hooks.php +++ b/apps/files_encryption/lib/hooks.php @@ -34,8 +34,234 @@ 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. */ |