Merge pull request #7374 from owncloud/enc_dont_overwrite_keys

[encryption] don't overwrite keys if rename was done by a stream copy
This commit is contained in:
Björn Schießle 2014-02-25 12:34:49 +01:00
commit e10ca7c2e9
4 changed files with 140 additions and 4 deletions

View File

@ -501,12 +501,21 @@ class Hooks {
* @param array $params with the old path and the new path * @param array $params with the old path and the new path
*/ */
public static function preRename($params) { public static function preRename($params) {
$util = new Util(new \OC_FilesystemView('/'), \OCP\User::getUser()); $user = \OCP\User::getUser();
$view = new \OC_FilesystemView('/');
$util = new Util($view, $user);
list($ownerOld, $pathOld) = $util->getUidAndFilename($params['oldpath']); list($ownerOld, $pathOld) = $util->getUidAndFilename($params['oldpath']);
// we only need to rename the keys if the rename happens on the same mountpoint
// otherwise we perform a stream copy, so we get a new set of keys
$mp1 = $view->getMountPoint('/' . $user . '/files/' . $params['oldpath']);
$mp2 = $view->getMountPoint('/' . $user . '/files/' . $params['newpath']);
if ($mp1 === $mp2) {
self::$renamedFiles[$params['oldpath']] = array( self::$renamedFiles[$params['oldpath']] = array(
'uid' => $ownerOld, 'uid' => $ownerOld,
'path' => $pathOld); 'path' => $pathOld);
} }
}
/** /**
* @brief after a file is renamed, rename its keyfile and share-keys also fix the file size and fix also the sharing * @brief after a file is renamed, rename its keyfile and share-keys also fix the file size and fix also the sharing

View File

@ -47,6 +47,7 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
public $rootView; // view on /data/user public $rootView; // view on /data/user
public $data; public $data;
public $filename; public $filename;
public $folder;
public static function setUpBeforeClass() { public static function setUpBeforeClass() {
// reset backend // reset backend
@ -89,6 +90,7 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
// init short data // init short data
$this->data = 'hats'; $this->data = 'hats';
$this->filename = 'enc_hooks_tests-' . uniqid() . '.txt'; $this->filename = 'enc_hooks_tests-' . uniqid() . '.txt';
$this->folder = 'enc_hooks_tests_folder-' . uniqid();
} }
@ -268,4 +270,57 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
} }
} }
/**
* @brief test rename operation
*/
function testRenameHook() {
// save file with content
$cryptedFile = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->filename, $this->data);
// test that data was successfully written
$this->assertTrue(is_int($cryptedFile));
// check if keys exists
$this->assertTrue($this->rootView->file_exists(
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
. $this->filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
$this->assertTrue($this->rootView->file_exists(
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/'
. $this->filename . '.key'));
// make subfolder
$this->rootView->mkdir('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder);
$this->assertTrue($this->rootView->is_dir('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder));
// move the file out of the shared folder
$root = $this->rootView->getRoot();
$this->rootView->chroot('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/');
$this->rootView->rename($this->filename, '/' . $this->folder . '/' . $this->filename);
$this->rootView->chroot($root);
$this->assertFalse($this->rootView->file_exists('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->filename));
$this->assertTrue($this->rootView->file_exists('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder . '/' . $this->filename));
// keys should be renamed too
$this->assertFalse($this->rootView->file_exists(
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
. $this->filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
$this->assertFalse($this->rootView->file_exists(
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/'
. $this->filename . '.key'));
$this->assertTrue($this->rootView->file_exists(
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/' . $this->folder . '/'
. $this->filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
$this->assertTrue($this->rootView->file_exists(
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->folder . '/'
. $this->filename . '.key'));
// cleanup
$this->rootView->unlink('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder);
}
} }

View File

@ -127,6 +127,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
\OC_User::deleteUser(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4); \OC_User::deleteUser(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4);
} }
/** /**
* @medium * @medium
* @param bool $withTeardown * @param bool $withTeardown
@ -498,6 +499,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
} }
} }
function testPublicShareFile() { function testPublicShareFile() {
// login as admin // login as admin
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1); \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
@ -864,6 +866,13 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
\OCA\Encryption\Helper::adminDisableRecovery('test123'); \OCA\Encryption\Helper::adminDisableRecovery('test123');
$this->assertEquals(0, \OC::$server->getAppConfig()->getValue('files_encryption', 'recoveryAdminEnabled')); $this->assertEquals(0, \OC::$server->getAppConfig()->getValue('files_encryption', 'recoveryAdminEnabled'));
//clean up, reset passwords
\OC_User::setPassword(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, 'test123');
$params = array('uid' => \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2,
'password' => \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2,
'recoveryPassword' => 'test123');
\OCA\Encryption\Hooks::setPassphrase($params);
} }
/** /**
@ -947,4 +956,65 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
$this->view->chroot('/'); $this->view->chroot('/');
} }
/**
* @brief test moving a shared file out of the Shared folder
*/
function testRename() {
// login as admin
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
// save file with content
$cryptedFile = file_put_contents('crypt:///' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename, $this->dataShort);
// test that data was successfully written
$this->assertTrue(is_int($cryptedFile));
// get the file info from previous created file
$fileInfo = $this->view->getFileInfo(
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
// check if we have a valid file info
$this->assertTrue($fileInfo instanceof \OC\Files\FileInfo);
// share the file
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, OCP\PERMISSION_ALL);
// check if share key for user2exists
$this->assertTrue($this->view->file_exists(
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
// login as user2
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
$this->assertTrue($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/Shared/' . $this->filename));
// get file contents
$retrievedCryptedFile = $this->view->file_get_contents(
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/Shared/' . $this->filename);
// check if data is the same as we previously written
$this->assertEquals($this->dataShort, $retrievedCryptedFile);
// move the file out of the shared folder
$this->view->rename('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/Shared/' . $this->filename,
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename);
// check if we can read the moved file
$retrievedRenamedFile = $this->view->file_get_contents(
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename);
// check if data is the same as we previously written
$this->assertEquals($this->dataShort, $retrievedRenamedFile);
// the owners file should be deleted
$this->assertFalse($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename));
// cleanup
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename);
}
} }

View File

@ -534,6 +534,8 @@ class View {
$source = $this->fopen($path1 . $postFix1, 'r'); $source = $this->fopen($path1 . $postFix1, 'r');
$target = $this->fopen($path2 . $postFix2, 'w'); $target = $this->fopen($path2 . $postFix2, 'w');
list($count, $result) = \OC_Helper::streamCopy($source, $target); list($count, $result) = \OC_Helper::streamCopy($source, $target);
fclose($source);
fclose($target);
} }
} }
if ($this->shouldEmitHooks() && $result !== false) { if ($this->shouldEmitHooks() && $result !== false) {