Merge pull request #15445 from owncloud/enc2_migration
add migration script from old encryption to new one
This commit is contained in:
commit
1174ad0681
29 changed files with 1204 additions and 118 deletions
|
@ -24,6 +24,8 @@
|
|||
namespace OCA\Encryption\AppInfo;
|
||||
|
||||
$app = new Application();
|
||||
$app->registerEncryptionModule();
|
||||
$app->registerHooks();
|
||||
$app->registerSettings();
|
||||
if (\OC::$server->getEncryptionManager()->isReady()) {
|
||||
$app->registerEncryptionModule();
|
||||
$app->registerHooks();
|
||||
$app->registerSettings();
|
||||
}
|
||||
|
|
|
@ -40,13 +40,10 @@ use OCP\IConfig;
|
|||
|
||||
|
||||
class Application extends \OCP\AppFramework\App {
|
||||
/**
|
||||
* @var IManager
|
||||
*/
|
||||
|
||||
/** @var IManager */
|
||||
private $encryptionManager;
|
||||
/**
|
||||
* @var IConfig
|
||||
*/
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
|
||||
/**
|
||||
|
@ -59,6 +56,10 @@ class Application extends \OCP\AppFramework\App {
|
|||
$this->registerServices();
|
||||
}
|
||||
|
||||
/**
|
||||
* register hooks
|
||||
*/
|
||||
|
||||
public function registerHooks() {
|
||||
if (!$this->config->getSystemValue('maintenance', false)) {
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
based on AES 128 or 256 bit keys. More information is available in
|
||||
the Encryption documentation
|
||||
</description>
|
||||
<name>Encryption</name>
|
||||
<name>ownCloud Default Encryption Module</name>
|
||||
<license>AGPL</license>
|
||||
<author>Bjoern Schiessle, Clark Tomlinson</author>
|
||||
<requiremin>8</requiremin>
|
||||
|
|
15
apps/encryption/appinfo/register_command.php
Normal file
15
apps/encryption/appinfo/register_command.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (c) 2015 Thomas Müller <deepdiver@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
use OCA\Encryption\Command\MigrateKeys;
|
||||
|
||||
$userManager = OC::$server->getUserManager();
|
||||
$view = new \OC\Files\View();
|
||||
$config = \OC::$server->getConfig();
|
||||
$connection = \OC::$server->getDatabaseConnection();
|
||||
$application->add(new MigrateKeys($userManager, $view, $connection, $config));
|
1
apps/encryption/appinfo/version
Normal file
1
apps/encryption/appinfo/version
Normal file
|
@ -0,0 +1 @@
|
|||
1.0.0
|
105
apps/encryption/command/migratekeys.php
Normal file
105
apps/encryption/command/migratekeys.php
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (c) 2015 Thomas Müller <thomas.mueller@tmit.eu>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
namespace OCA\Encryption\Command;
|
||||
|
||||
use OC\DB\Connection;
|
||||
use OC\Files\View;
|
||||
use OC\User\Manager;
|
||||
use OCA\Encryption\Migration;
|
||||
use OCP\IConfig;
|
||||
use OCP\IUserBackend;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class MigrateKeys extends Command {
|
||||
|
||||
/** @var \OC\User\Manager */
|
||||
private $userManager;
|
||||
|
||||
/** @var View */
|
||||
private $view;
|
||||
/** @var \OC\DB\Connection */
|
||||
private $connection;
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @param Manager $userManager
|
||||
* @param View $view
|
||||
* @param Connection $connection
|
||||
* @param IConfig $config
|
||||
*/
|
||||
public function __construct(Manager $userManager,
|
||||
View $view,
|
||||
Connection $connection,
|
||||
IConfig $config) {
|
||||
|
||||
$this->userManager = $userManager;
|
||||
$this->view = $view;
|
||||
$this->connection = $connection;
|
||||
$this->config = $config;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure() {
|
||||
$this
|
||||
->setName('encryption:migrate')
|
||||
->setDescription('initial migration to encryption 2.0')
|
||||
->addArgument(
|
||||
'user_id',
|
||||
InputArgument::OPTIONAL | InputArgument::IS_ARRAY,
|
||||
'will migrate keys of the given user(s)'
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
|
||||
// perform system reorganization
|
||||
$migration = new Migration($this->config, $this->view, $this->connection);
|
||||
|
||||
$users = $input->getArgument('user_id');
|
||||
if (!empty($users)) {
|
||||
foreach ($users as $user) {
|
||||
if ($this->userManager->userExists($user)) {
|
||||
$output->writeln("Migrating keys <info>$user</info>");
|
||||
$migration->reorganizeFolderStructureForUser($user);
|
||||
} else {
|
||||
$output->writeln("<error>Unknown user $user</error>");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$output->writeln("Reorganize system folder structure");
|
||||
$migration->reorganizeSystemFolderStructure();
|
||||
$migration->updateDB();
|
||||
foreach($this->userManager->getBackends() as $backend) {
|
||||
$name = get_class($backend);
|
||||
|
||||
if ($backend instanceof IUserBackend) {
|
||||
$name = $backend->getBackendName();
|
||||
}
|
||||
|
||||
$output->writeln("Migrating keys for users on backend <info>$name</info>");
|
||||
|
||||
$limit = 500;
|
||||
$offset = 0;
|
||||
do {
|
||||
$users = $backend->getUsers('', $limit, $offset);
|
||||
foreach ($users as $user) {
|
||||
$output->writeln(" <info>$user</info>");
|
||||
$migration->reorganizeFolderStructureForUser($user);
|
||||
}
|
||||
$offset += $limit;
|
||||
} while(count($users) >= $limit);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -142,7 +142,6 @@ class UserHooks implements IHook {
|
|||
}
|
||||
|
||||
// ensure filesystem is loaded
|
||||
// Todo: update?
|
||||
if (!\OC\Files\Filesystem::$loaded) {
|
||||
\OC_Util::setupFS($params['uid']);
|
||||
}
|
||||
|
|
|
@ -231,7 +231,7 @@ class Crypt {
|
|||
* @param string $password
|
||||
* @return bool|string
|
||||
*/
|
||||
public function decryptPrivateKey($privateKey, $password) {
|
||||
public function decryptPrivateKey($privateKey, $password = '') {
|
||||
|
||||
$header = $this->parseHeader($privateKey);
|
||||
|
||||
|
@ -273,7 +273,7 @@ class Crypt {
|
|||
* @return string
|
||||
* @throws DecryptionFailedException
|
||||
*/
|
||||
public function symmetricDecryptFileContent($keyFileContents, $passPhrase = '', $cipher = self::DEFAULT_CIPHER) {
|
||||
public function symmetricDecryptFileContent($keyFileContents, $passPhrase, $cipher = self::DEFAULT_CIPHER) {
|
||||
// Remove Padding
|
||||
$noPadding = $this->removePadding($keyFileContents);
|
||||
|
||||
|
|
|
@ -338,7 +338,7 @@ class KeyManager {
|
|||
$uid = $this->getPublicShareKeyId();
|
||||
$shareKey = $this->getShareKey($path, $uid);
|
||||
$privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey');
|
||||
$privateKey = $this->crypt->symmetricDecryptFileContent($privateKey);
|
||||
$privateKey = $this->crypt->decryptPrivateKey($privateKey);
|
||||
} else {
|
||||
$shareKey = $this->getShareKey($path, $uid);
|
||||
$privateKey = $this->session->getPrivateKey();
|
||||
|
|
319
apps/encryption/lib/migration.php
Normal file
319
apps/encryption/lib/migration.php
Normal file
|
@ -0,0 +1,319 @@
|
|||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @copyright (C) 2015 ownCloud, Inc.
|
||||
*
|
||||
* @author Bjoern Schiessle <schiessle@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library 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 library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Encryption;
|
||||
|
||||
|
||||
use OC\DB\Connection;
|
||||
use OC\Files\View;
|
||||
use OCP\IConfig;
|
||||
|
||||
class Migration {
|
||||
|
||||
private $moduleId;
|
||||
/** @var \OC\Files\View */
|
||||
private $view;
|
||||
/** @var \OC\DB\Connection */
|
||||
private $connection;
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @param IConfig $config
|
||||
* @param View $view
|
||||
* @param Connection $connection
|
||||
*/
|
||||
public function __construct(IConfig $config, View $view, Connection $connection) {
|
||||
$this->view = $view;
|
||||
$this->view->getUpdater()->disable();
|
||||
$this->connection = $connection;
|
||||
$this->moduleId = \OCA\Encryption\Crypto\Encryption::ID;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
$this->view->deleteAll('files_encryption/public_keys');
|
||||
$this->updateFileCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* update file cache, copy unencrypted_size to the 'size' column
|
||||
*/
|
||||
private function updateFileCache() {
|
||||
$query = $this->connection->createQueryBuilder();
|
||||
$query->update('`*PREFIX*filecache`')
|
||||
->set('`size`', '`unencrypted_size`')
|
||||
->where($query->expr()->eq('`encrypted`', ':encrypted'))
|
||||
->setParameter('encrypted', 1);
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* iterate through users and reorganize the folder structure
|
||||
*/
|
||||
public function reorganizeFolderStructure() {
|
||||
$this->reorganizeSystemFolderStructure();
|
||||
|
||||
$limit = 500;
|
||||
$offset = 0;
|
||||
do {
|
||||
$users = \OCP\User::getUsers('', $limit, $offset);
|
||||
foreach ($users as $user) {
|
||||
$this->reorganizeFolderStructureForUser($user);
|
||||
}
|
||||
$offset += $limit;
|
||||
} while (count($users) >= $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* reorganize system wide folder structure
|
||||
*/
|
||||
public function reorganizeSystemFolderStructure() {
|
||||
|
||||
$this->createPathForKeys('/files_encryption');
|
||||
|
||||
// backup system wide folders
|
||||
$this->backupSystemWideKeys();
|
||||
|
||||
// rename system wide mount point
|
||||
$this->renameFileKeys('', '/files_encryption/keys');
|
||||
|
||||
// rename system private keys
|
||||
$this->renameSystemPrivateKeys();
|
||||
|
||||
$storage = $this->view->getMount('')->getStorage();
|
||||
$storage->getScanner()->scan('files_encryption');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* reorganize folder structure for user
|
||||
*
|
||||
* @param string $user
|
||||
*/
|
||||
public function reorganizeFolderStructureForUser($user) {
|
||||
// backup all keys
|
||||
\OC_Util::tearDownFS();
|
||||
\OC_Util::setupFS($user);
|
||||
if ($this->backupUserKeys($user)) {
|
||||
// rename users private key
|
||||
$this->renameUsersPrivateKey($user);
|
||||
$this->renameUsersPublicKey($user);
|
||||
// rename file keys
|
||||
$path = '/files_encryption/keys';
|
||||
$this->renameFileKeys($user, $path);
|
||||
$trashPath = '/files_trashbin/keys';
|
||||
if (\OC_App::isEnabled('files_trashbin') && $this->view->is_dir($user . '/' . $trashPath)) {
|
||||
$this->renameFileKeys($user, $trashPath, true);
|
||||
$this->view->deleteAll($trashPath);
|
||||
}
|
||||
// delete old folders
|
||||
$this->deleteOldKeys($user);
|
||||
$this->view->getMount('/' . $user)->getStorage()->getScanner()->scan('files_encryption');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update database
|
||||
*/
|
||||
public function updateDB() {
|
||||
|
||||
// delete left-over from old encryption which is no longer needed
|
||||
$this->config->deleteAppValue('files_encryption', 'installed_version');
|
||||
$this->config->deleteAppValue('files_encryption', 'ocsid');
|
||||
$this->config->deleteAppValue('files_encryption', 'types');
|
||||
$this->config->deleteAppValue('files_encryption', 'enabled');
|
||||
|
||||
|
||||
$query = $this->connection->createQueryBuilder();
|
||||
$query->update('`*PREFIX*appconfig`')
|
||||
->set('`appid`', ':newappid')
|
||||
->where($query->expr()->eq('`appid`', ':oldappid'))
|
||||
->setParameter('oldappid', 'files_encryption')
|
||||
->setParameter('newappid', 'encryption');
|
||||
$query->execute();
|
||||
|
||||
$query = $this->connection->createQueryBuilder();
|
||||
$query->update('`*PREFIX*preferences`')
|
||||
->set('`appid`', ':newappid')
|
||||
->where($query->expr()->eq('`appid`', ':oldappid'))
|
||||
->setParameter('oldappid', 'files_encryption')
|
||||
->setParameter('newappid', 'encryption');
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* create backup of system-wide keys
|
||||
*/
|
||||
private function backupSystemWideKeys() {
|
||||
$backupDir = 'encryption_migration_backup_' . date("Y-m-d_H-i-s");
|
||||
$this->view->mkdir($backupDir);
|
||||
$this->view->copy('files_encryption', $backupDir . '/files_encryption');
|
||||
}
|
||||
|
||||
/**
|
||||
* create backup of user specific keys
|
||||
*
|
||||
* @param string $user
|
||||
* @return bool
|
||||
*/
|
||||
private function backupUserKeys($user) {
|
||||
$encryptionDir = $user . '/files_encryption';
|
||||
if ($this->view->is_dir($encryptionDir)) {
|
||||
$backupDir = $user . '/encryption_migration_backup_' . date("Y-m-d_H-i-s");
|
||||
$this->view->mkdir($backupDir);
|
||||
$this->view->copy($encryptionDir, $backupDir);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* rename system-wide private keys
|
||||
*/
|
||||
private function renameSystemPrivateKeys() {
|
||||
$dh = $this->view->opendir('files_encryption');
|
||||
$this->createPathForKeys('/files_encryption/' . $this->moduleId );
|
||||
if (is_resource($dh)) {
|
||||
while (($privateKey = readdir($dh)) !== false) {
|
||||
if (!\OC\Files\Filesystem::isIgnoredDir($privateKey) ) {
|
||||
if (!$this->view->is_dir('/files_encryption/' . $privateKey)) {
|
||||
$this->view->rename('files_encryption/' . $privateKey, 'files_encryption/' . $this->moduleId . '/' . $privateKey);
|
||||
$this->renameSystemPublicKey($privateKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($dh);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* rename system wide public key
|
||||
*
|
||||
* @param $privateKey private key for which we want to rename the corresponding public key
|
||||
*/
|
||||
private function renameSystemPublicKey($privateKey) {
|
||||
$publicKey = substr($privateKey,0 , strrpos($privateKey, '.privateKey')) . '.publicKey';
|
||||
$this->view->rename('files_encryption/public_keys/' . $publicKey, 'files_encryption/' . $this->moduleId . '/' . $publicKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* rename user-specific private keys
|
||||
*
|
||||
* @param string $user
|
||||
*/
|
||||
private function renameUsersPrivateKey($user) {
|
||||
$oldPrivateKey = $user . '/files_encryption/' . $user . '.privateKey';
|
||||
$newPrivateKey = $user . '/files_encryption/' . $this->moduleId . '/' . $user . '.privateKey';
|
||||
$this->createPathForKeys(dirname($newPrivateKey));
|
||||
|
||||
$this->view->rename($oldPrivateKey, $newPrivateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* rename user-specific public keys
|
||||
*
|
||||
* @param string $user
|
||||
*/
|
||||
private function renameUsersPublicKey($user) {
|
||||
$oldPublicKey = '/files_encryption/public_keys/' . $user . '.publicKey';
|
||||
$newPublicKey = $user . '/files_encryption/' . $this->moduleId . '/' . $user . '.publicKey';
|
||||
$this->createPathForKeys(dirname($newPublicKey));
|
||||
|
||||
$this->view->rename($oldPublicKey, $newPublicKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* rename file keys
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $path
|
||||
* @param bool $trash
|
||||
*/
|
||||
private function renameFileKeys($user, $path, $trash = false) {
|
||||
|
||||
$dh = $this->view->opendir($user . '/' . $path);
|
||||
|
||||
if (is_resource($dh)) {
|
||||
while (($file = readdir($dh)) !== false) {
|
||||
if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
|
||||
if ($this->view->is_dir($user . '/' . $path . '/' . $file)) {
|
||||
$this->renameFileKeys($user, $path . '/' . $file, $trash);
|
||||
} else {
|
||||
$target = $this->getTargetDir($user, $path, $file, $trash);
|
||||
$this->createPathForKeys(dirname($target));
|
||||
$this->view->rename($user . '/' . $path . '/' . $file, $target);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($dh);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* generate target directory
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $filePath
|
||||
* @param string $filename
|
||||
* @param bool $trash
|
||||
* @return string
|
||||
*/
|
||||
private function getTargetDir($user, $filePath, $filename, $trash) {
|
||||
if ($trash) {
|
||||
$targetDir = $user . '/files_encryption/keys/files_trashbin/' . substr($filePath, strlen('/files_trashbin/keys/')) . '/' . $this->moduleId . '/' . $filename;
|
||||
} else {
|
||||
$targetDir = $user . '/files_encryption/keys/files/' . substr($filePath, strlen('/files_encryption/keys/')) . '/' . $this->moduleId . '/' . $filename;
|
||||
}
|
||||
|
||||
return $targetDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* delete old keys
|
||||
*
|
||||
* @param string $user
|
||||
*/
|
||||
private function deleteOldKeys($user) {
|
||||
$this->view->deleteAll($user . '/files_encryption/keyfiles');
|
||||
$this->view->deleteAll($user . '/files_encryption/share-keys');
|
||||
}
|
||||
|
||||
/**
|
||||
* create directories for the keys recursively
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
private function createPathForKeys($path) {
|
||||
if (!$this->view->file_exists($path)) {
|
||||
$sub_dirs = explode('/', $path);
|
||||
$dir = '';
|
||||
foreach ($sub_dirs as $sub_dir) {
|
||||
$dir .= '/' . $sub_dir;
|
||||
if (!$this->view->is_dir($dir)) {
|
||||
$this->view->mkdir($dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -268,7 +268,7 @@ class KeyManagerTest extends TestCase {
|
|||
->willReturn(true);
|
||||
|
||||
$this->cryptMock->expects($this->once())
|
||||
->method('symmetricDecryptFileContent')
|
||||
->method('decryptPrivateKey')
|
||||
->willReturn(true);
|
||||
|
||||
$this->cryptMock->expects($this->once())
|
||||
|
|
356
apps/encryption/tests/lib/MigrationTest.php
Normal file
356
apps/encryption/tests/lib/MigrationTest.php
Normal file
|
@ -0,0 +1,356 @@
|
|||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @copyright (C) 2015 ownCloud, Inc.
|
||||
*
|
||||
* @author Bjoern Schiessle <schiessle@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library 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 library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Encryption\Tests;
|
||||
|
||||
use OCA\Encryption\Migration;
|
||||
|
||||
class MigrationTest extends \Test\TestCase {
|
||||
|
||||
const TEST_ENCRYPTION_MIGRATION_USER1='test_encryption_user1';
|
||||
const TEST_ENCRYPTION_MIGRATION_USER2='test_encryption_user2';
|
||||
const TEST_ENCRYPTION_MIGRATION_USER3='test_encryption_user3';
|
||||
|
||||
/** @var \OC\Files\View */
|
||||
private $view;
|
||||
private $public_share_key_id = 'share_key_id';
|
||||
private $recovery_key_id = 'recovery_key_id';
|
||||
private $moduleId;
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
parent::setUpBeforeClass();
|
||||
\OC_User::createUser(self::TEST_ENCRYPTION_MIGRATION_USER1, 'foo');
|
||||
\OC_User::createUser(self::TEST_ENCRYPTION_MIGRATION_USER2, 'foo');
|
||||
\OC_User::createUser(self::TEST_ENCRYPTION_MIGRATION_USER3, 'foo');
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
\OC_User::deleteUser(self::TEST_ENCRYPTION_MIGRATION_USER1);
|
||||
\OC_User::deleteUser(self::TEST_ENCRYPTION_MIGRATION_USER2);
|
||||
\OC_User::deleteUser(self::TEST_ENCRYPTION_MIGRATION_USER3);
|
||||
parent::tearDownAfterClass();
|
||||
}
|
||||
|
||||
|
||||
public function setUp() {
|
||||
$this->view = new \OC\Files\View();
|
||||
$this->moduleId = \OCA\Encryption\Crypto\Encryption::ID;
|
||||
}
|
||||
|
||||
protected function createDummyShareKeys($uid) {
|
||||
$this->view->mkdir($uid . '/files_encryption/keys/folder1/folder2/folder3/file3');
|
||||
$this->view->mkdir($uid . '/files_encryption/keys/folder1/folder2/file2');
|
||||
$this->view->mkdir($uid . '/files_encryption/keys/folder1/file.1');
|
||||
$this->view->mkdir($uid . '/files_encryption/keys/folder2/file.2.1');
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder1/folder2/folder3/file3/' . self::TEST_ENCRYPTION_MIGRATION_USER1 . '.shareKey' , 'data');
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder1/folder2/folder3/file3/' . self::TEST_ENCRYPTION_MIGRATION_USER2 . '.shareKey' , 'data');
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder1/folder2/folder3/file3/' . self::TEST_ENCRYPTION_MIGRATION_USER3 . '.shareKey' , 'data');
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder1/folder2/file2/' . self::TEST_ENCRYPTION_MIGRATION_USER1 . '.shareKey' , 'data');
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder1/folder2/file2/' . self::TEST_ENCRYPTION_MIGRATION_USER2 . '.shareKey' , 'data');
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder1/folder2/file2/' . self::TEST_ENCRYPTION_MIGRATION_USER3 . '.shareKey' , 'data');
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder1/file.1/' . self::TEST_ENCRYPTION_MIGRATION_USER1 . '.shareKey' , 'data');
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder1/file.1/' . self::TEST_ENCRYPTION_MIGRATION_USER2 . '.shareKey' , 'data');
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder1/file.1/' . self::TEST_ENCRYPTION_MIGRATION_USER3 . '.shareKey' , 'data');
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder2/file.2.1/' . self::TEST_ENCRYPTION_MIGRATION_USER1 . '.shareKey' , 'data');
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder2/file.2.1/' . self::TEST_ENCRYPTION_MIGRATION_USER2 . '.shareKey' , 'data');
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder2/file.2.1/' . self::TEST_ENCRYPTION_MIGRATION_USER3 . '.shareKey' , 'data');
|
||||
if ($this->public_share_key_id) {
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder2/file.2.1/' . $this->public_share_key_id . '.shareKey' , 'data');
|
||||
}
|
||||
if ($this->recovery_key_id) {
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder2/file.2.1/' . $this->recovery_key_id . '.shareKey' , 'data');
|
||||
}
|
||||
}
|
||||
|
||||
protected function createDummyUserKeys($uid) {
|
||||
$this->view->mkdir($uid . '/files_encryption/');
|
||||
$this->view->mkdir('/files_encryption/public_keys');
|
||||
$this->view->file_put_contents($uid . '/files_encryption/' . $uid . '.privateKey', 'privateKey');
|
||||
$this->view->file_put_contents('/files_encryption/public_keys/' . $uid . '.publicKey', 'publicKey');
|
||||
}
|
||||
|
||||
protected function createDummyFileKeys($uid) {
|
||||
$this->view->mkdir($uid . '/files_encryption/keys/folder1/folder2/folder3/file3');
|
||||
$this->view->mkdir($uid . '/files_encryption/keys/folder1/folder2/file2');
|
||||
$this->view->mkdir($uid . '/files_encryption/keys/folder1/file.1');
|
||||
$this->view->mkdir($uid . '/files_encryption/keys/folder2/file.2.1');
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder1/folder2/folder3/file3/fileKey' , 'data');
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder1/folder2/file2/fileKey' , 'data');
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder1/file.1/fileKey' , 'data');
|
||||
$this->view->file_put_contents($uid . '/files_encryption/keys/folder2/file.2.1/fileKey' , 'data');
|
||||
}
|
||||
|
||||
protected function createDummyFilesInTrash($uid) {
|
||||
$this->view->mkdir($uid . '/files_trashbin/keys/file1.d5457864');
|
||||
$this->view->mkdir($uid . '/files_trashbin/keys/folder1.d7437648723/file2');
|
||||
$this->view->file_put_contents($uid . '/files_trashbin/keys/file1.d5457864/' . self::TEST_ENCRYPTION_MIGRATION_USER1 . '.shareKey' , 'data');
|
||||
$this->view->file_put_contents($uid . '/files_trashbin/keys/file1.d5457864/' . self::TEST_ENCRYPTION_MIGRATION_USER1 . '.shareKey' , 'data');
|
||||
$this->view->file_put_contents($uid . '/files_trashbin/keys/folder1.d7437648723/file2/' . self::TEST_ENCRYPTION_MIGRATION_USER1 . '.shareKey' , 'data');
|
||||
|
||||
$this->view->file_put_contents($uid . '/files_trashbin/keys/file1.d5457864/fileKey' , 'data');
|
||||
$this->view->file_put_contents($uid . '/files_trashbin/keys/folder1.d7437648723/file2/fileKey' , 'data');
|
||||
}
|
||||
|
||||
protected function createDummySystemWideKeys() {
|
||||
$this->view->mkdir('files_encryption');
|
||||
$this->view->mkdir('files_encryption/public_keys');
|
||||
$this->view->file_put_contents('files_encryption/systemwide_1.privateKey', 'data');
|
||||
$this->view->file_put_contents('files_encryption/systemwide_2.privateKey', 'data');
|
||||
$this->view->file_put_contents('files_encryption/public_keys/systemwide_1.publicKey', 'data');
|
||||
$this->view->file_put_contents('files_encryption/public_keys/systemwide_2.publicKey', 'data');
|
||||
|
||||
}
|
||||
|
||||
public function testMigrateToNewFolderStructure() {
|
||||
$this->createDummyUserKeys(self::TEST_ENCRYPTION_MIGRATION_USER1);
|
||||
$this->createDummyUserKeys(self::TEST_ENCRYPTION_MIGRATION_USER2);
|
||||
$this->createDummyUserKeys(self::TEST_ENCRYPTION_MIGRATION_USER3);
|
||||
|
||||
$this->createDummyShareKeys(self::TEST_ENCRYPTION_MIGRATION_USER1);
|
||||
$this->createDummyShareKeys(self::TEST_ENCRYPTION_MIGRATION_USER2);
|
||||
$this->createDummyShareKeys(self::TEST_ENCRYPTION_MIGRATION_USER3);
|
||||
|
||||
$this->createDummyFileKeys(self::TEST_ENCRYPTION_MIGRATION_USER1);
|
||||
$this->createDummyFileKeys(self::TEST_ENCRYPTION_MIGRATION_USER2);
|
||||
$this->createDummyFileKeys(self::TEST_ENCRYPTION_MIGRATION_USER3);
|
||||
|
||||
$this->createDummyFilesInTrash(self::TEST_ENCRYPTION_MIGRATION_USER2);
|
||||
|
||||
// no user for system wide mount points
|
||||
$this->createDummyFileKeys('');
|
||||
$this->createDummyShareKeys('');
|
||||
|
||||
$this->createDummySystemWideKeys();
|
||||
|
||||
$m = new Migration(\OC::$server->getConfig(), new \OC\Files\View(), \OC::$server->getDatabaseConnection());
|
||||
$m->reorganizeFolderStructure();
|
||||
|
||||
$this->assertTrue(
|
||||
$this->view->file_exists(
|
||||
self::TEST_ENCRYPTION_MIGRATION_USER1 . '/files_encryption/' .
|
||||
$this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER1 . '.publicKey')
|
||||
);
|
||||
$this->assertTrue(
|
||||
$this->view->file_exists(
|
||||
self::TEST_ENCRYPTION_MIGRATION_USER2 . '/files_encryption/' .
|
||||
$this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER2 . '.publicKey')
|
||||
);
|
||||
$this->assertTrue(
|
||||
$this->view->file_exists(
|
||||
self::TEST_ENCRYPTION_MIGRATION_USER3 . '/files_encryption/' .
|
||||
$this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER3 . '.publicKey')
|
||||
);
|
||||
$this->assertTrue(
|
||||
$this->view->file_exists(
|
||||
'/files_encryption/' . $this->moduleId . '/systemwide_1.publicKey')
|
||||
);
|
||||
$this->assertTrue(
|
||||
$this->view->file_exists(
|
||||
'/files_encryption/' . $this->moduleId . '/systemwide_2.publicKey')
|
||||
);
|
||||
|
||||
$this->verifyNewKeyPath(self::TEST_ENCRYPTION_MIGRATION_USER1);
|
||||
$this->verifyNewKeyPath(self::TEST_ENCRYPTION_MIGRATION_USER2);
|
||||
$this->verifyNewKeyPath(self::TEST_ENCRYPTION_MIGRATION_USER3);
|
||||
// system wide keys
|
||||
$this->verifyNewKeyPath('');
|
||||
// trash
|
||||
$this->verifyFilesInTrash(self::TEST_ENCRYPTION_MIGRATION_USER2);
|
||||
|
||||
}
|
||||
|
||||
protected function verifyFilesInTrash($uid) {
|
||||
// share keys
|
||||
$this->assertTrue(
|
||||
$this->view->file_exists($uid . '/files_encryption/keys/files_trashbin/file1.d5457864/' . $this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER1 . '.shareKey')
|
||||
);
|
||||
$this->assertTrue(
|
||||
$this->view->file_exists($uid . '/files_encryption/keys/files_trashbin/file1.d5457864/' . $this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER1 . '.shareKey')
|
||||
);
|
||||
$this->assertTrue(
|
||||
$this->view->file_exists($uid . '/files_encryption/keys/files_trashbin/folder1.d7437648723/file2/' . $this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER1 . '.shareKey')
|
||||
);
|
||||
|
||||
// file keys
|
||||
$this->assertTrue(
|
||||
$this->view->file_exists($uid . '/files_encryption/keys/files_trashbin/file1.d5457864/' . $this->moduleId . '/fileKey')
|
||||
);
|
||||
|
||||
$this->assertTrue(
|
||||
$this->view->file_exists($uid . '/files_encryption/keys/files_trashbin/file1.d5457864/' . $this->moduleId . '/fileKey')
|
||||
);
|
||||
$this->assertTrue(
|
||||
$this->view->file_exists($uid . '/files_encryption/keys/files_trashbin/folder1.d7437648723/file2/' . $this->moduleId . '/fileKey')
|
||||
);
|
||||
}
|
||||
|
||||
protected function verifyNewKeyPath($uid) {
|
||||
// private key
|
||||
if ($uid !== '') {
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/' . $this->moduleId . '/'. $uid . '.privateKey'));
|
||||
}
|
||||
// file keys
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder1/folder2/folder3/file3/' . $this->moduleId . '/fileKey'));
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder1/folder2/file2/' . $this->moduleId . '/fileKey'));
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder1/file.1/' . $this->moduleId . '/fileKey'));
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder2/file.2.1/' .$this->moduleId . '/fileKey'));
|
||||
// share keys
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder1/folder2/folder3/file3/' . $this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER1 . '.shareKey'));
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder1/folder2/folder3/file3/' . $this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER2 . '.shareKey'));
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder1/folder2/folder3/file3/' . $this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER3 . '.shareKey'));
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder1/folder2/file2/' . $this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER1 . '.shareKey'));
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder1/folder2/file2/' . $this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER2 . '.shareKey'));
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder1/folder2/file2/' . $this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER3 . '.shareKey'));
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder1/file.1/' . $this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER1 . '.shareKey'));
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder1/file.1/' . $this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER2 . '.shareKey'));
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder1/file.1/' . $this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER3 . '.shareKey'));
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder2/file.2.1/' . $this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER1 . '.shareKey'));
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder2/file.2.1/' . $this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER2 . '.shareKey'));
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder2/file.2.1/' . $this->moduleId . '/' . self::TEST_ENCRYPTION_MIGRATION_USER3 . '.shareKey'));
|
||||
if ($this->public_share_key_id) {
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder2/file.2.1/' . $this->moduleId . '/' . $this->public_share_key_id . '.shareKey'));
|
||||
}
|
||||
if ($this->recovery_key_id) {
|
||||
$this->assertTrue($this->view->file_exists($uid . '/files_encryption/keys/files/folder2/file.2.1/' . $this->moduleId . '/' . $this->recovery_key_id . '.shareKey'));
|
||||
}
|
||||
}
|
||||
|
||||
private function prepareDB() {
|
||||
$config = \OC::$server->getConfig();
|
||||
$config->setAppValue('files_encryption', 'recoveryKeyId', 'recovery_id');
|
||||
$config->setAppValue('files_encryption', 'publicShareKeyId', 'share_id');
|
||||
$config->setAppValue('files_encryption', 'recoveryAdminEnabled', '1');
|
||||
$config->setUserValue(self::TEST_ENCRYPTION_MIGRATION_USER1, 'files_encryption', 'recoverKeyEnabled', '1');
|
||||
|
||||
// delete default values set by the encryption app during initialization
|
||||
|
||||
/** @var \OC\DB\Connection $connection */
|
||||
$connection = \OC::$server->getDatabaseConnection();
|
||||
$query = $connection->createQueryBuilder();
|
||||
$query->delete('`*PREFIX*appconfig`')
|
||||
->where($query->expr()->eq('`appid`', ':appid'))
|
||||
->setParameter('appid', 'encryption');
|
||||
$query->execute();
|
||||
$query = $connection->createQueryBuilder();
|
||||
$query->delete('`*PREFIX*preferences`')
|
||||
->where($query->expr()->eq('`appid`', ':appid'))
|
||||
->setParameter('appid', 'encryption');
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
public function testUpdateDB() {
|
||||
$this->prepareDB();
|
||||
|
||||
$m = new Migration(\OC::$server->getConfig(), new \OC\Files\View(), \OC::$server->getDatabaseConnection());
|
||||
$m->updateDB();
|
||||
|
||||
$this->verifyDB('`*PREFIX*appconfig`', 'files_encryption', 0);
|
||||
$this->verifyDB('`*PREFIX*preferences`', 'files_encryption', 0);
|
||||
$this->verifyDB('`*PREFIX*appconfig`', 'encryption', 3);
|
||||
$this->verifyDB('`*PREFIX*preferences`', 'encryption', 1);
|
||||
|
||||
}
|
||||
|
||||
public function verifyDB($table, $appid, $expected) {
|
||||
/** @var \OC\DB\Connection $connection */
|
||||
$connection = \OC::$server->getDatabaseConnection();
|
||||
$query = $connection->createQueryBuilder();
|
||||
$query->select('`appid`')
|
||||
->from($table)
|
||||
->where($query->expr()->eq('`appid`', ':appid'))
|
||||
->setParameter('appid', $appid);
|
||||
$result = $query->execute();
|
||||
$values = $result->fetchAll();
|
||||
$this->assertSame($expected,
|
||||
count($values)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* test update of the file cache
|
||||
*/
|
||||
public function testUpdateFileCache() {
|
||||
$this->prepareFileCache();
|
||||
$m = new Migration(\OC::$server->getConfig(), new \OC\Files\View(), \OC::$server->getDatabaseConnection());
|
||||
\Test_Helper::invokePrivate($m, 'updateFileCache');
|
||||
|
||||
// check results
|
||||
|
||||
/** @var \OC\DB\Connection $connection */
|
||||
$connection = \OC::$server->getDatabaseConnection();
|
||||
$query = $connection->createQueryBuilder();
|
||||
$query->select('*')
|
||||
->from('`*PREFIX*filecache`');
|
||||
$result = $query->execute();
|
||||
$entries = $result->fetchAll();
|
||||
foreach($entries as $entry) {
|
||||
if ((int)$entry['encrypted'] === 1) {
|
||||
$this->assertSame((int)$entry['unencrypted_size'], (int)$entry['size']);
|
||||
} else {
|
||||
$this->assertSame((int)$entry['unencrypted_size'] - 2, (int)$entry['size']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function prepareFileCache() {
|
||||
/** @var \OC\DB\Connection $connection */
|
||||
$connection = \OC::$server->getDatabaseConnection();
|
||||
$query = $connection->createQueryBuilder();
|
||||
$query->delete('`*PREFIX*filecache`');
|
||||
$query->execute();
|
||||
$query = $connection->createQueryBuilder();
|
||||
$result = $query->select('`fileid`')
|
||||
->from('`*PREFIX*filecache`')
|
||||
->setMaxResults(1)->execute()->fetchAll();
|
||||
$this->assertEmpty($result);
|
||||
$query = $connection->createQueryBuilder();
|
||||
$query->insert('`*PREFIX*filecache`')
|
||||
->values(
|
||||
array(
|
||||
'`storage`' => ':storage',
|
||||
'`path_hash`' => ':path_hash',
|
||||
'`encrypted`' => ':encrypted',
|
||||
'`size`' => ':size',
|
||||
'`unencrypted_size`' => ':unencrypted_size'
|
||||
)
|
||||
);
|
||||
for ($i = 1; $i < 20; $i++) {
|
||||
$query->setParameter('storage', 1)
|
||||
->setParameter('path_hash', $i)
|
||||
->setParameter('encrypted', $i % 2)
|
||||
->setParameter('size', $i)
|
||||
->setParameter('unencrypted_size', $i + 2);
|
||||
$this->assertSame(1,
|
||||
$query->execute()
|
||||
);
|
||||
}
|
||||
$query = $connection->createQueryBuilder();
|
||||
$result = $query->select('`fileid`')
|
||||
->from('`*PREFIX*filecache`')
|
||||
->execute()->fetchAll();
|
||||
$this->assertSame(19, count($result));
|
||||
}
|
||||
|
||||
}
|
|
@ -728,6 +728,7 @@ class OC {
|
|||
new \OC\Encryption\Util(
|
||||
new \OC\Files\View(),
|
||||
\OC::$server->getUserManager(),
|
||||
\OC::$server->getGroupManager(),
|
||||
\OC::$server->getConfig()),
|
||||
\OC\Files\Filesystem::getMountManager(),
|
||||
\OC::$server->getEncryptionManager(),
|
||||
|
|
|
@ -266,7 +266,7 @@ class Storage implements \OCP\Encryption\Keys\IStorage {
|
|||
$filename = $this->util->stripPartialFileExtension($filename);
|
||||
|
||||
// in case of system wide mount points the keys are stored directly in the data directory
|
||||
if ($this->util->isSystemWideMountPoint($filename)) {
|
||||
if ($this->util->isSystemWideMountPoint($filename, $owner)) {
|
||||
$keyPath = $this->keys_base_dir . $filename . '/';
|
||||
} else {
|
||||
$keyPath = '/' . $owner . $this->keys_base_dir . $filename . '/';
|
||||
|
@ -287,7 +287,7 @@ class Storage implements \OCP\Encryption\Keys\IStorage {
|
|||
|
||||
list($owner, $source) = $this->util->getUidAndFilename($source);
|
||||
list(, $target) = $this->util->getUidAndFilename($target);
|
||||
$systemWide = $this->util->isSystemWideMountPoint($target);
|
||||
$systemWide = $this->util->isSystemWideMountPoint($target, $owner);
|
||||
|
||||
if ($systemWide) {
|
||||
$sourcePath = $this->keys_base_dir . $source . '/';
|
||||
|
@ -315,7 +315,7 @@ class Storage implements \OCP\Encryption\Keys\IStorage {
|
|||
|
||||
list($owner, $source) = $this->util->getUidAndFilename($source);
|
||||
list(, $target) = $this->util->getUidAndFilename($target);
|
||||
$systemWide = $this->util->isSystemWideMountPoint($target);
|
||||
$systemWide = $this->util->isSystemWideMountPoint($target, $owner);
|
||||
|
||||
if ($systemWide) {
|
||||
$sourcePath = $this->keys_base_dir . $source . '/';
|
||||
|
|
|
@ -22,24 +22,34 @@
|
|||
|
||||
namespace OC\Encryption;
|
||||
|
||||
use OC\Files\Storage\Shared;
|
||||
use OC\Files\Storage\Wrapper\Encryption;
|
||||
use OC\Files\View;
|
||||
use OCP\Encryption\IEncryptionModule;
|
||||
use OCP\Encryption\IManager;
|
||||
use OCP\Files\Mount\IMountPoint;
|
||||
use OCP\IConfig;
|
||||
use OCP\ILogger;
|
||||
|
||||
class Manager implements \OCP\Encryption\IManager {
|
||||
class Manager implements IManager {
|
||||
|
||||
/** @var array */
|
||||
protected $encryptionModules;
|
||||
|
||||
/** @var \OCP\IConfig */
|
||||
/** @var IConfig */
|
||||
protected $config;
|
||||
|
||||
/** @var ILogger */
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* @param \OCP\IConfig $config
|
||||
* @param IConfig $config
|
||||
* @param ILogger $logger
|
||||
*/
|
||||
public function __construct(\OCP\IConfig $config) {
|
||||
public function __construct(IConfig $config, ILogger $logger) {
|
||||
$this->encryptionModules = array();
|
||||
$this->config = $config;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,6 +68,24 @@ class Manager implements \OCP\Encryption\IManager {
|
|||
return $enabled === 'yes';
|
||||
}
|
||||
|
||||
/**
|
||||
* check if new encryption is ready
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isReady() {
|
||||
// check if we are still in transit between the old and the new encryption
|
||||
$oldEncryption = $this->config->getAppValue('files_encryption', 'installed_version');
|
||||
if (!empty($oldEncryption)) {
|
||||
$warning = 'Installation is in transit between the old Encryption (ownCloud <= 8.0)
|
||||
and the new encryption. Please enable the "ownCloud Default Encryption Module"
|
||||
and run \'occ encryption:migrate\'';
|
||||
$this->logger->warning($warning);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an encryption module
|
||||
*
|
||||
|
@ -185,10 +213,14 @@ class Manager implements \OCP\Encryption\IManager {
|
|||
'mountPoint' => $mountPoint,
|
||||
'mount' => $mount];
|
||||
|
||||
if (!($storage instanceof \OC\Files\Storage\Shared)) {
|
||||
if (!($storage instanceof Shared)) {
|
||||
$manager = \OC::$server->getEncryptionManager();
|
||||
$util = new \OC\Encryption\Util(
|
||||
new \OC\Files\View(), \OC::$server->getUserManager(), \OC::$server->getConfig());
|
||||
$util = new Util(
|
||||
new View(),
|
||||
\OC::$server->getUserManager(),
|
||||
\OC::$server->getGroupManager(),
|
||||
\OC::$server->getConfig()
|
||||
);
|
||||
$user = \OC::$server->getUserSession()->getUser();
|
||||
$logger = \OC::$server->getLogger();
|
||||
$uid = $user ? $user->getUID() : null;
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace OC\Encryption;
|
|||
|
||||
use OC\Encryption\Exceptions\EncryptionHeaderKeyExistsException;
|
||||
use OC\Encryption\Exceptions\EncryptionHeaderToLargeException;
|
||||
use OC\Encryption\Exceptions\ModuleDoesNotExistsException;
|
||||
use OC\Files\View;
|
||||
use OCP\Encryption\IEncryptionModule;
|
||||
use OCP\IConfig;
|
||||
|
@ -65,15 +66,20 @@ class Util {
|
|||
/** @var array paths excluded from encryption */
|
||||
protected $excludedPaths;
|
||||
|
||||
/** @var \OC\Group\Manager $manager */
|
||||
protected $groupManager;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param \OC\Files\View $view
|
||||
* @param \OC\User\Manager $userManager
|
||||
* @param \OC\Group\Manager $groupManager
|
||||
* @param IConfig $config
|
||||
*/
|
||||
public function __construct(
|
||||
\OC\Files\View $view,
|
||||
\OC\User\Manager $userManager,
|
||||
\OC\Group\Manager $groupManager,
|
||||
IConfig $config) {
|
||||
|
||||
$this->ocHeaderKeys = [
|
||||
|
@ -82,6 +88,7 @@ class Util {
|
|||
|
||||
$this->view = $view;
|
||||
$this->userManager = $userManager;
|
||||
$this->groupManager = $groupManager;
|
||||
$this->config = $config;
|
||||
|
||||
$this->excludedPaths[] = 'files_encryption';
|
||||
|
@ -92,6 +99,7 @@ class Util {
|
|||
*
|
||||
* @param array $header
|
||||
* @return string
|
||||
* @throws ModuleDoesNotExistsException
|
||||
*/
|
||||
public function getEncryptionModuleId(array $header = null) {
|
||||
$id = '';
|
||||
|
@ -99,6 +107,14 @@ class Util {
|
|||
|
||||
if (isset($header[$encryptionModuleKey])) {
|
||||
$id = $header[$encryptionModuleKey];
|
||||
} elseif (isset($header['cipher'])) {
|
||||
if (class_exists('\OCA\Encryption\Crypto\Encryption')) {
|
||||
// fall back to default encryption if the user migrated from
|
||||
// ownCloud <= 8.0 with the old encryption
|
||||
$id = \OCA\Encryption\Crypto\Encryption::ID;
|
||||
} else {
|
||||
throw new ModuleDoesNotExistsException('ownCloud default encryption module missing');
|
||||
}
|
||||
}
|
||||
|
||||
return $id;
|
||||
|
@ -294,15 +310,15 @@ class Util {
|
|||
/**
|
||||
* check if the file is stored on a system wide mount point
|
||||
* @param string $path relative to /data/user with leading '/'
|
||||
* @param string $uid
|
||||
* @return boolean
|
||||
*/
|
||||
public function isSystemWideMountPoint($path) {
|
||||
$normalizedPath = ltrim($path, '/');
|
||||
public function isSystemWideMountPoint($path, $uid) {
|
||||
if (\OCP\App::isEnabled("files_external")) {
|
||||
$mounts = \OC_Mount_Config::getSystemMountPoints();
|
||||
foreach ($mounts as $mount) {
|
||||
if ($mount['mountpoint'] == substr($normalizedPath, 0, strlen($mount['mountpoint']))) {
|
||||
if ($this->isMountPointApplicableToUser($mount)) {
|
||||
if (strpos($path, '/files/' . $mount['mountpoint']) === 0) {
|
||||
if ($this->isMountPointApplicableToUser($mount, $uid)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -311,6 +327,29 @@ class Util {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if mount point is applicable to user
|
||||
*
|
||||
* @param array $mount contains $mount['applicable']['users'], $mount['applicable']['groups']
|
||||
* @param string $uid
|
||||
* @return boolean
|
||||
*/
|
||||
private function isMountPointApplicableToUser($mount, $uid) {
|
||||
$acceptedUids = array('all', $uid);
|
||||
// check if mount point is applicable for the user
|
||||
$intersection = array_intersect($acceptedUids, $mount['applicable']['users']);
|
||||
if (!empty($intersection)) {
|
||||
return true;
|
||||
}
|
||||
// check if mount point is applicable for group where the user is a member
|
||||
foreach ($mount['applicable']['groups'] as $gid) {
|
||||
if ($this->groupManager->isInGroup($uid, $gid)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if it is a path which is excluded by ownCloud from encryption
|
||||
*
|
||||
|
|
|
@ -154,7 +154,8 @@ class Encryption extends Wrapper {
|
|||
* @return bool
|
||||
*/
|
||||
public function unlink($path) {
|
||||
if ($this->util->isExcluded($path)) {
|
||||
$fullPath = $this->getFullPath($path);
|
||||
if ($this->util->isExcluded($fullPath)) {
|
||||
return $this->storage->unlink($path);
|
||||
}
|
||||
|
||||
|
@ -175,7 +176,8 @@ class Encryption extends Wrapper {
|
|||
* @return bool
|
||||
*/
|
||||
public function rename($path1, $path2) {
|
||||
if ($this->util->isExcluded($path1)) {
|
||||
$fullPath1 = $this->getFullPath($path1);
|
||||
if ($this->util->isExcluded($fullPath1)) {
|
||||
return $this->storage->rename($path1, $path2);
|
||||
}
|
||||
|
||||
|
@ -204,8 +206,9 @@ class Encryption extends Wrapper {
|
|||
* @return bool
|
||||
*/
|
||||
public function copy($path1, $path2) {
|
||||
if ($this->util->isExcluded($path1)) {
|
||||
return $this->storage->rename($path1, $path2);
|
||||
$fullPath1 = $this->getFullPath($path1);
|
||||
if ($this->util->isExcluded($fullPath1)) {
|
||||
return $this->storage->copy($path1, $path2);
|
||||
}
|
||||
|
||||
$source = $this->getFullPath($path1);
|
||||
|
|
|
@ -280,7 +280,7 @@ class Encryption extends Wrapper {
|
|||
|
||||
if ($this->position === 0) {
|
||||
$this->writeHeader();
|
||||
$this->size+=$this->util->getHeaderSize();
|
||||
$this->size = $this->util->getHeaderSize();
|
||||
}
|
||||
|
||||
$length = 0;
|
||||
|
@ -293,7 +293,7 @@ class Encryption extends Wrapper {
|
|||
|
||||
// for seekable streams the pointer is moved back to the beginning of the encrypted block
|
||||
// flush will start writing there when the position moves to another block
|
||||
$positionInFile = floor($this->position / $this->unencryptedBlockSize) *
|
||||
$positionInFile = (int)floor($this->position / $this->unencryptedBlockSize) *
|
||||
$this->util->getBlockSize() + $this->util->getHeaderSize();
|
||||
$resultFseek = parent::stream_seek($positionInFile);
|
||||
|
||||
|
|
|
@ -84,11 +84,16 @@ class Server extends SimpleContainer implements IServerContainer {
|
|||
});
|
||||
|
||||
$this->registerService('EncryptionManager', function (Server $c) {
|
||||
return new Encryption\Manager($c->getConfig());
|
||||
return new Encryption\Manager($c->getConfig(), $c->getLogger());
|
||||
});
|
||||
|
||||
$this->registerService('EncryptionFileHelper', function (Server $c) {
|
||||
$util = new \OC\Encryption\Util(new \OC\Files\View(), $c->getUserManager(), $c->getConfig());
|
||||
$util = new \OC\Encryption\Util(
|
||||
new \OC\Files\View(),
|
||||
$c->getUserManager(),
|
||||
$c->getGroupManager(),
|
||||
$c->getConfig()
|
||||
);
|
||||
return new Encryption\File($util);
|
||||
});
|
||||
|
||||
|
@ -437,7 +442,12 @@ class Server extends SimpleContainer implements IServerContainer {
|
|||
*/
|
||||
function getEncryptionKeyStorage($encryptionModuleId) {
|
||||
$view = new \OC\Files\View();
|
||||
$util = new \OC\Encryption\Util($view, \OC::$server->getUserManager(), \OC::$server->getConfig());
|
||||
$util = new \OC\Encryption\Util(
|
||||
$view,
|
||||
\OC::$server->getUserManager(),
|
||||
\OC::$server->getGroupManager(),
|
||||
\OC::$server->getConfig()
|
||||
);
|
||||
return $this->query('EncryptionKeyStorageFactory')->get($encryptionModuleId, $view, $util);
|
||||
}
|
||||
|
||||
|
|
|
@ -82,7 +82,12 @@ $excludedGroupsList = $appConfig->getValue('core', 'shareapi_exclude_groups_list
|
|||
$excludedGroupsList = explode(',', $excludedGroupsList); // FIXME: this should be JSON!
|
||||
$template->assign('shareExcludedGroupsList', implode('|', $excludedGroupsList));
|
||||
$template->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabled());
|
||||
$backends = \OC::$server->getUserManager()->getBackends();
|
||||
$externalBackends = (count($backends) > 1) ? true : false;
|
||||
$template->assign('encryptionReady', \OC::$server->getEncryptionManager()->isReady());
|
||||
$template->assign('externalBackendsEnabled', $externalBackends);
|
||||
$encryptionModules = \OC::$server->getEncryptionManager()->getEncryptionModules();
|
||||
|
||||
try {
|
||||
$defaultEncryptionModule = \OC::$server->getEncryptionManager()->getDefaultEncryptionModule();
|
||||
$defaultEncryptionModuleId = $defaultEncryptionModule->getId();
|
||||
|
|
|
@ -23,8 +23,10 @@
|
|||
|
||||
namespace OC\Settings;
|
||||
|
||||
use OC\Files\View;
|
||||
use OC\Settings\Controller\AppSettingsController;
|
||||
use OC\Settings\Controller\CheckSetupController;
|
||||
use OC\Settings\Controller\EncryptionController;
|
||||
use OC\Settings\Controller\GroupsController;
|
||||
use OC\Settings\Controller\LogSettingsController;
|
||||
use OC\Settings\Controller\MailSettingsController;
|
||||
|
@ -65,6 +67,17 @@ class Application extends App {
|
|||
$c->query('DefaultMailAddress')
|
||||
);
|
||||
});
|
||||
$container->registerService('EncryptionController', function(IContainer $c) {
|
||||
return new EncryptionController(
|
||||
$c->query('AppName'),
|
||||
$c->query('Request'),
|
||||
$c->query('L10N'),
|
||||
$c->query('Config'),
|
||||
$c->query('DatabaseConnection'),
|
||||
$c->query('UserManager'),
|
||||
new View()
|
||||
);
|
||||
});
|
||||
$container->registerService('AppSettingsController', function(IContainer $c) {
|
||||
return new AppSettingsController(
|
||||
$c->query('AppName'),
|
||||
|
@ -207,5 +220,8 @@ class Application extends App {
|
|||
$container->registerService('Util', function(IContainer $c) {
|
||||
return new \OC_Util();
|
||||
});
|
||||
$container->registerService('DatabaseConnection', function(IContainer $c) {
|
||||
return $c->query('ServerContainer')->getDatabaseConnection();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
122
settings/controller/encryptioncontroller.php
Normal file
122
settings/controller/encryptioncontroller.php
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
*
|
||||
* @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\Settings\Controller;
|
||||
use OC\Files\View;
|
||||
use OCA\Encryption\Migration;
|
||||
use OCP\IL10N;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\IRequest;
|
||||
use OCP\IConfig;
|
||||
use OC\DB\Connection;
|
||||
use OCP\IUserManager;
|
||||
|
||||
/**
|
||||
* @package OC\Settings\Controller
|
||||
*/
|
||||
class EncryptionController extends Controller {
|
||||
|
||||
/** @var \OCP\IL10N */
|
||||
private $l10n;
|
||||
|
||||
/** @var Connection */
|
||||
private $connection;
|
||||
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
|
||||
/** @var IUserManager */
|
||||
private $userManager;
|
||||
|
||||
/** @var View */
|
||||
private $view;
|
||||
|
||||
/**
|
||||
* @param string $appName
|
||||
* @param IRequest $request
|
||||
* @param \OCP\IL10N $l10n
|
||||
* @param \OCP\IConfig $config
|
||||
* @param \OC\DB\Connection $connection
|
||||
* @param IUserManager $userManager
|
||||
* @param View $view
|
||||
*/
|
||||
public function __construct($appName,
|
||||
IRequest $request,
|
||||
IL10N $l10n,
|
||||
IConfig $config,
|
||||
Connection $connection,
|
||||
IUserManager $userManager,
|
||||
View $view) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->l10n = $l10n;
|
||||
$this->config = $config;
|
||||
$this->connection = $connection;
|
||||
$this->view = $view;
|
||||
$this->userManager = $userManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* start migration
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function startMigration() {
|
||||
// allow as long execution on the web server as possible
|
||||
set_time_limit(0);
|
||||
$migration = new Migration($this->config, $this->view, $this->connection);
|
||||
$migration->reorganizeSystemFolderStructure();
|
||||
$migration->updateDB();
|
||||
|
||||
try {
|
||||
|
||||
foreach ($this->userManager->getBackends() as $backend) {
|
||||
|
||||
$limit = 500;
|
||||
$offset = 0;
|
||||
do {
|
||||
$users = $backend->getUsers('', $limit, $offset);
|
||||
foreach ($users as $user) {
|
||||
$migration->reorganizeFolderStructureForUser($user);
|
||||
}
|
||||
$offset += $limit;
|
||||
} while (count($users) >= $limit);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return array(
|
||||
'data' => array(
|
||||
'message' => (string)$this->l10n->t('A problem occurred, please check your log files (Error: %s)', [$e->getMessage()]),
|
||||
),
|
||||
'status' => 'error',
|
||||
);
|
||||
}
|
||||
|
||||
return array('data' =>
|
||||
array('message' =>
|
||||
(string) $this->l10n->t('Migration Completed')
|
||||
),
|
||||
'status' => 'success'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -55,7 +55,7 @@ $(document).ready(function(){
|
|||
});
|
||||
|
||||
$('#encryptionEnabled').change(function() {
|
||||
$('#encryptionAPI div#selectEncryptionModules').toggleClass('hidden');
|
||||
$('#encryptionAPI div#EncryptionSettingsArea').toggleClass('hidden');
|
||||
});
|
||||
|
||||
$('#encryptionAPI input').change(function() {
|
||||
|
@ -70,6 +70,26 @@ $(document).ready(function(){
|
|||
OC.AppConfig.setValue('core', $(this).attr('name'), value);
|
||||
});
|
||||
|
||||
$('#startmigration').click(function(event){
|
||||
$(window).on('beforeunload.encryption', function(e) {
|
||||
return t('settings', 'Migration in progress. Please wait until the migration is finished');
|
||||
});
|
||||
event.preventDefault();
|
||||
$('#startmigration').prop('disabled', true);
|
||||
OC.msg.startAction('#startmigration_msg', t('settings', 'Migration started …'));
|
||||
$.post(OC.generateUrl('/settings/admin/startmigration'), '', function(data){
|
||||
OC.msg.finishedAction('#startmigration_msg', data);
|
||||
if (data['status'] === 'success') {
|
||||
$('#encryptionAPI div#selectEncryptionModules').toggleClass('hidden');
|
||||
$('#encryptionAPI div#migrationWarning').toggleClass('hidden');
|
||||
} else {
|
||||
$('#startmigration').prop('disabled', false);
|
||||
}
|
||||
$(window).off('beforeunload.encryption');
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
$('#shareAPI input:not(#excludedGroups)').change(function() {
|
||||
var value = $(this).val();
|
||||
if ($(this).attr('type') === 'checkbox') {
|
||||
|
|
|
@ -42,6 +42,7 @@ $application->registerRoutes($this, [
|
|||
['name' => 'MailSettings#setMailSettings', 'url' => '/settings/admin/mailsettings', 'verb' => 'POST'],
|
||||
['name' => 'MailSettings#storeCredentials', 'url' => '/settings/admin/mailsettings/credentials', 'verb' => 'POST'],
|
||||
['name' => 'MailSettings#sendTestMail', 'url' => '/settings/admin/mailtest', 'verb' => 'POST'],
|
||||
['name' => 'Encryption#startMigration', 'url' => '/settings/admin/startmigration', 'verb' => 'POST'],
|
||||
['name' => 'AppSettings#listCategories', 'url' => '/settings/apps/categories', 'verb' => 'GET'],
|
||||
['name' => 'AppSettings#viewApps', 'url' => '/settings/apps', 'verb' => 'GET'],
|
||||
['name' => 'AppSettings#listApps', 'url' => '/settings/apps/list', 'verb' => 'GET'],
|
||||
|
|
|
@ -300,27 +300,50 @@ if ($_['cronErrors']) {
|
|||
</div>
|
||||
|
||||
<div class="section" id='encryptionAPI'>
|
||||
<h2><?php p($l->t('Server Side Encryption'));?></h2>
|
||||
<p id="enable">
|
||||
<input type="checkbox" name="encryption_enabled" id="encryptionEnabled"
|
||||
value="1" <?php if ($_['encryptionEnabled']) print_unescaped('checked="checked"'); ?> />
|
||||
<label for="encryptionEnabled"><?php p($l->t('Enable Server-Side-Encryption'));?></label><br/>
|
||||
</p>
|
||||
<div id='selectEncryptionModules' class="<?php if (!$_['encryptionEnabled']) { p('hidden'); }?>">
|
||||
<?php if (empty($_['encryptionModules'])): p('No encryption module loaded, please load a encryption module in the app menu');
|
||||
else: ?>
|
||||
<h2><?php p($l->t('Server Side Encryption')); ?> </h2>
|
||||
|
||||
<p id="enable">
|
||||
<input type="checkbox" name="encryption_enabled"
|
||||
id="encryptionEnabled"
|
||||
value="1" <?php if ($_['encryptionEnabled']) print_unescaped('checked="checked"'); ?> />
|
||||
<label
|
||||
for="encryptionEnabled"><?php p($l->t('Enable Server-Side-Encryption')); ?> <span id="startmigration_msg" class="msg"></span> </label><br/>
|
||||
</p>
|
||||
|
||||
<div id="EncryptionSettingsArea" class="<?php if (!$_['encryptionEnabled']) p('hidden'); ?>">
|
||||
<div id='selectEncryptionModules' class="<?php if (!$_['encryptionReady']) p('hidden'); ?>">
|
||||
<?php
|
||||
if (empty($_['encryptionModules'])) {
|
||||
p('No encryption module loaded, please load a encryption module in the app menu');
|
||||
} else { ?>
|
||||
<h3>Select default encryption module:</h3>
|
||||
<fieldset id='encryptionModules'>
|
||||
<?php foreach ($_['encryptionModules'] as $id => $module): ?>
|
||||
<input type="radio" id="<?php p($id) ?>"
|
||||
name="default_encryption_module"
|
||||
value="<?php p($id) ?>"
|
||||
<?php if($module['default']) { p('checked'); } ?>>
|
||||
<label for="<?php p($id) ?>"><?php p($module['displayName']) ?></label><br />
|
||||
<?php endforeach;?>
|
||||
<?php foreach ($_['encryptionModules'] as $id => $module): ?>
|
||||
<input type="radio" id="<?php p($id) ?>"
|
||||
name="default_encryption_module"
|
||||
value="<?php p($id) ?>"
|
||||
<?php if ($module['default']) {
|
||||
p('checked');
|
||||
} ?>>
|
||||
<label
|
||||
for="<?php p($id) ?>"><?php p($module['displayName']) ?></label>
|
||||
<br/>
|
||||
<?php endforeach; ?>
|
||||
</fieldset>
|
||||
<?php endif; ?>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<div id="migrationWarning" class="<?php if ($_['encryptionReady']) p('hidden'); ?>">
|
||||
<?php
|
||||
if ($_['encryptionReady'] === false && $_['externalBackendsEnabled'] === true) {
|
||||
p('You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. '
|
||||
. 'Please enable the "ownCloud Default Encryption Module" and run \'occ encryption:migrate\'');
|
||||
} elseif ($_['encryptionReady'] === false && $_['externalBackendsEnabled'] === false) {
|
||||
p('You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one.'); ?>
|
||||
<input type="submit" name="startmigration" id="startmigration"
|
||||
value="<?php p($l->t('Start migration')); ?>"/>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section" id="mail_general_settings">
|
||||
|
|
|
@ -7,36 +7,45 @@ use Test\TestCase;
|
|||
|
||||
class ManagerTest extends TestCase {
|
||||
|
||||
/** @var Manager */
|
||||
private $manager;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject */
|
||||
private $config;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject */
|
||||
private $logger;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
$this->config = $this->getMock('\OCP\IConfig');
|
||||
$this->logger = $this->getMock('\OCP\ILogger');
|
||||
$this->manager = new Manager($this->config, $this->logger);
|
||||
|
||||
}
|
||||
|
||||
public function testManagerIsDisabled() {
|
||||
$config = $this->getMock('\OCP\IConfig');
|
||||
$m = new Manager($config);
|
||||
$this->assertFalse($m->isEnabled());
|
||||
$this->assertFalse($this->manager->isEnabled());
|
||||
}
|
||||
|
||||
public function testManagerIsDisabledIfEnabledButNoModules() {
|
||||
$config = $this->getMock('\OCP\IConfig');
|
||||
$config->expects($this->any())->method('getAppValue')->willReturn(true);
|
||||
$m = new Manager($config);
|
||||
$this->assertFalse($m->isEnabled());
|
||||
$this->config->expects($this->any())->method('getAppValue')->willReturn(true);
|
||||
$this->assertFalse($this->manager->isEnabled());
|
||||
}
|
||||
|
||||
public function testManagerIsDisabledIfDisabledButModules() {
|
||||
$config = $this->getMock('\OCP\IConfig');
|
||||
$config->expects($this->any())->method('getAppValue')->willReturn(false);
|
||||
$this->config->expects($this->any())->method('getAppValue')->willReturn(false);
|
||||
$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->assertFalse($m->isEnabled());
|
||||
$this->manager->registerEncryptionModule($em);
|
||||
$this->assertFalse($this->manager->isEnabled());
|
||||
}
|
||||
|
||||
public function testManagerIsEnabled() {
|
||||
$config = $this->getMock('\OCP\IConfig');
|
||||
$config->expects($this->any())->method('getSystemValue')->willReturn(true);
|
||||
$config->expects($this->any())->method('getAppValue')->willReturn('yes');
|
||||
$m = new Manager($config);
|
||||
$this->assertTrue($m->isEnabled());
|
||||
$this->config->expects($this->any())->method('getSystemValue')->willReturn(true);
|
||||
$this->config->expects($this->any())->method('getAppValue')->willReturn('yes');
|
||||
$this->assertTrue($this->manager->isEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -44,30 +53,26 @@ class ManagerTest extends TestCase {
|
|||
* @expectedExceptionMessage Id "0" already used by encryption module "TestDummyModule0"
|
||||
*/
|
||||
public function testModuleRegistration() {
|
||||
$config = $this->getMock('\OCP\IConfig');
|
||||
$config->expects($this->any())->method('getAppValue')->willReturn('yes');
|
||||
$this->config->expects($this->any())->method('getAppValue')->willReturn('yes');
|
||||
$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->assertSame(1, count($m->getEncryptionModules()));
|
||||
$m->registerEncryptionModule($em);
|
||||
$this->manager->registerEncryptionModule($em);
|
||||
$this->assertSame(1, count($this->manager->getEncryptionModules()));
|
||||
$this->manager->registerEncryptionModule($em);
|
||||
}
|
||||
|
||||
public function testModuleUnRegistration() {
|
||||
$config = $this->getMock('\OCP\IConfig');
|
||||
$config->expects($this->any())->method('getAppValue')->willReturn(true);
|
||||
$this->config->expects($this->any())->method('getAppValue')->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->manager->registerEncryptionModule($em);
|
||||
$this->assertSame(1,
|
||||
count($m->getEncryptionModules())
|
||||
count($this->manager->getEncryptionModules())
|
||||
);
|
||||
$m->unregisterEncryptionModule($em);
|
||||
$this->assertEmpty($m->getEncryptionModules());
|
||||
$this->manager->unregisterEncryptionModule($em);
|
||||
$this->assertEmpty($this->manager->getEncryptionModules());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,40 +80,34 @@ class ManagerTest extends TestCase {
|
|||
* @expectedExceptionMessage Module with id: unknown does not exists.
|
||||
*/
|
||||
public function testGetEncryptionModuleUnknown() {
|
||||
$config = $this->getMock('\OCP\IConfig');
|
||||
$config->expects($this->any())->method('getAppValue')->willReturn(true);
|
||||
$this->config->expects($this->any())->method('getAppValue')->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->assertSame(1, count($m->getEncryptionModules()));
|
||||
$m->getEncryptionModule('unknown');
|
||||
$this->manager->registerEncryptionModule($em);
|
||||
$this->assertSame(1, count($this->manager->getEncryptionModules()));
|
||||
$this->manager->getEncryptionModule('unknown');
|
||||
}
|
||||
|
||||
public function testGetEncryptionModule() {
|
||||
$config = $this->getMock('\OCP\IConfig');
|
||||
$config->expects($this->any())->method('getAppValue')->willReturn(true);
|
||||
$this->config->expects($this->any())->method('getAppValue')->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->assertSame(1, count($m->getEncryptionModules()));
|
||||
$en0 = $m->getEncryptionModule(0);
|
||||
$this->manager->registerEncryptionModule($em);
|
||||
$this->assertSame(1, count($this->manager->getEncryptionModules()));
|
||||
$en0 = $this->manager->getEncryptionModule(0);
|
||||
$this->assertEquals(0, $en0->getId());
|
||||
}
|
||||
|
||||
public function testGetDefaultEncryptionModule() {
|
||||
$config = $this->getMock('\OCP\IConfig');
|
||||
$config->expects($this->any())->method('getAppValue')->willReturn(true);
|
||||
$this->config->expects($this->any())->method('getAppValue')->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->assertSame(1, count($m->getEncryptionModules()));
|
||||
$en0 = $m->getEncryptionModule(0);
|
||||
$this->manager->registerEncryptionModule($em);
|
||||
$this->assertSame(1, count($this->manager->getEncryptionModules()));
|
||||
$en0 = $this->manager->getEncryptionModule(0);
|
||||
$this->assertEquals(0, $en0->getId());
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,15 @@ class UtilTest extends TestCase {
|
|||
/** @var \PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $userManager;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $groupManager;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject */
|
||||
private $config;
|
||||
|
||||
/** @var \OC\Encryption\Util */
|
||||
private $util;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
$this->view = $this->getMockBuilder('OC\Files\View')
|
||||
|
@ -33,18 +39,28 @@ class UtilTest extends TestCase {
|
|||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->groupManager = $this->getMockBuilder('OC\Group\Manager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->config = $this->getMockBuilder('OCP\IConfig')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->util = new Util(
|
||||
$this->view,
|
||||
$this->userManager,
|
||||
$this->groupManager,
|
||||
$this->config
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providesHeadersForEncryptionModule
|
||||
*/
|
||||
public function testGetEncryptionModuleId($expected, $header) {
|
||||
$u = new Util($this->view, $this->userManager, $this->config);
|
||||
$id = $u->getEncryptionModuleId($header);
|
||||
$id = $this->util->getEncryptionModuleId($header);
|
||||
$this->assertEquals($expected, $id);
|
||||
}
|
||||
|
||||
|
@ -61,8 +77,7 @@ class UtilTest extends TestCase {
|
|||
*/
|
||||
public function testReadHeader($header, $expected, $moduleId) {
|
||||
$expected['oc_encryption_module'] = $moduleId;
|
||||
$u = new Util($this->view, $this->userManager, $this->config);
|
||||
$result = $u->readHeader($header);
|
||||
$result = $this->util->readHeader($header);
|
||||
$this->assertSameSize($expected, $result);
|
||||
foreach ($expected as $key => $value) {
|
||||
$this->assertArrayHasKey($key, $result);
|
||||
|
@ -78,8 +93,7 @@ class UtilTest extends TestCase {
|
|||
$em = $this->getMock('\OCP\Encryption\IEncryptionModule');
|
||||
$em->expects($this->any())->method('getId')->willReturn($moduleId);
|
||||
|
||||
$u = new Util($this->view, $this->userManager, $this->config);
|
||||
$result = $u->createHeader($header, $em);
|
||||
$result = $this->util->createHeader($header, $em);
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
|
@ -102,23 +116,20 @@ class UtilTest extends TestCase {
|
|||
$em = $this->getMock('\OCP\Encryption\IEncryptionModule');
|
||||
$em->expects($this->any())->method('getId')->willReturn('moduleId');
|
||||
|
||||
$u = new Util($this->view, $this->userManager, $this->config);
|
||||
$u->createHeader($header, $em);
|
||||
$this->util->createHeader($header, $em);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providePathsForTestIsExcluded
|
||||
*/
|
||||
public function testIsEcluded($path, $expected) {
|
||||
public function testIsExcluded($path, $expected) {
|
||||
$this->userManager
|
||||
->expects($this->any())
|
||||
->method('userExists')
|
||||
->will($this->returnCallback(array($this, 'isExcludedCallback')));
|
||||
|
||||
$u = new Util($this->view, $this->userManager, $this->config);
|
||||
|
||||
$this->assertSame($expected,
|
||||
$u->isExcluded($path)
|
||||
$this->util->isExcluded($path)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -34,8 +34,11 @@ class Encryption extends \Test\Files\Storage\Storage {
|
|||
$config = $this->getMockBuilder('\OCP\IConfig')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$groupManager = $this->getMockBuilder('\OC\Group\Manager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$util = $this->getMock('\OC\Encryption\Util', ['getUidAndFilename'], [new View(), new \OC\User\Manager(), $config]);
|
||||
$util = $this->getMock('\OC\Encryption\Util', ['getUidAndFilename'], [new View(), new \OC\User\Manager(), $groupManager, $config]);
|
||||
$util->expects($this->any())
|
||||
->method('getUidAndFilename')
|
||||
->willReturnCallback(function ($path) {
|
||||
|
|
|
@ -27,12 +27,15 @@ class Encryption extends \Test\TestCase {
|
|||
$config = $this->getMockBuilder('\OCP\IConfig')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$groupManager = $this->getMockBuilder('\OC\Group\Manager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$file = $this->getMockBuilder('\OC\Encryption\File')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['getAccessList'])
|
||||
->getMock();
|
||||
$file->expects($this->any())->method('getAccessList')->willReturn([]);
|
||||
$util = $this->getMock('\OC\Encryption\Util', ['getUidAndFilename'], [new View(), new \OC\User\Manager(), $config]);
|
||||
$util = $this->getMock('\OC\Encryption\Util', ['getUidAndFilename'], [new View(), new \OC\User\Manager(), $groupManager, $config]);
|
||||
$util->expects($this->any())
|
||||
->method('getUidAndFilename')
|
||||
->willReturn(['user1', $internalPath]);
|
||||
|
|
Loading…
Reference in a new issue