summaryrefslogtreecommitdiffstats
path: root/apps/encryption/hooks
diff options
context:
space:
mode:
authorClark Tomlinson <fallen013@gmail.com>2015-02-24 13:05:19 -0500
committerThomas Müller <thomas.mueller@tmit.eu>2015-04-07 13:30:27 +0200
commit39733c8da1c12cc79b7d650edf2ea1074330ee5f (patch)
tree9d072f0ebd7c0a185c5d6afeb345b5d0ae55295e /apps/encryption/hooks
parent63e7fe608a5f507c5d2b417c45cf26589d091ebc (diff)
downloadnextcloud-server-39733c8da1c12cc79b7d650edf2ea1074330ee5f.tar.gz
nextcloud-server-39733c8da1c12cc79b7d650edf2ea1074330ee5f.zip
Initial commit
Diffstat (limited to 'apps/encryption/hooks')
-rw-r--r--apps/encryption/hooks/apphooks.php37
-rw-r--r--apps/encryption/hooks/contracts/ihook.php32
-rw-r--r--apps/encryption/hooks/filesystemhooks.php46
-rw-r--r--apps/encryption/hooks/sharehooks.php40
-rw-r--r--apps/encryption/hooks/userhooks.php304
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);
+ }
+}