Browse Source
add migration script from old encryption to new one
remotes/origin/poc-doctrine-migrations
add migration script from old encryption to new one
remotes/origin/poc-doctrine-migrations
14 changed files with 915 additions and 73 deletions
-
8apps/encryption/appinfo/app.php
-
13apps/encryption/appinfo/application.php
-
2apps/encryption/appinfo/info.xml
-
15apps/encryption/appinfo/register_command.php
-
105apps/encryption/command/migratekeys.php
-
319apps/encryption/lib/migration.php
-
356apps/encryption/tests/lib/MigrationTest.php
-
42lib/private/encryption/manager.php
-
10lib/private/encryption/util.php
-
11lib/private/files/storage/wrapper/encryption.php
-
2lib/private/server.php
-
1settings/admin.php
-
9settings/templates/admin.php
-
95tests/lib/encryption/managertest.php
@ -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)); |
@ -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); |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -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)); |
|||
} |
|||
|
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue