From 0f8fe77b3a7be660e78079bc987bb851b30b576c Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Tue, 29 Nov 2016 16:27:28 +0100 Subject: [PATCH] check if the file should really be encrypted before we update the file cache Signed-off-by: Bjoern Schiessle --- .../Files/Storage/Wrapper/Encryption.php | 32 ++++++- .../Files/Storage/Wrapper/EncryptionTest.php | 94 +++++++++++++++++++ 2 files changed, 124 insertions(+), 2 deletions(-) diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php index 8531ccc0dd..c0ccd22d14 100644 --- a/lib/private/Files/Storage/Wrapper/Encryption.php +++ b/lib/private/Files/Storage/Wrapper/Encryption.php @@ -444,7 +444,7 @@ class Encryption extends Wrapper { } // encryption disabled on write of new file and write to existing unencrypted file -> don't encrypt - if (!$encryptionEnabled || !$this->mount->getOption('encrypt', true)) { + if (!$encryptionEnabled || !$this->shouldEncrypt($path)) { if (!$targetExists || !$targetIsEncrypted) { $shouldEncrypt = false; } @@ -651,7 +651,7 @@ class Encryption extends Wrapper { * @param bool $isRename */ private function updateEncryptedVersion(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $isRename) { - $isEncrypted = $this->encryptionManager->isEnabled() && $this->mount->getOption('encrypt', true) ? 1 : 0; + $isEncrypted = $this->encryptionManager->isEnabled() && $this->shouldEncrypt($targetInternalPath) ? 1 : 0; $cacheInformation = [ 'encrypted' => (bool)$isEncrypted, ]; @@ -954,6 +954,7 @@ class Encryption extends Wrapper { throw $e; } } + return $encryptionModule; } @@ -991,4 +992,31 @@ class Encryption extends Wrapper { return substr($normalized, 0, strlen('/files_versions/')) === '/files_versions/'; } + /** + * check if the given storage should be encrypted or not + * + * @param $path + * @return bool + */ + protected function shouldEncrypt($path) { + $fullPath = $this->getFullPath($path); + $mountPointConfig = $this->mount->getOption('encrypt', true); + if ($mountPointConfig === false) { + return false; + } + + try { + $encryptionModule = $this->getEncryptionModule($fullPath); + } catch (ModuleDoesNotExistsException $e) { + return false; + } + + if ($encryptionModule === null) { + $encryptionModule = $this->encryptionManager->getEncryptionModule(); + } + + return $encryptionModule->shouldEncrypt($fullPath); + + } + } diff --git a/tests/lib/Files/Storage/Wrapper/EncryptionTest.php b/tests/lib/Files/Storage/Wrapper/EncryptionTest.php index 245f39f5e2..fb3b463e43 100644 --- a/tests/lib/Files/Storage/Wrapper/EncryptionTest.php +++ b/tests/lib/Files/Storage/Wrapper/EncryptionTest.php @@ -2,13 +2,21 @@ namespace Test\Files\Storage\Wrapper; +use OC\Encryption\Exceptions\ModuleDoesNotExistsException; +use OC\Encryption\Update; use OC\Encryption\Util; use OC\Files\Storage\Temporary; +use OC\Files\Storage\Wrapper\Encryption; use OC\Files\View; use OC\Log; use OC\Memcache\ArrayCache; use OC\User\Manager; +use OCP\Encryption\IEncryptionModule; +use OCP\Encryption\IFile; +use OCP\Encryption\Keys\IStorage; use OCP\Files\Cache\ICache; +use OCP\Files\Mount\IMountPoint; +use OCP\ILogger; use Test\Files\Storage\Storage; class EncryptionTest extends Storage { @@ -926,4 +934,90 @@ class EncryptionTest extends Storage { ]; } + /** + * @dataProvider dataTestShouldEncrypt + * + * @param bool $encryptMountPoint + * @param \PHPUnit_Framework_MockObject_MockObject | IEncryptionModule $encryptionModule + * @param bool $encryptionModuleShouldEncrypt + * @param bool $expected + */ + public function testShouldEncrypt( + $encryptMountPoint, + $encryptionModule, + $encryptionModuleShouldEncrypt, + $expected + ) { + $encryptionManager = $this->createMock(\OC\Encryption\Manager::class); + $util = $this->createMock(Util::class); + $logger = $this->createMock(ILogger::class); + $fileHelper = $this->createMock(IFile::class); + $uid = null; + $keyStorage = $this->createMock(IStorage::class); + $update = $this->createMock(Update::class); + $mountManager = $this->createMock(\OC\Files\Mount\Manager::class); + $mount = $this->createMock(IMountPoint::class); + $arrayCache = $this->createMock(ArrayCache::class); + $path = '/welcome.txt'; + $fullPath = 'admin/files/welcome.txt'; + $defaultEncryptionModule = $this->createMock(IEncryptionModule::class); + + $wrapper = $this->getMockBuilder(Encryption::class) + ->setConstructorArgs( + [ + ['mountPoint' => '', 'mount' => $mount, 'storage' => ''], + $encryptionManager, + $util, + $logger, + $fileHelper, + $uid, + $keyStorage, + $update, + $mountManager, + $arrayCache + ] + ) + ->setMethods(['getFullPath', 'getEncryptionModule']) + ->getMock(); + + $wrapper->method('getFullPath')->with($path)->willReturn($fullPath); + $wrapper->method('getEncryptionModule')->with($fullPath) + ->willReturnCallback( + function() use ($encryptionModule) { + if ($encryptionModule === false) { + throw new ModuleDoesNotExistsException(); + } + return $encryptionModule; + } + ); + $mount->expects($this->once())->method('getOption')->with('encrypt', true) + ->willReturn($encryptMountPoint); + + if ($encryptionModule !== null && $encryptionModule !== false) { + $encryptionModule->method('shouldEncrypt')->with($fullPath) + ->willReturn($encryptionModuleShouldEncrypt); + } + + if ($encryptionModule === null) { + $encryptionManager->expects($this->once())->method('getEncryptionModule') + ->willReturn($defaultEncryptionModule); + } + $defaultEncryptionModule->method('shouldEncrypt')->willReturn(true); + + $result = $this->invokePrivate($wrapper, 'shouldEncrypt', [$path]); + + $this->assertSame($expected, $result); + } + + public function dataTestShouldEncrypt() { + $encryptionModule = $this->createMock(IEncryptionModule::class); + return [ + [false, false, false, false], + [true, false, false, false], + [true, $encryptionModule, false, false], + [true, $encryptionModule, true, true], + [true, null, false, true], + ]; + } + }