]> source.dussan.org Git - nextcloud-server.git/commitdiff
Initial commit
authorClark Tomlinson <fallen013@gmail.com>
Tue, 24 Feb 2015 18:05:19 +0000 (13:05 -0500)
committerThomas Müller <thomas.mueller@tmit.eu>
Tue, 7 Apr 2015 11:30:27 +0000 (13:30 +0200)
37 files changed:
apps/encryption/appinfo/app.php [new file with mode: 0644]
apps/encryption/appinfo/encryption.php [new file with mode: 0644]
apps/encryption/appinfo/info.xml [new file with mode: 0644]
apps/encryption/appinfo/routes.php [new file with mode: 0644]
apps/encryption/controller/recoverycontroller.php [new file with mode: 0644]
apps/encryption/hooks/apphooks.php [new file with mode: 0644]
apps/encryption/hooks/contracts/ihook.php [new file with mode: 0644]
apps/encryption/hooks/filesystemhooks.php [new file with mode: 0644]
apps/encryption/hooks/sharehooks.php [new file with mode: 0644]
apps/encryption/hooks/userhooks.php [new file with mode: 0644]
apps/encryption/lib/crypto/Encryption.php [new file with mode: 0644]
apps/encryption/lib/crypto/crypt.php [new file with mode: 0644]
apps/encryption/lib/hookmanager.php [new file with mode: 0644]
apps/encryption/lib/keymanager.php [new file with mode: 0644]
apps/encryption/lib/migrator.php [new file with mode: 0644]
apps/encryption/lib/recovery.php [new file with mode: 0644]
apps/encryption/lib/setup.php [new file with mode: 0644]
apps/encryption/lib/users/setup.php [new file with mode: 0644]
apps/encryption/settings/settings-admin.php [new file with mode: 0644]
apps/encryption/settings/settings-personal.php [new file with mode: 0644]
apps/encryption/tests/lib/KeyManagerTest.php [new file with mode: 0644]
apps/encryption/tests/lib/MigratorTest.php [new file with mode: 0644]
apps/encryption/tests/lib/RequirementsCheckerTest.php [new file with mode: 0644]
apps/files_encryption/lib/hooks.php
lib/private/encryption/exceptions/decryptionfailedexception.php [new file with mode: 0644]
lib/private/encryption/exceptions/emptyencryptiondataexception.php [new file with mode: 0644]
lib/private/encryption/exceptions/encryptionfailedexception.php [new file with mode: 0644]
lib/private/encryption/exceptions/encryptionheadertolargeexception.php [new file with mode: 0644]
lib/private/encryption/exceptions/genericencryptionexception.php [new file with mode: 0644]
lib/private/encryption/exceptions/privatekeymissingexception.php [new file with mode: 0644]
lib/private/encryption/exceptions/publickeymissingexception.php [new file with mode: 0644]
lib/private/encryption/exceptions/unexpectedblocksizeexception.php [new file with mode: 0644]
lib/private/encryption/exceptions/unexpectedendofencryptionheaderexception.php [new file with mode: 0644]
lib/private/encryption/exceptions/unknowncipherexception.php [new file with mode: 0644]
lib/private/encryption/keystorage.php
lib/public/encryption/ikeystorage.php
tests/lib/encryption/managertest.php

