|
|
|
@ -33,6 +33,7 @@ |
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|
|
|
|
* |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
namespace OC\Files\Storage\Wrapper; |
|
|
|
|
|
|
|
|
|
use OC\Encryption\Exceptions\ModuleDoesNotExistsException; |
|
|
|
@ -41,6 +42,7 @@ use OC\Encryption\Util; |
|
|
|
|
use OC\Files\Cache\CacheEntry; |
|
|
|
|
use OC\Files\Filesystem; |
|
|
|
|
use OC\Files\Mount\Manager; |
|
|
|
|
use OC\Files\ObjectStore\ObjectStoreStorage; |
|
|
|
|
use OC\Files\Storage\LocalTempFileTrait; |
|
|
|
|
use OC\Memcache\ArrayCache; |
|
|
|
|
use OCP\Encryption\Exceptions\GenericEncryptionException; |
|
|
|
@ -139,28 +141,36 @@ class Encryption extends Wrapper { |
|
|
|
|
$size = $this->unencryptedSize[$fullPath]; |
|
|
|
|
// update file cache |
|
|
|
|
if ($info instanceof ICacheEntry) { |
|
|
|
|
$info = $info->getData(); |
|
|
|
|
$info['encrypted'] = $info['encryptedVersion']; |
|
|
|
|
} else { |
|
|
|
|
if (!is_array($info)) { |
|
|
|
|
$info = []; |
|
|
|
|
} |
|
|
|
|
$info['encrypted'] = true; |
|
|
|
|
$info = new CacheEntry($info); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$info['size'] = $size; |
|
|
|
|
$this->getCache()->put($path, $info); |
|
|
|
|
if ($size !== $info->getUnencryptedSize()) { |
|
|
|
|
$this->getCache()->update($info->getId(), [ |
|
|
|
|
'unencrypted_size' => $size |
|
|
|
|
]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return $size; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (isset($info['fileid']) && $info['encrypted']) { |
|
|
|
|
return $this->verifyUnencryptedSize($path, $info['size']); |
|
|
|
|
return $this->verifyUnencryptedSize($path, $info->getUnencryptedSize()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return $this->storage->filesize($path); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @param string $path |
|
|
|
|
* @param array $data |
|
|
|
|
* @return array |
|
|
|
|
*/ |
|
|
|
|
private function modifyMetaData(string $path, array $data): array { |
|
|
|
|
$fullPath = $this->getFullPath($path); |
|
|
|
|
$info = $this->getCache()->get($path); |
|
|
|
@ -170,7 +180,7 @@ class Encryption extends Wrapper { |
|
|
|
|
$data['size'] = $this->unencryptedSize[$fullPath]; |
|
|
|
|
} else { |
|
|
|
|
if (isset($info['fileid']) && $info['encrypted']) { |
|
|
|
|
$data['size'] = $this->verifyUnencryptedSize($path, $info['size']); |
|
|
|
|
$data['size'] = $this->verifyUnencryptedSize($path, $info->getUnencryptedSize()); |
|
|
|
|
$data['encrypted'] = true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -478,7 +488,7 @@ class Encryption extends Wrapper { |
|
|
|
|
* |
|
|
|
|
* @return int unencrypted size |
|
|
|
|
*/ |
|
|
|
|
protected function verifyUnencryptedSize($path, $unencryptedSize) { |
|
|
|
|
protected function verifyUnencryptedSize(string $path, int $unencryptedSize): int { |
|
|
|
|
$size = $this->storage->filesize($path); |
|
|
|
|
$result = $unencryptedSize; |
|
|
|
|
|
|
|
|
@ -510,7 +520,7 @@ class Encryption extends Wrapper { |
|
|
|
|
* |
|
|
|
|
* @return int calculated unencrypted size |
|
|
|
|
*/ |
|
|
|
|
protected function fixUnencryptedSize($path, $size, $unencryptedSize) { |
|
|
|
|
protected function fixUnencryptedSize(string $path, int $size, int $unencryptedSize): int { |
|
|
|
|
$headerSize = $this->getHeaderSize($path); |
|
|
|
|
$header = $this->getHeader($path); |
|
|
|
|
$encryptionModule = $this->getEncryptionModule($path); |
|
|
|
@ -581,7 +591,9 @@ class Encryption extends Wrapper { |
|
|
|
|
$cache = $this->storage->getCache(); |
|
|
|
|
if ($cache) { |
|
|
|
|
$entry = $cache->get($path); |
|
|
|
|
$cache->update($entry['fileid'], ['size' => $newUnencryptedSize]); |
|
|
|
|
$cache->update($entry['fileid'], [ |
|
|
|
|
'unencrypted_size' => $newUnencryptedSize |
|
|
|
|
]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return $newUnencryptedSize; |
|
|
|
@ -621,7 +633,12 @@ class Encryption extends Wrapper { |
|
|
|
|
* @param bool $preserveMtime |
|
|
|
|
* @return bool |
|
|
|
|
*/ |
|
|
|
|
public function moveFromStorage(Storage\IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = true) { |
|
|
|
|
public function moveFromStorage( |
|
|
|
|
Storage\IStorage $sourceStorage, |
|
|
|
|
$sourceInternalPath, |
|
|
|
|
$targetInternalPath, |
|
|
|
|
$preserveMtime = true |
|
|
|
|
) { |
|
|
|
|
if ($sourceStorage === $this) { |
|
|
|
|
return $this->rename($sourceInternalPath, $targetInternalPath); |
|
|
|
|
} |
|
|
|
@ -656,7 +673,13 @@ class Encryption extends Wrapper { |
|
|
|
|
* @param bool $isRename |
|
|
|
|
* @return bool |
|
|
|
|
*/ |
|
|
|
|
public function copyFromStorage(Storage\IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false, $isRename = false) { |
|
|
|
|
public function copyFromStorage( |
|
|
|
|
Storage\IStorage $sourceStorage, |
|
|
|
|
$sourceInternalPath, |
|
|
|
|
$targetInternalPath, |
|
|
|
|
$preserveMtime = false, |
|
|
|
|
$isRename = false |
|
|
|
|
) { |
|
|
|
|
|
|
|
|
|
// TODO clean this up once the underlying moveFromStorage in OC\Files\Storage\Wrapper\Common is fixed: |
|
|
|
|
// - call $this->storage->copyFromStorage() instead of $this->copyBetweenStorage |
|
|
|
@ -676,7 +699,13 @@ class Encryption extends Wrapper { |
|
|
|
|
* @param bool $isRename |
|
|
|
|
* @param bool $keepEncryptionVersion |
|
|
|
|
*/ |
|
|
|
|
private function updateEncryptedVersion(Storage\IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, $isRename, $keepEncryptionVersion) { |
|
|
|
|
private function updateEncryptedVersion( |
|
|
|
|
Storage\IStorage $sourceStorage, |
|
|
|
|
$sourceInternalPath, |
|
|
|
|
$targetInternalPath, |
|
|
|
|
$isRename, |
|
|
|
|
$keepEncryptionVersion |
|
|
|
|
) { |
|
|
|
|
$isEncrypted = $this->encryptionManager->isEnabled() && $this->shouldEncrypt($targetInternalPath); |
|
|
|
|
$cacheInformation = [ |
|
|
|
|
'encrypted' => $isEncrypted, |
|
|
|
@ -725,7 +754,13 @@ class Encryption extends Wrapper { |
|
|
|
|
* @return bool |
|
|
|
|
* @throws \Exception |
|
|
|
|
*/ |
|
|
|
|
private function copyBetweenStorage(Storage\IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename) { |
|
|
|
|
private function copyBetweenStorage( |
|
|
|
|
Storage\IStorage $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 |
|
|
|
@ -743,7 +778,7 @@ class Encryption extends Wrapper { |
|
|
|
|
if (isset($info['encrypted']) && $info['encrypted'] === true) { |
|
|
|
|
$this->updateUnencryptedSize( |
|
|
|
|
$this->getFullPath($targetInternalPath), |
|
|
|
|
$info['size'] |
|
|
|
|
$info->getUnencryptedSize() |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
$this->updateEncryptedVersion($sourceStorage, $sourceInternalPath, $targetInternalPath, $isRename, true); |
|
|
|
@ -808,13 +843,6 @@ class Encryption extends Wrapper { |
|
|
|
|
return (bool)$result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* get the path to a local version of the file. |
|
|
|
|
* The local version of the file can be temporary and doesn't have to be persistent across requests |
|
|
|
|
* |
|
|
|
|
* @param string $path |
|
|
|
|
* @return string |
|
|
|
|
*/ |
|
|
|
|
public function getLocalFile($path) { |
|
|
|
|
if ($this->encryptionManager->isEnabled()) { |
|
|
|
|
$cachedFile = $this->getCachedFile($path); |
|
|
|
@ -825,11 +853,6 @@ class Encryption extends Wrapper { |
|
|
|
|
return $this->storage->getLocalFile($path); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the wrapped storage's value for isLocal() |
|
|
|
|
* |
|
|
|
|
* @return bool wrapped storage's isLocal() value |
|
|
|
|
*/ |
|
|
|
|
public function isLocal() { |
|
|
|
|
if ($this->encryptionManager->isEnabled()) { |
|
|
|
|
return false; |
|
|
|
@ -837,15 +860,11 @@ class Encryption extends Wrapper { |
|
|
|
|
return $this->storage->isLocal(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* see https://www.php.net/manual/en/function.stat.php |
|
|
|
|
* only the following keys are required in the result: size and mtime |
|
|
|
|
* |
|
|
|
|
* @param string $path |
|
|
|
|
* @return array |
|
|
|
|
*/ |
|
|
|
|
public function stat($path) { |
|
|
|
|
$stat = $this->storage->stat($path); |
|
|
|
|
if (!$stat) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
$fileSize = $this->filesize($path); |
|
|
|
|
$stat['size'] = $fileSize; |
|
|
|
|
$stat[7] = $fileSize; |
|
|
|
@ -853,14 +872,6 @@ class Encryption extends Wrapper { |
|
|
|
|
return $stat; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* see https://www.php.net/manual/en/function.hash.php |
|
|
|
|
* |
|
|
|
|
* @param string $type |
|
|
|
|
* @param string $path |
|
|
|
|
* @param bool $raw |
|
|
|
|
* @return string |
|
|
|
|
*/ |
|
|
|
|
public function hash($type, $path, $raw = false) { |
|
|
|
|
$fh = $this->fopen($path, 'rb'); |
|
|
|
|
$ctx = hash_init($type); |
|
|
|
@ -1068,6 +1079,13 @@ class Encryption extends Wrapper { |
|
|
|
|
[$count, $result] = \OC_Helper::streamCopy($stream, $target); |
|
|
|
|
fclose($stream); |
|
|
|
|
fclose($target); |
|
|
|
|
|
|
|
|
|
// object store, stores the size after write and doesn't update this during scan |
|
|
|
|
// manually store the unencrypted size |
|
|
|
|
if ($result && $this->getWrapperStorage()->instanceOfStorage(ObjectStoreStorage::class)) { |
|
|
|
|
$this->getCache()->put($path, ['unencrypted_size' => $count]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return $count; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|