/** * Wraps the given storage when it is not a shared storage * * @param string $mountPoint * @param Storage $storage * @param IMountPoint $mount * @return Encryption|Storage */ public function wrapStorage($mountPoint, Storage $storage, IMountPoint $mount) { $parameters = ['storage' => $storage, 'mountPoint' => $mountPoint, 'mount' => $mount]; if (!$storage->instanceOfStorage('OC\\Files\\Storage\\Shared') && !$storage->instanceOfStorage('OCA\\Files_Sharing\\External\\Storage') && !$storage->instanceOfStorage('OC\\Files\\Storage\\OwnCloud')) { $user = \OC::$server->getUserSession()->getUser(); $mountManager = Filesystem::getMountManager(); $uid = $user ? $user->getUID() : null; $fileHelper = \OC::$server->getEncryptionFilesHelper(); $keyStorage = \OC::$server->getEncryptionKeyStorage(); $util = new Util(new View(), \OC::$server->getUserManager(), \OC::$server->getGroupManager(), \OC::$server->getConfig()); $update = new Update(new View(), $util, Filesystem::getMountManager(), $this->manager, $fileHelper, $uid); return new Encryption($parameters, $this->manager, $util, $this->logger, $fileHelper, $uid, $keyStorage, $update, $mountManager, $this->arrayCache); } else { return $storage; } }
/** * by default the encryption module should encrypt regular files, files in * files_versions and files in files_trashbin * * @dataProvider dataTestShouldEncrypt */ public function testShouldEncrypt($path, $shouldEncryptHomeStorage, $isHomeStorage, $expected) { $this->utilMock->expects($this->once())->method('shouldEncryptHomeStorage')->willReturn($shouldEncryptHomeStorage); if ($shouldEncryptHomeStorage === false) { $this->storageMock->expects($this->once())->method('instanceOfStorage')->with('\\OCP\\Files\\IHomeStorage')->willReturn($isHomeStorage); $this->utilMock->expects($this->once())->method('getStorage')->with($path)->willReturn($this->storageMock); } $this->assertSame($expected, $this->instance->shouldEncrypt($path)); }
/** * Returns whether a part file is needed for the given storage * or whether the file can be assembled/uploaded directly on the * target storage. * * @param \OCP\Files\Storage $storage * @return bool true if the storage needs part file handling */ private function needsPartFile($storage) { // TODO: in the future use ChunkHandler provided by storage // and/or add method on Storage called "needsPartFile()" return !$storage->instanceOfStorage('OCA\Files_Sharing\External\Storage') && !$storage->instanceOfStorage('OC\Files\Storage\OwnCloud'); }
/** * @param \OCP\Files\Storage $sourceStorage * @param string $sourceInternalPath * @param string $targetInternalPath * @return bool */ public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { if ($sourceStorage->instanceOfStorage('\OC\Files\Storage\Local')) { /** * @var \OC\Files\Storage\Local $sourceStorage */ $rootStorage = new Local(['datadir' => '/']); return $rootStorage->rename($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath)); } else { return parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); } }
/** * @param \OCP\Files\Storage $sourceStorage * @param string $sourceInternalPath * @param string $targetInternalPath * @param bool $preserveMtime * @return bool */ public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false) { if ($sourceStorage === $this) { return $this->copy($sourceInternalPath, $targetInternalPath); } if ($sourceStorage->is_dir($sourceInternalPath)) { $dh = $sourceStorage->opendir($sourceInternalPath); $result = $this->mkdir($targetInternalPath); if (is_resource($dh)) { while ($result and ($file = readdir($dh)) !== false) { if (!Filesystem::isIgnoredDir($file)) { $result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file); } } } } else { $source = $sourceStorage->fopen($sourceInternalPath, 'r'); // TODO: call fopen in a way that we execute again all storage wrappers // to avoid that we bypass storage wrappers which perform important actions // for this operation. Same is true for all other operations which // are not the same as the original one.Once this is fixed we also // need to adjust the encryption wrapper. $target = $this->fopen($targetInternalPath, 'w'); list(, $result) = \OC_Helper::streamCopy($source, $target); if ($result and $preserveMtime) { $this->touch($targetInternalPath, $sourceStorage->filemtime($sourceInternalPath)); } fclose($source); fclose($target); if (!$result) { // delete partially written target file $this->unlink($targetInternalPath); // delete cache entry that was created by fopen $this->getCache()->remove($targetInternalPath); } } return (bool) $result; }
/** * copy file between two storages * * @param Storage $sourceStorage * @param string $sourceInternalPath * @param string $targetInternalPath * @param bool $preserveMtime * @param bool $isRename * @return bool */ private function copyBetweenStorage(Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename) { // first copy the keys that we reuse the existing file key on the target location // and don't create a new one which would break versions for example. $mount = $this->mountManager->findByStorageId($sourceStorage->getId()); if (count($mount) === 1) { $mountPoint = $mount[0]->getMountPoint(); $source = $mountPoint . '/' . $sourceInternalPath; $target = $this->getFullPath($targetInternalPath); $this->copyKeys($source, $target); } else { $this->logger->error('Could not find mount point, can\'t keep encryption keys'); } if ($sourceStorage->is_dir($sourceInternalPath)) { $dh = $sourceStorage->opendir($sourceInternalPath); $result = $this->mkdir($targetInternalPath); if (is_resource($dh)) { while ($result and ($file = readdir($dh)) !== false) { if (!Filesystem::isIgnoredDir($file)) { $result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file); } } } } else { $source = $sourceStorage->fopen($sourceInternalPath, 'r'); $target = $this->fopen($targetInternalPath, 'w'); list(, $result) = \OC_Helper::streamCopy($source, $target); fclose($source); fclose($target); if ($result) { if ($preserveMtime) { $this->touch($targetInternalPath, $sourceStorage->filemtime($sourceInternalPath)); } $isEncrypted = $this->mount->getOption('encrypt', true) ? 1 : 0; // 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 { // delete partially written target file $this->unlink($targetInternalPath); // delete cache entry that was created by fopen $this->getCache()->remove($targetInternalPath); } } return (bool) $result; }
/** * Wraps the given storage when it is not a shared storage * * @param string $mountPoint * @param Storage $storage * @param IMountPoint $mount * @return Encryption|Storage */ public function wrapStorage($mountPoint, Storage $storage, IMountPoint $mount) { $parameters = [ 'storage' => $storage, 'mountPoint' => $mountPoint, 'mount' => $mount]; if (!$storage->instanceOfStorage('OC\Files\Storage\Shared') && !$storage->instanceOfStorage('OCA\Files_Sharing\External\Storage') && !$storage->instanceOfStorage('OC\Files\Storage\OwnCloud')) { $manager = \OC::$server->getEncryptionManager(); $user = \OC::$server->getUserSession()->getUser(); $logger = \OC::$server->getLogger(); $mountManager = Filesystem::getMountManager(); $uid = $user ? $user->getUID() : null; $fileHelper = \OC::$server->getEncryptionFilesHelper(); $keyStorage = \OC::$server->getEncryptionKeyStorage(); $update = new Update( new View(), $this, Filesystem::getMountManager(), $manager, $fileHelper, $uid ); return new Encryption( $parameters, $manager, $this, $logger, $fileHelper, $uid, $keyStorage, $update, $mountManager ); } else { return $storage; } }
/** * 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) { $encryptedVersion = $sourceStorage->getCache()->get($sourceInternalPath)['encryptedVersion']; // In case of a move operation from an unencrypted to an encrypted // storage the old encrypted version would stay with "0" while the // correct value would be "1". Thus we manually set the value to "1" // for those cases. // See also https://github.com/owncloud/core/issues/23078 if ($encryptedVersion === 0) { $encryptedVersion = 1; } $cacheInformation['encryptedVersion'] = $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); } }
/** * @param \OCP\Files\Storage $sourceStorage * @param string $sourceInternalPath * @param string $targetInternalPath * @return bool */ public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { if ($sourceStorage === $this) { return $this->rename($sourceInternalPath, $targetInternalPath); } if (!$sourceStorage->isDeletable($sourceInternalPath)) { return false; } $result = $this->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, true); if ($result) { if ($sourceStorage->is_dir($sourceInternalPath)) { $result &= $sourceStorage->rmdir($sourceInternalPath); } else { $result &= $sourceStorage->unlink($sourceInternalPath); } } return $result; }
/** * 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); } }