diff --git a/apps/encryption/appinfo/app.php b/apps/encryption/appinfo/app.php
new file mode 100644 (file)
index 0000000..72e7fc4
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+/**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+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 (file)
index 0000000..f2ab89a
--- /dev/null
@@ -0,0 +1,182 @@
+<?php
+/**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+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 (file)
index 0000000..e4a7d79
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<info>
+       <id>encryption</id>
+       <description>
+               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
+       </description>
+<name>Encryption</name>
+       <license>AGPL</license>
+       <author>Bjoern Schiessle, Clark Tomlinson</author>
+       <requiremin>8</requiremin>
+       <shipped>true</shipped>
+       <documentation>
+               <user>user-encryption</user>
+               <admin>admin-encryption</admin>
+       </documentation>
+       <rememberlogin>false</rememberlogin>
+       <types>
+               <filesystem/>
+       </types>
+       <dependencies>
+               <lib>openssl</lib>
+       </dependencies>
+
+</info>
diff --git a/apps/encryption/appinfo/routes.php b/apps/encryption/appinfo/routes.php
new file mode 100644 (file)
index 0000000..a86f371
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+/**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+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 (file)
index 0000000..abea899
--- /dev/null
@@ -0,0 +1,106 @@
+<?php
+/**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+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 (file)
index 0000000..713e9ca
--- /dev/null
@@ -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 (file)
index 0000000..2cc01fd
--- /dev/null
@@ -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 (file)
index 0000000..fda6b75
--- /dev/null
@@ -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 (file)
index 0000000..fc50712
--- /dev/null
@@ -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 (file)
index 0000000..79de70a
--- /dev/null
@@ -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);
+       }
+}
diff --git a/apps/encryption/lib/crypto/Encryption.php b/apps/encryption/lib/crypto/Encryption.php
new file mode 100644 (file)
index 0000000..123581b
--- /dev/null
@@ -0,0 +1,116 @@
+<?php
+  /**
+ * @author Clark Tomlinson  <fallen013@gmail.com>
+ * @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 (file)
index 0000000..8018f11
--- /dev/null
@@ -0,0 +1,355 @@
+<?php
+/**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+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 (file)
index 0000000..a535230
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+/**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+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 (file)
index 0000000..272bf08
--- /dev/null
@@ -0,0 +1,217 @@
+<?php
+/**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+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 (file)
index 0000000..8f7823c
--- /dev/null
@@ -0,0 +1,123 @@
+<?php
+/**
+ * @author Clark Tomlinson  <fallen013@gmail.com>
+ * @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 (file)
index 0000000..88350e9
--- /dev/null
@@ -0,0 +1,134 @@
+<?php
+/**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+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 (file)
index 0000000..cc8f00f
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+/**
+ * @author Clark Tomlinson  <fallen013@gmail.com>
+ * @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 (file)
index 0000000..123d697
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+/**
+ * @author Clark Tomlinson  <fallen013@gmail.com>
+ * @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 (file)
index 0000000..0f5d56a
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Copyright (c) 2011 Robin Appelman <icewind@owncloud.com>
+ * 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 (file)
index 0000000..fe2d846
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Copyright (c) 2013 Sam Tuke <samtuke@owncloud.com>
+ * 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 (file)
index 0000000..260e69a
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+/**
+ * @author Clark Tomlinson  <fallen013@gmail.com>
+ * @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 (file)
index 0000000..a9d57b3
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+/**
+ * @author Clark Tomlinson  <fallen013@gmail.com>
+ * @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 (file)
index 0000000..97ddd76
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+/**
+ * @author Clark Tomlinson  <fallen013@gmail.com>
+ * @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());
+       }
+
+}
index 4a29ffaaedfe13b1a54ec9f10e72575b7b6cf805..536e512bdb23626b9414e635ce430570f32fa048 100644 (file)
@@ -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 (file)
index 0000000..43fea90
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+  /**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+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 (file)
index 0000000..ea18180
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+  /**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+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 (file)
index 0000000..9e6648f
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+  /**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+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 (file)
index 0000000..cc980aa
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+  /**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+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 (file)
index 0000000..608e5e6
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+  /**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+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 (file)
index 0000000..878b83d
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+  /**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+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 (file)
index 0000000..d5f2aae
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+/**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+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 (file)
index 0000000..799d08e
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+  /**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+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 (file)
index 0000000..04f65cf
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+  /**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+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 (file)
index 0000000..5177af6
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+  /**
+ * @author Clark Tomlinson  <clark@owncloud.com>
+ * @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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OC\Encryption\Exceptions;
+
+
+class UnknownCipherException extends GenericEncryptionException{
+
+}
index 5b56f6af4e713b69bdaf7b19ec58fecee2fc75d8..fbc427edf0f1c824d78ca91a85ee40dcf3847b73 100644 (file)
 
 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;
+       }
+
 }
index cf94d56e59b32db52791ed4ec98cfdf703b0aba3..2ab5048709e47f762260240fb17e8e579746576a 100644 (file)
@@ -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();
 }
index ab297bae0cb015dd08730860541f1ca0e1c38ea8..5a0efa37b369d3ed7f090bc339df93ce7f3007d3 100644 (file)
@@ -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());
+       }
 }