Merge pull request #22796 from owncloud/fix-encryption-on-version-restore

Keep "encryptedVersion" when calling `\OC\Files\View::copy`
This commit is contained in:
Thomas Müller 2016-03-03 16:31:11 +01:00
commit 8d2238e055
3 changed files with 61 additions and 25 deletions

View File

@ -191,12 +191,7 @@ class Storage {
$mtime = $users_view->filemtime('files/' . $filename); $mtime = $users_view->filemtime('files/' . $filename);
$users_view->copy('files/' . $filename, 'files_versions/' . $filename . '.v' . $mtime); $users_view->copy('files/' . $filename, 'files_versions/' . $filename . '.v' . $mtime);
// call getFileInfo to enforce a file cache entry for the new version // call getFileInfo to enforce a file cache entry for the new version
$newFileInfo = $users_view->getFileInfo('files_versions/' . $filename . '.v' . $mtime); $users_view->getFileInfo('files_versions/' . $filename . '.v' . $mtime);
// Keep the "encrypted" value of the original file
$oldVersion = $files_view->getFileInfo($filename)->getEncryptedVersion();
$cache = $newFileInfo->getStorage()->getCache();
$cache->update($newFileInfo->getId(), ['encrypted' => $oldVersion, 'encryptedVersion' => $oldVersion]);
} }
} }
@ -331,15 +326,22 @@ class Storage {
//first create a new version //first create a new version
$version = 'files_versions'.$filename.'.v'.$users_view->filemtime('files'.$filename); $version = 'files_versions'.$filename.'.v'.$users_view->filemtime('files'.$filename);
if ( !$users_view->file_exists($version)) { if (!$users_view->file_exists($version)) {
$users_view->copy('files'.$filename, 'files_versions'.$filename.'.v'.$users_view->filemtime('files'.$filename)); $users_view->copy('files'.$filename, 'files_versions'.$filename.'.v'.$users_view->filemtime('files'.$filename));
$versionCreated = true; $versionCreated = true;
} }
$fileToRestore = 'files_versions' . $filename . '.v' . $revision;
// Restore encrypted version of the old file for the newly restored file
// This has to happen manually here since the file is manually copied below
$oldVersion = $users_view->getFileInfo($fileToRestore)->getEncryptedVersion();
$newFileInfo = $files_view->getFileInfo($filename);
$cache = $newFileInfo->getStorage()->getCache();
$cache->update($newFileInfo->getId(), ['encrypted' => $oldVersion, 'encryptedVersion' => $oldVersion]);
// rollback // rollback
if (self::copyFileContents($users_view, 'files_versions' . $filename . '.v' . $revision, 'files' . $filename)) { if (self::copyFileContents($users_view, $fileToRestore, 'files' . $filename)) {
$files_view->touch($file, $revision); $files_view->touch($file, $revision);
Storage::scheduleExpire($uid, $file); Storage::scheduleExpire($uid, $file);
\OC_Hook::emit('\OCP\Versions', 'rollback', array( \OC_Hook::emit('\OCP\Versions', 'rollback', array(

View File

@ -620,6 +620,32 @@ class Encryption extends Wrapper {
return $this->copyBetweenStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, false); return $this->copyBetweenStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, false);
} }
/**
* Update the encrypted cache version in the database
*
* @param Storage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
* @param bool $isRename
*/
private function updateEncryptedVersion(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $isRename) {
$isEncrypted = $this->encryptionManager->isEnabled() && $this->mount->getOption('encrypt', true) ? 1 : 0;
$cacheInformation = [
'encrypted' => (bool)$isEncrypted,
];
if($isEncrypted === 1) {
$cacheInformation['encryptedVersion'] = $sourceStorage->getCache()->get($sourceInternalPath)['encryptedVersion'];
}
// in case of a rename we need to manipulate the source cache because
// this information will be kept for the new target
if ($isRename) {
$sourceStorage->getCache()->put($sourceInternalPath, $cacheInformation);
} else {
$this->getCache()->put($targetInternalPath, $cacheInformation);
}
}
/** /**
* copy file between two storages * copy file between two storages
* *
@ -647,6 +673,7 @@ class Encryption extends Wrapper {
$info['size'] $info['size']
); );
} }
$this->updateEncryptedVersion($sourceStorage, $sourceInternalPath, $targetInternalPath, $isRename);
} }
return $result; return $result;
} }
@ -689,15 +716,7 @@ class Encryption extends Wrapper {
if ($preserveMtime) { if ($preserveMtime) {
$this->touch($targetInternalPath, $sourceStorage->filemtime($sourceInternalPath)); $this->touch($targetInternalPath, $sourceStorage->filemtime($sourceInternalPath));
} }
$isEncrypted = $this->encryptionManager->isEnabled() && $this->mount->getOption('encrypt', true) ? 1 : 0; $this->updateEncryptedVersion($sourceStorage, $sourceInternalPath, $targetInternalPath, $isRename);
// in case of a rename we need to manipulate the source cache because
// this information will be kept for the new target
if ($isRename) {
$sourceStorage->getCache()->put($sourceInternalPath, ['encrypted' => $isEncrypted]);
} else {
$this->getCache()->put($targetInternalPath, ['encrypted' => $isEncrypted]);
}
} else { } else {
// delete partially written target file // delete partially written target file
$this->unlink($targetInternalPath); $this->unlink($targetInternalPath);

View File

@ -693,11 +693,19 @@ class Encryption extends Storage {
$temp = \OC::$server->getTempManager(); $temp = \OC::$server->getTempManager();
return fopen($temp->getTemporaryFile(), $mode); return fopen($temp->getTemporaryFile(), $mode);
}); });
if($expectedEncrypted) {
$cache = $this->getMock('\OCP\Files\Cache\ICache');
$cache->expects($this->once())
->method('get')
->with($sourceInternalPath)
->willReturn(['encryptedVersion' => 12345]);
$storage2->expects($this->once())
->method('getCache')
->willReturn($cache);
}
$this->encryptionManager->expects($this->any()) $this->encryptionManager->expects($this->any())
->method('isEnabled') ->method('isEnabled')
->willReturn($encryptionEnabled); ->willReturn($encryptionEnabled);
// FIXME can not overwrite the return after definition // FIXME can not overwrite the return after definition
// $this->mount->expects($this->at(0)) // $this->mount->expects($this->at(0))
// ->method('getOption') // ->method('getOption')
@ -706,9 +714,16 @@ class Encryption extends Storage {
global $mockedMountPointEncryptionEnabled; global $mockedMountPointEncryptionEnabled;
$mockedMountPointEncryptionEnabled = $mountPointEncryptionEnabled; $mockedMountPointEncryptionEnabled = $mountPointEncryptionEnabled;
$expectedCachePut = [
'encrypted' => $expectedEncrypted,
];
if($expectedEncrypted === true) {
$expectedCachePut['encryptedVersion'] = 12345;
}
$this->cache->expects($this->once()) $this->cache->expects($this->once())
->method('put') ->method('put')
->with($sourceInternalPath, ['encrypted' => $expectedEncrypted]); ->with($sourceInternalPath, $expectedCachePut);
$this->invokePrivate($this->instance, 'copyBetweenStorage', [$storage2, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename]); $this->invokePrivate($this->instance, 'copyBetweenStorage', [$storage2, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename]);
@ -765,10 +780,10 @@ class Encryption extends Storage {
->with($sourceStorage, $sourceInternalPath, $targetInternalPath) ->with($sourceStorage, $sourceInternalPath, $targetInternalPath)
->willReturn($copyResult); ->willReturn($copyResult);
$instance->expects($this->any())->method('getCache')
->willReturn($cache);
if ($copyResult) { if ($copyResult) {
$instance->expects($this->once())->method('getCache')
->with('', $sourceStorage)
->willReturn($cache);
$cache->expects($this->once())->method('get') $cache->expects($this->once())->method('get')
->with($sourceInternalPath) ->with($sourceInternalPath)
->willReturn(['encrypted' => $encrypted, 'size' => 42]); ->willReturn(['encrypted' => $encrypted, 'size' => 42]);