diff --git a/apps/files/lib/Command/TransferOwnership.php b/apps/files/lib/Command/TransferOwnership.php index 4adb24d8637c..85c5f898f894 100644 --- a/apps/files/lib/Command/TransferOwnership.php +++ b/apps/files/lib/Command/TransferOwnership.php @@ -194,6 +194,14 @@ function (FileInfo $fileInfo) use ($progress, $self) { $progress->advance(); $this->allFiles[] = $fileInfo; if ($fileInfo->isEncrypted()) { + if (\OC::$server->getAppConfig()->getValue('encryption', 'useMasterKey', 0) !== 0) { + /** + * We are not going to add this to encryptedFiles array. + * Because its encrypted with masterKey and hence it doesn't + * require user's specific password. + */ + return true; + } $this->encryptedFiles[] = $fileInfo; } return true; diff --git a/lib/private/Files/Filesystem.php b/lib/private/Files/Filesystem.php index ba31bf53c818..f37816bc2bf6 100644 --- a/lib/private/Files/Filesystem.php +++ b/lib/private/Files/Filesystem.php @@ -944,6 +944,9 @@ public static function getDirectoryContent($directory, $mimetype_filter = '') { * @return string */ public static function getPath($id) { + if (self::$defaultInstance === null) { + throw new NotFoundException("defaultInstance is null"); + } return self::$defaultInstance->getPath($id); } diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php index 0bbe9e67d345..b4c270bb8d51 100644 --- a/lib/private/Files/Storage/Wrapper/Encryption.php +++ b/lib/private/Files/Storage/Wrapper/Encryption.php @@ -246,7 +246,7 @@ public function unlink($path) { return $this->storage->unlink($path); } - $encryptionModule = $this->getEncryptionModule($path); + $encryptionModule = ($this->encryptionManager->isEnabled()) ? $this->getEncryptionModule($path) : ""; if ($encryptionModule) { $this->keyStorage->deleteAllFileKeys($this->getFullPath($path)); } @@ -358,11 +358,12 @@ public function copy($path1, $path2) { * * @param string $path * @param string $mode + * @param string|null $sourceFileOfRename * @return resource|bool * @throws GenericEncryptionException * @throws ModuleDoesNotExistsException */ - public function fopen($path, $mode) { + public function fopen($path, $mode, $sourceFileOfRename = null) { // check if the file is stored in the array cache, this means that we // copy a file over to the versions folder, in this case we don't want to @@ -378,7 +379,7 @@ public function fopen($path, $mode) { $header = $this->getHeader($path); $signed = (isset($header['signed']) && $header['signed'] === 'true') ? true : false; $fullPath = $this->getFullPath($path); - $encryptionModuleId = $this->util->getEncryptionModuleId($header); + $encryptionModuleId = ($encryptionEnabled) ? $this->util->getEncryptionModuleId($header): ""; if ($this->util->isExcluded($fullPath) === false) { @@ -457,7 +458,7 @@ public function fopen($path, $mode) { } $handle = \OC\Files\Stream\Encryption::wrap($source, $path, $fullPath, $header, $this->uid, $encryptionModule, $this->storage, $this, $this->util, $this->fileHelper, $mode, - $size, $unencryptedSize, $headerSize, $signed); + $size, $unencryptedSize, $headerSize, $signed, $sourceFileOfRename); return $handle; } @@ -569,7 +570,7 @@ protected function fixUnencryptedSize($path, $size, $unencryptedSize) { fclose($stream); // we have to decrypt the last chunk to get it actual size - $encryptionModule->begin($this->getFullPath($path), $this->uid, 'r', $header, []); + $encryptionModule->begin($this->getFullPath($path), $this->uid, 'r', $header, [], null); $decryptedLastChunk = $encryptionModule->decrypt($lastChunkContentEncrypted, $lastChunkNr . 'end'); $decryptedLastChunk .= $encryptionModule->end($this->getFullPath($path), $lastChunkNr . 'end'); @@ -672,6 +673,12 @@ private function updateEncryptedVersion(Storage $sourceStorage, $sourceInternalP // in case of a rename we need to manipulate the source cache because // this information will be kept for the new target if ($isRename) { + /* + * Rename is a process of creating a new file. Here we try to use the + * incremented version of source file, for the destination file. + */ + $encryptedVersion = $sourceStorage->getCache()->get($sourceInternalPath)['encryptedVersion']; + $cacheInformation['encryptedVersion'] = $encryptedVersion + 1; $sourceStorage->getCache()->put($sourceInternalPath, $cacheInformation); } else { $this->getCache()->put($targetInternalPath, $cacheInformation); @@ -690,7 +697,6 @@ private function updateEncryptedVersion(Storage $sourceStorage, $sourceInternalP * @throws \Exception */ private function copyBetweenStorage(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename) { - // for versions we have nothing to do, because versions should always use the // key from the original file. Just create a 1:1 copy and done if ($this->isVersion($targetInternalPath) || @@ -740,7 +746,12 @@ private function copyBetweenStorage(Storage $sourceStorage, $sourceInternalPath, } else { try { $source = $sourceStorage->fopen($sourceInternalPath, 'r'); - $target = $this->fopen($targetInternalPath, 'w'); + if ($isRename) { + $absSourcePath = Filesystem::normalizePath($sourceStorage->getOwner($sourceInternalPath). '/' . $sourceInternalPath); + $target = $this->fopen($targetInternalPath, 'w', $absSourcePath); + } else { + $target = $this->fopen($targetInternalPath, 'w'); + } list(, $result) = \OC_Helper::streamCopy($source, $target); fclose($source); fclose($target); diff --git a/lib/private/Files/Stream/Encryption.php b/lib/private/Files/Stream/Encryption.php index 28690c2c8a9e..72f47e5f33b0 100644 --- a/lib/private/Files/Stream/Encryption.php +++ b/lib/private/Files/Stream/Encryption.php @@ -115,7 +115,8 @@ public function __construct() { 'unencryptedSize', 'encryptionStorage', 'headerSize', - 'signed' + 'signed', + 'sourceFileOfRename' ]; } @@ -155,6 +156,7 @@ public static function wrap($source, $internalPath, $fullPath, array $header, $unencryptedSize, $headerSize, $signed, + $sourceFileOfRename = null, $wrapper = 'OC\Files\Stream\Encryption') { $context = stream_context_create([ @@ -172,7 +174,8 @@ public static function wrap($source, $internalPath, $fullPath, array $header, 'unencryptedSize' => $unencryptedSize, 'encryptionStorage' => $encStorage, 'headerSize' => $headerSize, - 'signed' => $signed + 'signed' => $signed, + 'sourceFileOfRename' => $sourceFileOfRename ] ]); @@ -228,7 +231,7 @@ protected function loadContext($name) { } public function stream_open($path, $mode, $options, &$opened_path) { - $this->loadContext('ocencryption'); + $context = $this->loadContext('ocencryption'); $this->position = 0; $this->cache = ''; @@ -254,7 +257,7 @@ public function stream_open($path, $mode, $options, &$opened_path) { } $accessList = $this->file->getAccessList($sharePath); - $this->newHeader = $this->encryptionModule->begin($this->fullPath, $this->uid, $mode, $this->header, $accessList); + $this->newHeader = $this->encryptionModule->begin($this->fullPath, $this->uid, $mode, $this->header, $accessList, $context['sourceFileOfRename']); if ( $mode === 'w' diff --git a/lib/public/Encryption/IEncryptionModule.php b/lib/public/Encryption/IEncryptionModule.php index 07b0220b4df0..1f6c5c00b488 100644 --- a/lib/public/Encryption/IEncryptionModule.php +++ b/lib/public/Encryption/IEncryptionModule.php @@ -58,13 +58,15 @@ public function getDisplayName(); * @param string $mode php stream open mode * @param array $header contains the header data read from the file * @param array $accessList who has access to the file contains the key 'users' and 'public' + * @param string|null $sourceFileOfRename contains false or the rename source file. This is required + * for version increment. * * $return array $header contain data as key-value pairs which should be * written to the header, in case of a write operation * or if no additional data is needed return a empty array * @since 8.1.0 */ - public function begin($path, $user, $mode, array $header, array $accessList); + public function begin($path, $user, $mode, array $header, array $accessList, $sourceFileOfRename); /** * last chunk received. This is the place where you can perform some final diff --git a/tests/integration/features/transfer-ownership.feature b/tests/integration/features/transfer-ownership.feature index 686b74fb9b11..b73476557348 100644 --- a/tests/integration/features/transfer-ownership.feature +++ b/tests/integration/features/transfer-ownership.feature @@ -1,7 +1,6 @@ Feature: transfer-ownership # TODO: change to @no_default_encryption once all this works with master key - @no_encryption Scenario: transfering ownership of a file Given user "user0" exists And user "user1" exists @@ -12,7 +11,19 @@ Feature: transfer-ownership And using received transfer folder of "user1" as dav path Then Downloaded content when downloading file "/somefile.txt" with range "bytes=0-6" should be "This is" - @no_encryption + Scenario: transfering ownership of a file after updating the file + Given user "user0" exists + And user "user1" exists + And User "user0" uploads file "data/file_to_overwrite.txt" to "/PARENT/textfile0.txt" + And user "user0" uploads chunk file "1" of "3" with "AA" to "/PARENT/textfile0.txt" + And user "user0" uploads chunk file "2" of "3" with "BB" to "/PARENT/textfile0.txt" + And user "user0" uploads chunk file "3" of "3" with "CC" to "/PARENT/textfile0.txt" + When transfering ownership from "user0" to "user1" + Then the command was successful + And As an "user1" + And using received transfer folder of "user1" as dav path + Then Downloaded content when downloading file "/PARENT/textfile0.txt" with range "bytes=0-5" should be "AABBCC" + Scenario: transfering ownership of a folder Given user "user0" exists And user "user1" exists @@ -24,7 +35,6 @@ Feature: transfer-ownership And using received transfer folder of "user1" as dav path Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is" - @no_encryption Scenario: transfering ownership of file shares Given user "user0" exists And user "user1" exists @@ -36,7 +46,6 @@ Feature: transfer-ownership And As an "user2" Then Downloaded content when downloading file "/somefile.txt" with range "bytes=0-6" should be "This is" - @no_encryption Scenario: transfering ownership of folder shared with third user Given user "user0" exists And user "user1" exists @@ -49,7 +58,6 @@ Feature: transfer-ownership And As an "user2" Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is" - @no_encryption Scenario: transfering ownership of folder shared with transfer recipient Given user "user0" exists And user "user1" exists @@ -63,7 +71,6 @@ Feature: transfer-ownership And using received transfer folder of "user1" as dav path And Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is" - @no_encryption Scenario: transfering ownership of folder doubly shared with third user Given group "group1" exists And user "user0" exists @@ -79,7 +86,6 @@ Feature: transfer-ownership And As an "user2" Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is" - @no_encryption Scenario: transfering ownership does not transfer received shares Given user "user0" exists And user "user1" exists @@ -92,7 +98,6 @@ Feature: transfer-ownership And using received transfer folder of "user1" as dav path Then as "user1" the folder "/test" does not exist - @no_encryption @local_storage Scenario: transfering ownership does not transfer external storage Given user "user0" exists @@ -103,7 +108,6 @@ Feature: transfer-ownership And using received transfer folder of "user1" as dav path Then as "user1" the folder "/local_storage" does not exist - @no_encryption Scenario: transfering ownership does not fail with shared trashed files Given user "user0" exists And user "user1" exists @@ -115,21 +119,18 @@ Feature: transfer-ownership When transfering ownership from "user0" to "user1" Then the command was successful - @no_encryption Scenario: transfering ownership fails with invalid source user Given user "user0" exists When transfering ownership from "invalid_user" to "user0" Then the command error output contains the text "Unknown source user" And the command failed with exit code 1 - @no_encryption Scenario: transfering ownership fails with invalid target user Given user "user0" exists When transfering ownership from "user0" to "invalid_user" Then the command error output contains the text "Unknown target user" And the command failed with exit code 1 - @no_encryption Scenario: transfering ownership of a folder Given user "user0" exists And user "user1" exists @@ -141,7 +142,6 @@ Feature: transfer-ownership And using received transfer folder of "user1" as dav path Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is" - @no_encryption Scenario: transfering ownership of file shares Given user "user0" exists And user "user1" exists @@ -154,7 +154,6 @@ Feature: transfer-ownership And As an "user2" Then Downloaded content when downloading file "/somefile.txt" with range "bytes=0-6" should be "This is" - @no_encryption Scenario: transfering ownership of folder shared with third user Given user "user0" exists And user "user1" exists @@ -167,7 +166,6 @@ Feature: transfer-ownership And As an "user2" Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is" - @no_encryption Scenario: transfering ownership of folder shared with transfer recipient Given user "user0" exists And user "user1" exists @@ -181,7 +179,6 @@ Feature: transfer-ownership And using received transfer folder of "user1" as dav path And Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is" - @no_encryption Scenario: transfering ownership of folder doubly shared with third user Given group "group1" exists And user "user0" exists @@ -197,7 +194,6 @@ Feature: transfer-ownership And As an "user2" Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is" - @no_encryption Scenario: transfering ownership does not transfer received shares Given user "user0" exists And user "user1" exists @@ -212,7 +208,6 @@ Feature: transfer-ownership And using received transfer folder of "user1" as dav path Then as "user1" the folder "/sub/test" does not exist - @no_encryption @local_storage Scenario: transfering ownership does not transfer external storage Given user "user0" exists @@ -224,7 +219,6 @@ Feature: transfer-ownership And using received transfer folder of "user1" as dav path Then as "user1" the folder "/local_storage" does not exist - @no_encryption Scenario: transfering ownership fails with invalid source user Given user "user0" exists And User "user0" created a folder "/sub" @@ -232,7 +226,6 @@ Feature: transfer-ownership Then the command error output contains the text "Unknown source user" And the command failed with exit code 1 - @no_encryption Scenario: transfering ownership fails with invalid target user Given user "user0" exists And User "user0" created a folder "/sub" @@ -240,7 +233,6 @@ Feature: transfer-ownership Then the command error output contains the text "Unknown target user" And the command failed with exit code 1 - @no_encryption Scenario: transfering ownership fails with invalid path Given user "user0" exists And user "user1" exists