aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/dav/tests/unit/Connector/Sabre/RequestTest/EncryptionMasterKeyUploadTest.php50
-rw-r--r--apps/dav/tests/unit/Connector/Sabre/RequestTest/EncryptionUploadTest.php2
-rw-r--r--apps/encryption/appinfo/app.php1
-rw-r--r--apps/encryption/appinfo/info.xml9
-rw-r--r--apps/encryption/lib/AppInfo/Application.php10
-rw-r--r--apps/encryption/lib/Command/DisableMasterKey.php89
-rw-r--r--apps/encryption/lib/Controller/StatusController.php21
-rw-r--r--apps/encryption/lib/Crypto/Encryption.php9
-rw-r--r--apps/encryption/lib/KeyManager.php13
-rw-r--r--apps/encryption/lib/Migration/SetMasterKeyStatus.php77
-rw-r--r--apps/encryption/lib/Util.php2
-rw-r--r--apps/encryption/templates/settings-admin.php2
-rw-r--r--apps/encryption/tests/Controller/StatusControllerTest.php8
-rw-r--r--apps/encryption/tests/UtilTest.php2
-rw-r--r--apps/files_sharing/tests/EncryptedSizePropagationTest.php2
-rw-r--r--lib/private/Encryption/Update.php10
-rw-r--r--lib/private/Files/Stream/Encryption.php5
-rw-r--r--lib/public/Encryption/IEncryptionModule.php10
-rw-r--r--settings/Controller/UsersController.php23
-rw-r--r--tests/Settings/Controller/UsersControllerTest.php36
-rw-r--r--tests/lib/Files/Storage/Wrapper/EncryptionTest.php3
-rw-r--r--tests/lib/Files/Stream/EncryptionTest.php37
-rw-r--r--tests/lib/Traits/EncryptionTrait.php2
23 files changed, 387 insertions, 36 deletions
diff --git a/apps/dav/tests/unit/Connector/Sabre/RequestTest/EncryptionMasterKeyUploadTest.php b/apps/dav/tests/unit/Connector/Sabre/RequestTest/EncryptionMasterKeyUploadTest.php
new file mode 100644
index 00000000000..480baab6baf
--- /dev/null
+++ b/apps/dav/tests/unit/Connector/Sabre/RequestTest/EncryptionMasterKeyUploadTest.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ *
+ * @author Joas Schilling <coding@schilljs.com>
+ * @author Robin Appelman <robin@icewind.nl>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @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\DAV\Tests\unit\Connector\Sabre\RequestTest;
+
+use OC\Files\View;
+use Test\Traits\EncryptionTrait;
+
+/**
+ * Class EncryptionMasterKeyUploadTest
+ *
+ * @group DB
+ *
+ * @package OCA\DAV\Tests\Unit\Connector\Sabre\RequestTest
+ */
+class EncryptionMasterKeyUploadTest extends UploadTest {
+ use EncryptionTrait;
+
+ protected function setupUser($name, $password) {
+ $this->createUser($name, $password);
+ $tmpFolder = \OC::$server->getTempManager()->getTemporaryFolder();
+ $this->registerMount($name, '\OC\Files\Storage\Local', '/' . $name, ['datadir' => $tmpFolder]);
+ // we use the master key
+ \OC::$server->getConfig()->setAppValue('encryption', 'useMasterKey', '1');
+ $this->setupForUser($name, $password);
+ $this->loginWithEncryption($name);
+ return new View('/' . $name . '/files');
+ }
+}
diff --git a/apps/dav/tests/unit/Connector/Sabre/RequestTest/EncryptionUploadTest.php b/apps/dav/tests/unit/Connector/Sabre/RequestTest/EncryptionUploadTest.php
index e65d58b816f..c0cba121386 100644
--- a/apps/dav/tests/unit/Connector/Sabre/RequestTest/EncryptionUploadTest.php
+++ b/apps/dav/tests/unit/Connector/Sabre/RequestTest/EncryptionUploadTest.php
@@ -41,6 +41,8 @@ class EncryptionUploadTest extends UploadTest {
$this->createUser($name, $password);
$tmpFolder = \OC::$server->getTempManager()->getTemporaryFolder();
$this->registerMount($name, '\OC\Files\Storage\Local', '/' . $name, ['datadir' => $tmpFolder]);
+ // we use per-user keys
+ \OC::$server->getConfig()->setAppValue('encryption', 'useMasterKey', '0');
$this->setupForUser($name, $password);
$this->loginWithEncryption($name);
return new View('/' . $name . '/files');
diff --git a/apps/encryption/appinfo/app.php b/apps/encryption/appinfo/app.php
index 950166dca2b..4f54f0e7251 100644
--- a/apps/encryption/appinfo/app.php
+++ b/apps/encryption/appinfo/app.php
@@ -31,4 +31,5 @@ $app = new Application([], $encryptionSystemReady);
if ($encryptionSystemReady) {
$app->registerEncryptionModule();
$app->registerHooks();
+ $app->setUp();
}
diff --git a/apps/encryption/appinfo/info.xml b/apps/encryption/appinfo/info.xml
index 7cfdc934386..f35a87aa4f2 100644
--- a/apps/encryption/appinfo/info.xml
+++ b/apps/encryption/appinfo/info.xml
@@ -19,7 +19,7 @@
<user>user-encryption</user>
<admin>admin-encryption</admin>
</documentation>
- <version>1.7.1</version>
+ <version>2.0.0</version>
<types>
<filesystem/>
</types>
@@ -33,6 +33,13 @@
</settings>
<commands>
<command>OCA\Encryption\Command\EnableMasterKey</command>
+ <command>OCA\Encryption\Command\DisableMasterKey</command>
<command>OCA\Encryption\Command\MigrateKeys</command>
</commands>
+
+ <repair-steps>
+ <post-migration>
+ <step>OCA\Encryption\Migration\SetMasterKeyStatus</step>
+ </post-migration>
+ </repair-steps>
</info>
diff --git a/apps/encryption/lib/AppInfo/Application.php b/apps/encryption/lib/AppInfo/Application.php
index 56c2dafdabd..dd9d173c8eb 100644
--- a/apps/encryption/lib/AppInfo/Application.php
+++ b/apps/encryption/lib/AppInfo/Application.php
@@ -67,7 +67,11 @@ class Application extends \OCP\AppFramework\App {
$session = $this->getContainer()->query('Session');
$session->setStatus(Session::RUN_MIGRATION);
}
- if ($this->encryptionManager->isEnabled() && $encryptionSystemReady) {
+
+ }
+
+ public function setUp() {
+ if ($this->encryptionManager->isEnabled()) {
/** @var Setup $setup */
$setup = $this->getContainer()->query('UserSetup');
$setup->setupSystem();
@@ -77,7 +81,6 @@ class Application extends \OCP\AppFramework\App {
/**
* register hooks
*/
-
public function registerHooks() {
if (!$this->config->getSystemValue('maintenance', false)) {
@@ -193,7 +196,8 @@ class Application extends \OCP\AppFramework\App {
$c->getAppName(),
$server->getRequest(),
$server->getL10N($c->getAppName()),
- $c->query('Session')
+ $c->query('Session'),
+ $server->getEncryptionManager()
);
});
diff --git a/apps/encryption/lib/Command/DisableMasterKey.php b/apps/encryption/lib/Command/DisableMasterKey.php
new file mode 100644
index 00000000000..97c2ad40b61
--- /dev/null
+++ b/apps/encryption/lib/Command/DisableMasterKey.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 Bjoern Schiessle <bjoern@schiessle.org>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Encryption\Command;
+
+
+use OCA\Encryption\Util;
+use OCP\IConfig;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\QuestionHelper;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Question\ConfirmationQuestion;
+
+class DisableMasterKey extends Command {
+
+ /** @var Util */
+ protected $util;
+
+ /** @var IConfig */
+ protected $config;
+
+ /** @var QuestionHelper */
+ protected $questionHelper;
+
+ /**
+ * @param Util $util
+ * @param IConfig $config
+ * @param QuestionHelper $questionHelper
+ */
+ public function __construct(Util $util,
+ IConfig $config,
+ QuestionHelper $questionHelper) {
+
+ $this->util = $util;
+ $this->config = $config;
+ $this->questionHelper = $questionHelper;
+ parent::__construct();
+ }
+
+ protected function configure() {
+ $this
+ ->setName('encryption:disable-master-key')
+ ->setDescription('Disable the master key and use per-user keys instead. Only available for fresh installations with no existing encrypted data! There is no way to enable it again.');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+
+ $isMasterKeyEnabled = $this->util->isMasterKeyEnabled();
+
+ if(!$isMasterKeyEnabled) {
+ $output->writeln('Master key already disabled');
+ } else {
+ $question = new ConfirmationQuestion(
+ 'Warning: Only perform this operation for a fresh installations with no existing encrypted data! '
+ . 'There is no way to enable the master key again. '
+ . 'We strongly recommend to keep the master key, it provides significant performance improvements '
+ . 'and is easier to handle for both, users and administrators. '
+ . 'Do you really want to switch to per-user keys? (y/n) ', false);
+ if ($this->questionHelper->ask($input, $output, $question)) {
+ $this->config->setAppValue('encryption', 'useMasterKey', '0');
+ $output->writeln('Master key successfully disabled.');
+ } else {
+ $output->writeln('aborted.');
+ }
+ }
+
+ }
+
+}
diff --git a/apps/encryption/lib/Controller/StatusController.php b/apps/encryption/lib/Controller/StatusController.php
index 0776a84ceb4..9ec9fd1234b 100644
--- a/apps/encryption/lib/Controller/StatusController.php
+++ b/apps/encryption/lib/Controller/StatusController.php
@@ -28,6 +28,7 @@ namespace OCA\Encryption\Controller;
use OCA\Encryption\Session;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\DataResponse;
+use OCP\Encryption\IManager;
use OCP\IL10N;
use OCP\IRequest;
@@ -39,20 +40,26 @@ class StatusController extends Controller {
/** @var Session */
private $session;
+ /** @var IManager */
+ private $encryptionManager;
+
/**
* @param string $AppName
* @param IRequest $request
* @param IL10N $l10n
* @param Session $session
+ * @param IManager $encryptionManager
*/
public function __construct($AppName,
IRequest $request,
IL10N $l10n,
- Session $session
+ Session $session,
+ IManager $encryptionManager
) {
parent::__construct($AppName, $request);
$this->l = $l10n;
$this->session = $session;
+ $this->encryptionManager = $encryptionManager;
}
/**
@@ -78,9 +85,15 @@ class StatusController extends Controller {
break;
case Session::NOT_INITIALIZED:
$status = 'interactionNeeded';
- $message = (string)$this->l->t(
- 'Encryption App is enabled, but your keys are not initialized. Please log-out and log-in again.'
- );
+ if ($this->encryptionManager->isEnabled()) {
+ $message = (string)$this->l->t(
+ 'Encryption App is enabled, but your keys are not initialized. Please log-out and log-in again.'
+ );
+ } else {
+ $message = (string)$this->l->t(
+ 'Please enable server side encryption in the admin settings in order to use the encryption module.'
+ );
+ }
break;
case Session::INIT_SUCCESSFUL:
$status = 'success';
diff --git a/apps/encryption/lib/Crypto/Encryption.php b/apps/encryption/lib/Crypto/Encryption.php
index 7f7665a24fc..6869177ac31 100644
--- a/apps/encryption/lib/Crypto/Encryption.php
+++ b/apps/encryption/lib/Crypto/Encryption.php
@@ -569,4 +569,13 @@ class Encryption implements IEncryptionModule {
public function isReadyForUser($user) {
return $this->keyManager->userHasKeys($user);
}
+
+ /**
+ * We only need a detailed access list if the master key is not enabled
+ *
+ * @return bool
+ */
+ public function needDetailedAccessList() {
+ return !$this->util->isMasterKeyEnabled();
+ }
}
diff --git a/apps/encryption/lib/KeyManager.php b/apps/encryption/lib/KeyManager.php
index 6b260c39bfb..6039aaaaa0e 100644
--- a/apps/encryption/lib/KeyManager.php
+++ b/apps/encryption/lib/KeyManager.php
@@ -179,8 +179,8 @@ class KeyManager {
return;
}
- $masterKey = $this->getPublicMasterKey();
- if (empty($masterKey)) {
+ $publicMasterKey = $this->getPublicMasterKey();
+ if (empty($publicMasterKey)) {
$keyPair = $this->crypt->createKeyPair();
// Save public key
@@ -193,6 +193,15 @@ class KeyManager {
$header = $this->crypt->generateHeader();
$this->setSystemPrivateKey($this->masterKeyId, $header . $encryptedKey);
}
+
+ if (!$this->session->isPrivateKeySet()) {
+ $masterKey = $this->getSystemPrivateKey($this->masterKeyId);
+ $decryptedMasterKey = $this->crypt->decryptPrivateKey($masterKey, $this->getMasterKeyPassword(), $this->masterKeyId);
+ $this->session->setPrivateKey($decryptedMasterKey);
+ }
+
+ // after the encryption key is available we are ready to go
+ $this->session->setStatus(Session::INIT_SUCCESSFUL);
}
/**
diff --git a/apps/encryption/lib/Migration/SetMasterKeyStatus.php b/apps/encryption/lib/Migration/SetMasterKeyStatus.php
new file mode 100644
index 00000000000..a21d0acae24
--- /dev/null
+++ b/apps/encryption/lib/Migration/SetMasterKeyStatus.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 Bjoern Schiessle <bjoern@schiessle.org>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Encryption\Migration;
+
+
+use OCP\IConfig;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+/**
+ * Class SetPasswordColumn
+ *
+ * @package OCA\Files_Sharing\Migration
+ */
+class SetMasterKeyStatus implements IRepairStep {
+
+
+ /** @var IConfig */
+ private $config;
+
+
+ public function __construct(IConfig $config) {
+ $this->config = $config;
+ }
+
+ /**
+ * Returns the step's name
+ *
+ * @return string
+ * @since 9.1.0
+ */
+ public function getName() {
+ return 'Write default encryption module configuration to the database';
+ }
+
+ /**
+ * @param IOutput $output
+ */
+ public function run(IOutput $output) {
+ if (!$this->shouldRun()) {
+ return;
+ }
+
+ // if no config for the master key is set we set it explicitly to '0' in
+ // order not to break old installations because the default changed to '1'.
+ $configAlreadySet = $this->config->getAppValue('encryption', 'useMasterKey', false);
+ if ($configAlreadySet === false) {
+ $this->config->setAppValue('encryption', 'useMasterKey', '0');
+ }
+ }
+
+ protected function shouldRun() {
+ $appVersion = $this->config->getAppValue('encryption', 'installed_version', '0.0.0');
+ return version_compare($appVersion, '2.0.0', '<');
+ }
+
+}
diff --git a/apps/encryption/lib/Util.php b/apps/encryption/lib/Util.php
index 72afa68aad2..d6ae9bd7e5e 100644
--- a/apps/encryption/lib/Util.php
+++ b/apps/encryption/lib/Util.php
@@ -136,7 +136,7 @@ class Util {
* @return bool
*/
public function isMasterKeyEnabled() {
- $userMasterKey = $this->config->getAppValue('encryption', 'useMasterKey', '0');
+ $userMasterKey = $this->config->getAppValue('encryption', 'useMasterKey', '1');
return ($userMasterKey === '1');
}
diff --git a/apps/encryption/templates/settings-admin.php b/apps/encryption/templates/settings-admin.php
index efe9c44ece7..c5f8d9f5536 100644
--- a/apps/encryption/templates/settings-admin.php
+++ b/apps/encryption/templates/settings-admin.php
@@ -7,7 +7,7 @@ style('encryption', 'settings-admin');
?>
<form id="ocDefaultEncryptionModule" class="sub-section">
<h3><?php p($l->t("Default encryption module")); ?></h3>
- <?php if(!$_["initStatus"]): ?>
+ <?php if(!$_["initStatus"] && $_['masterKeyEnabled'] === false): ?>
<?php p($l->t("Encryption app is enabled but your keys are not initialized, please log-out and log-in again")); ?>
<?php else: ?>
<p id="encryptHomeStorageSetting">
diff --git a/apps/encryption/tests/Controller/StatusControllerTest.php b/apps/encryption/tests/Controller/StatusControllerTest.php
index c6c92e2aac2..ee0f7b2661c 100644
--- a/apps/encryption/tests/Controller/StatusControllerTest.php
+++ b/apps/encryption/tests/Controller/StatusControllerTest.php
@@ -27,6 +27,7 @@ namespace OCA\Encryption\Tests\Controller;
use OCA\Encryption\Controller\StatusController;
use OCA\Encryption\Session;
+use OCP\Encryption\IManager;
use OCP\IRequest;
use Test\TestCase;
@@ -41,6 +42,9 @@ class StatusControllerTest extends TestCase {
/** @var \OCA\Encryption\Session | \PHPUnit_Framework_MockObject_MockObject */
protected $sessionMock;
+ /** @var IManager | \PHPUnit_Framework_MockObject_MockObject */
+ protected $encryptionManagerMock;
+
/** @var StatusController */
protected $controller;
@@ -59,11 +63,13 @@ class StatusControllerTest extends TestCase {
->will($this->returnCallback(function($message) {
return $message;
}));
+ $this->encryptionManagerMock = $this->createMock(IManager::class);
$this->controller = new StatusController('encryptionTest',
$this->requestMock,
$this->l10nMock,
- $this->sessionMock);
+ $this->sessionMock,
+ $this->encryptionManagerMock);
}
diff --git a/apps/encryption/tests/UtilTest.php b/apps/encryption/tests/UtilTest.php
index d2f1d40e16d..40fc5537251 100644
--- a/apps/encryption/tests/UtilTest.php
+++ b/apps/encryption/tests/UtilTest.php
@@ -152,7 +152,7 @@ class UtilTest extends TestCase {
*/
public function testIsMasterKeyEnabled($value, $expect) {
$this->configMock->expects($this->once())->method('getAppValue')
- ->with('encryption', 'useMasterKey', '0')->willReturn($value);
+ ->with('encryption', 'useMasterKey', '1')->willReturn($value);
$this->assertSame($expect,
$this->instance->isMasterKeyEnabled()
);
diff --git a/apps/files_sharing/tests/EncryptedSizePropagationTest.php b/apps/files_sharing/tests/EncryptedSizePropagationTest.php
index 6b6ed2cd73e..38bbf12177c 100644
--- a/apps/files_sharing/tests/EncryptedSizePropagationTest.php
+++ b/apps/files_sharing/tests/EncryptedSizePropagationTest.php
@@ -36,8 +36,10 @@ class EncryptedSizePropagationTest extends SizePropagationTest {
$this->createUser($name, $password);
$tmpFolder = \OC::$server->getTempManager()->getTemporaryFolder();
$this->registerMount($name, '\OC\Files\Storage\Local', '/' . $name, ['datadir' => $tmpFolder]);
+ $this->config->setAppValue('encryption', 'useMasterKey', '0');
$this->setupForUser($name, $password);
$this->loginWithEncryption($name);
return new View('/' . $name . '/files');
}
+
}
diff --git a/lib/private/Encryption/Update.php b/lib/private/Encryption/Update.php
index ad40183767b..94d64b73504 100644
--- a/lib/private/Encryption/Update.php
+++ b/lib/private/Encryption/Update.php
@@ -168,6 +168,14 @@ class Update {
*/
public function update($path) {
+ $encryptionModule = $this->encryptionManager->getEncryptionModule();
+
+ // if the encryption module doesn't encrypt the files on a per-user basis
+ // we have nothing to do here.
+ if ($encryptionModule->needDetailedAccessList() === false) {
+ return;
+ }
+
// if a folder was shared, get a list of all (sub-)folders
if ($this->view->is_dir($path)) {
$allFiles = $this->util->getAllFiles($path);
@@ -175,7 +183,7 @@ class Update {
$allFiles = array($path);
}
- $encryptionModule = $this->encryptionManager->getEncryptionModule();
+
foreach ($allFiles as $file) {
$usersSharing = $this->file->getAccessList($file);
diff --git a/lib/private/Files/Stream/Encryption.php b/lib/private/Files/Stream/Encryption.php
index d1f68696848..b68917ce76e 100644
--- a/lib/private/Files/Stream/Encryption.php
+++ b/lib/private/Files/Stream/Encryption.php
@@ -254,7 +254,10 @@ class Encryption extends Wrapper {
$sharePath = dirname($sharePath);
}
- $accessList = $this->file->getAccessList($sharePath);
+ $accessList = [];
+ if ($this->encryptionModule->needDetailedAccessList()) {
+ $accessList = $this->file->getAccessList($sharePath);
+ }
$this->newHeader = $this->encryptionModule->begin($this->fullPath, $this->uid, $mode, $this->header, $accessList);
if (
diff --git a/lib/public/Encryption/IEncryptionModule.php b/lib/public/Encryption/IEncryptionModule.php
index 6be9763c9c8..d96c6c8ba06 100644
--- a/lib/public/Encryption/IEncryptionModule.php
+++ b/lib/public/Encryption/IEncryptionModule.php
@@ -182,4 +182,14 @@ interface IEncryptionModule {
*/
public function isReadyForUser($user);
+ /**
+ * Does the encryption module needs a detailed list of users with access to the file?
+ * For example if the encryption module uses per-user encryption keys and needs to know
+ * the users with access to the file to encrypt/decrypt it.
+ *
+ * @since 13.0.0
+ * @return bool
+ */
+ public function needDetailedAccessList();
+
}
diff --git a/settings/Controller/UsersController.php b/settings/Controller/UsersController.php
index a193f9bc8de..76394fcb6c6 100644
--- a/settings/Controller/UsersController.php
+++ b/settings/Controller/UsersController.php
@@ -42,6 +42,8 @@ use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\IJobList;
use OCP\Files\Config\IUserMountCache;
+use OCP\Encryption\IEncryptionModule;
+use OCP\Encryption\IManager;
use OCP\IConfig;
use OCP\IGroupManager;
use OCP\IL10N;
@@ -99,9 +101,14 @@ class UsersController extends Controller {
private $keyManager;
/** @var IJobList */
private $jobList;
+
/** @var IUserMountCache */
private $userMountCache;
+ /** @var IManager */
+ private $encryptionManager;
+
+
/**
* @param string $appName
* @param IRequest $request
@@ -124,6 +131,7 @@ class UsersController extends Controller {
* @param Manager $keyManager
* @param IJobList $jobList
* @param IUserMountCache $userMountCache
+ * @param IManager $encryptionManager
*/
public function __construct($appName,
IRequest $request,
@@ -145,7 +153,8 @@ class UsersController extends Controller {
ICrypto $crypto,
Manager $keyManager,
IJobList $jobList,
- IUserMountCache $userMountCache) {
+ IUserMountCache $userMountCache,
+ IManager $encryptionManager) {
parent::__construct($appName, $request);
$this->userManager = $userManager;
$this->groupManager = $groupManager;
@@ -165,6 +174,7 @@ class UsersController extends Controller {
$this->keyManager = $keyManager;
$this->jobList = $jobList;
$this->userMountCache = $userMountCache;
+ $this->encryptionManager = $encryptionManager;
// check for encryption state - TODO see formatUserForIndex
$this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
@@ -200,6 +210,17 @@ class UsersController extends Controller {
// user also has recovery mode enabled
$restorePossible = true;
}
+ } else {
+ $modules = $this->encryptionManager->getEncryptionModules();
+ $restorePossible = true;
+ foreach ($modules as $id => $module) {
+ /* @var IEncryptionModule $instance */
+ $instance = call_user_func($module['callback']);
+ if ($instance->needDetailedAccessList()) {
+ $restorePossible = false;
+ break;
+ }
+ }
}
} else {
// recovery is possible if encryption is disabled (plain files are
diff --git a/tests/Settings/Controller/UsersControllerTest.php b/tests/Settings/Controller/UsersControllerTest.php
index 0780f5219c0..cd08c834147 100644
--- a/tests/Settings/Controller/UsersControllerTest.php
+++ b/tests/Settings/Controller/UsersControllerTest.php
@@ -20,6 +20,8 @@ use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\IJobList;
use OCP\Files\Config\IUserMountCache;
+use OCP\Encryption\IEncryptionModule;
+use OCP\Encryption\IManager;
use OCP\IAvatar;
use OCP\IAvatarManager;
use OCP\IConfig;
@@ -82,6 +84,10 @@ class UsersControllerTest extends \Test\TestCase {
private $securityManager;
/** @var IUserMountCache |\PHPUnit_Framework_MockObject_MockObject */
private $userMountCache;
+ /** @var IManager | \PHPUnit_Framework_MockObject_MockObject */
+ private $encryptionManager;
+ /** @var IEncryptionModule | \PHPUnit_Framework_MockObject_MockObject */
+ private $encryptionModule;
protected function setUp() {
parent::setUp();
@@ -104,6 +110,7 @@ class UsersControllerTest extends \Test\TestCase {
$this->crypto = $this->createMock(ICrypto::class);
$this->securityManager = $this->getMockBuilder(\OC\Security\IdentityProof\Manager::class)->disableOriginalConstructor()->getMock();
$this->jobList = $this->createMock(IJobList::class);
+ $this->encryptionManager = $this->createMock(IManager::class);
$this->l = $this->createMock(IL10N::class);
$this->l->method('t')
->will($this->returnCallback(function ($text, $parameters = []) {
@@ -111,6 +118,10 @@ class UsersControllerTest extends \Test\TestCase {
}));
$this->userMountCache = $this->createMock(IUserMountCache::class);
+ $this->encryptionModule = $this->createMock(IEncryptionModule::class);
+ $this->encryptionManager->expects($this->any())->method('getEncryptionModules')
+ ->willReturn(['encryptionModule' => ['callback' => function() { return $this->encryptionModule;}]]);
+
/*
* Set default avatar behaviour for whole test suite
*/
@@ -154,8 +165,8 @@ class UsersControllerTest extends \Test\TestCase {
$this->crypto,
$this->securityManager,
$this->jobList,
- $this->userMountCache
-
+ $this->userMountCache,
+ $this->encryptionManager
);
} else {
return $this->getMockBuilder(UsersController::class)
@@ -182,6 +193,7 @@ class UsersControllerTest extends \Test\TestCase {
$this->securityManager,
$this->jobList,
$this->userMountCache,
+ $this->encryptionManager
]
)->setMethods($mockedMethods)->getMock();
}
@@ -1689,9 +1701,17 @@ class UsersControllerTest extends \Test\TestCase {
$this->assertEquals($expectedResult, $result);
}
- public function testRestoreNotPossibleWithoutAdminRestore() {
+ /**
+ * @dataProvider dataTestRestoreNotPossibleWithoutAdminRestore
+ *
+ * @param bool $masterKeyEnabled
+ */
+ public function testRestoreNotPossibleWithoutAdminRestore($masterKeyEnabled) {
list($user, $expectedResult) = $this->mockUser();
+ // without the master key enabled we use per-user keys
+ $this->encryptionModule->expects($this->once())->method('needDetailedAccessList')->willReturn(!$masterKeyEnabled);
+
$this->appManager
->method('isEnabledForUser')
->with(
@@ -1699,7 +1719,8 @@ class UsersControllerTest extends \Test\TestCase {
)
->will($this->returnValue(true));
- $expectedResult['isRestoreDisabled'] = true;
+ // without the master key enabled we use per-user keys -> restore is disabled
+ $expectedResult['isRestoreDisabled'] = !$masterKeyEnabled;
$subadmin = $this->getMockBuilder('\OC\SubAdmin')
->disableOriginalConstructor()
@@ -1718,6 +1739,13 @@ class UsersControllerTest extends \Test\TestCase {
$this->assertEquals($expectedResult, $result);
}
+ public function dataTestRestoreNotPossibleWithoutAdminRestore() {
+ return [
+ [true],
+ [false]
+ ];
+ }
+
public function testRestoreNotPossibleWithoutUserRestore() {
list($user, $expectedResult) = $this->mockUser();
diff --git a/tests/lib/Files/Storage/Wrapper/EncryptionTest.php b/tests/lib/Files/Storage/Wrapper/EncryptionTest.php
index d310f110b94..a66ff14a778 100644
--- a/tests/lib/Files/Storage/Wrapper/EncryptionTest.php
+++ b/tests/lib/Files/Storage/Wrapper/EncryptionTest.php
@@ -212,7 +212,7 @@ class EncryptionTest extends Storage {
protected function buildMockModule() {
$this->encryptionModule = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule')
->disableOriginalConstructor()
- ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll', 'isReadyForUser'])
+ ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll', 'isReadyForUser', 'needDetailedAccessList'])
->getMock();
$this->encryptionModule->expects($this->any())->method('getId')->willReturn('UNIT_TEST_MODULE');
@@ -225,6 +225,7 @@ class EncryptionTest extends Storage {
$this->encryptionModule->expects($this->any())->method('shouldEncrypt')->willReturn(true);
$this->encryptionModule->expects($this->any())->method('getUnencryptedBlockSize')->willReturn(8192);
$this->encryptionModule->expects($this->any())->method('isReadable')->willReturn(true);
+ $this->encryptionModule->expects($this->any())->method('needDetailedAccessList')->willReturn(false);
return $this->encryptionModule;
}
diff --git a/tests/lib/Files/Stream/EncryptionTest.php b/tests/lib/Files/Stream/EncryptionTest.php
index e072dd6718d..1dc9dca0aad 100644
--- a/tests/lib/Files/Stream/EncryptionTest.php
+++ b/tests/lib/Files/Stream/EncryptionTest.php
@@ -58,7 +58,8 @@ class EncryptionTest extends \Test\TestCase {
/**
* @dataProvider dataProviderStreamOpen()
*/
- public function testStreamOpen($mode,
+ public function testStreamOpen($isMasterKeyUsed,
+ $mode,
$fullPath,
$fileExists,
$expectedSharePath,
@@ -69,6 +70,7 @@ class EncryptionTest extends \Test\TestCase {
// build mocks
$encryptionModuleMock = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule')
->disableOriginalConstructor()->getMock();
+ $encryptionModuleMock->expects($this->any())->method('needDetailedAccessList')->willReturn(!$isMasterKeyUsed);
$encryptionModuleMock->expects($this->once())
->method('getUnencryptedBlockSize')->willReturn(99);
$encryptionModuleMock->expects($this->once())
@@ -80,12 +82,15 @@ class EncryptionTest extends \Test\TestCase {
$fileMock = $this->getMockBuilder('\OC\Encryption\File')
->disableOriginalConstructor()->getMock();
- $fileMock->expects($this->once())->method('getAccessList')
- ->will($this->returnCallback(function($sharePath) use ($expectedSharePath) {
- $this->assertSame($expectedSharePath, $sharePath);
- return array();
- }));
-
+ if ($isMasterKeyUsed) {
+ $fileMock->expects($this->never())->method('getAccessList');
+ } else {
+ $fileMock->expects($this->once())->method('getAccessList')
+ ->will($this->returnCallback(function ($sharePath) use ($expectedSharePath) {
+ $this->assertSame($expectedSharePath, $sharePath);
+ return array();
+ }));
+ }
$utilMock = $this->getMockBuilder('\OC\Encryption\Util')
->disableOriginalConstructor()->getMock();
$utilMock->expects($this->any())
@@ -152,11 +157,14 @@ class EncryptionTest extends \Test\TestCase {
}
public function dataProviderStreamOpen() {
- return array(
- array('r', '/foo/bar/test.txt', true, '/foo/bar/test.txt', null, null, true),
- array('r', '/foo/bar/test.txt', false, '/foo/bar', null, null, true),
- array('w', '/foo/bar/test.txt', true, '/foo/bar/test.txt', 8192, 0, false),
- );
+ return [
+ [false, 'r', '/foo/bar/test.txt', true, '/foo/bar/test.txt', null, null, true],
+ [false, 'r', '/foo/bar/test.txt', false, '/foo/bar', null, null, true],
+ [false, 'w', '/foo/bar/test.txt', true, '/foo/bar/test.txt', 8192, 0, false],
+ [true, 'r', '/foo/bar/test.txt', true, '/foo/bar/test.txt', null, null, true],
+ [true, 'r', '/foo/bar/test.txt', false, '/foo/bar', null, null, true],
+ [true, 'w', '/foo/bar/test.txt', true, '/foo/bar/test.txt', 8192, 0, false],
+ ];
}
public function testWriteRead() {
@@ -193,7 +201,7 @@ class EncryptionTest extends \Test\TestCase {
$stream = $this->getStream($fileName, 'r', 6);
$this->assertEquals('barbar', fread($stream, 100));
fclose($stream);
-
+
unlink($fileName);
}
@@ -311,7 +319,7 @@ class EncryptionTest extends \Test\TestCase {
protected function buildMockModule() {
$encryptionModule = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule')
->disableOriginalConstructor()
- ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll', 'isReadyForUser'])
+ ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll', 'isReadyForUser', 'needDetailedAccessList'])
->getMock();
$encryptionModule->expects($this->any())->method('getId')->willReturn('UNIT_TEST_MODULE');
@@ -319,6 +327,7 @@ class EncryptionTest extends \Test\TestCase {
$encryptionModule->expects($this->any())->method('begin')->willReturn([]);
$encryptionModule->expects($this->any())->method('end')->willReturn('');
$encryptionModule->expects($this->any())->method('isReadable')->willReturn(true);
+ $encryptionModule->expects($this->any())->method('needDetailedAccessList')->willReturn(false);
$encryptionModule->expects($this->any())->method('encrypt')->willReturnCallback(function($data) {
// simulate different block size by adding some padding to the data
if (isset($data[6125])) {
diff --git a/tests/lib/Traits/EncryptionTrait.php b/tests/lib/Traits/EncryptionTrait.php
index 5e2ca4e561f..8a06d37fa7f 100644
--- a/tests/lib/Traits/EncryptionTrait.php
+++ b/tests/lib/Traits/EncryptionTrait.php
@@ -64,6 +64,7 @@ trait EncryptionTrait {
/** @var Setup $userSetup */
$userSetup = $container->query('UserSetup');
$userSetup->setupUser($name, $password);
+ $this->encryptionApp->setUp();
$keyManager->init($name, $password);
}
@@ -99,6 +100,7 @@ trait EncryptionTrait {
if ($this->config) {
$this->config->setAppValue('core', 'encryption_enabled', $this->encryptionWasEnabled);
$this->config->setAppValue('core', 'default_encryption_module', $this->originalEncryptionModule);
+ $this->config->deleteAppValue('encryption', 'useMasterKey');
}
}
}