diff options
Diffstat (limited to 'lib')
39 files changed, 979 insertions, 658 deletions
diff --git a/lib/base.php b/lib/base.php index 98da75b61a8..be397e52449 100644 --- a/lib/base.php +++ b/lib/base.php @@ -701,23 +701,7 @@ class OC { } private static function registerEncryptionWrapper() { - $enabled = self::$server->getEncryptionManager()->isEnabled(); - if ($enabled) { - \OC\Files\Filesystem::addStorageWrapper('oc_encryption', function ($mountPoint, $storage, \OCP\Files\Mount\IMountPoint $mount) { - if($mount->getOption('encrypt', true)) { - $parameters = array('storage' => $storage, 'mountPoint' => $mountPoint); - $manager = \OC::$server->getEncryptionManager(); - $util = new \OC\Encryption\Util(new \OC\Files\View(), \OC::$server->getUserManager()); - $user = \OC::$server->getUserSession()->getUser(); - $logger = \OC::$server->getLogger(); - $uid = $user ? $user->getUID() : null; - return new \OC\Files\Storage\Wrapper\Encryption($parameters, $manager, $util, $logger, $uid); - } else { - return $storage; - } - }); - } - + \OCP\Util::connectHook('OC_Filesystem', 'setup', 'OC\Encryption\Manager', 'setupStorage'); } private static function registerEncryptionHooks() { @@ -730,16 +714,17 @@ class OC { } $updater = new \OC\Encryption\Update( new \OC\Files\View(), - new \OC\Encryption\Util(new \OC\Files\View(), \OC::$server->getUserManager()), + new \OC\Encryption\Util( + new \OC\Files\View(), + \OC::$server->getUserManager(), + \OC::$server->getConfig()), \OC\Files\Filesystem::getMountManager(), \OC::$server->getEncryptionManager(), + \OC::$server->getEncryptionFilesHelper(), $uid ); \OCP\Util::connectHook('OCP\Share', 'post_shared', $updater, 'postShared'); \OCP\Util::connectHook('OCP\Share', 'post_unshare', $updater, 'postUnshared'); - - //\OCP\Util::connectHook('OC_Filesystem', 'post_umount', 'OCA\Files_Encryption\Hooks', 'postUnmount'); - //\OCP\Util::connectHook('OC_Filesystem', 'umount', 'OCA\Files_Encryption\Hooks', 'preUnmount'); } } diff --git a/lib/private/app.php b/lib/private/app.php index 84bc23608fb..4b3d4b82b82 100644 --- a/lib/private/app.php +++ b/lib/private/app.php @@ -207,7 +207,7 @@ class OC_App { self::$shippedApps = json_decode(file_get_contents($shippedJson), true); self::$shippedApps = self::$shippedApps['shippedApps']; } else { - self::$shippedApps = ['files', 'files_encryption', 'files_external', + self::$shippedApps = ['files', 'encryption', 'files_external', 'files_sharing', 'files_trashbin', 'files_versions', 'provisioning_api', 'user_ldap', 'user_webdavauth']; } diff --git a/lib/private/cache/file.php b/lib/private/cache/file.php index 8874acbb1e5..c70698eb7f8 100644 --- a/lib/private/cache/file.php +++ b/lib/private/cache/file.php @@ -67,13 +67,10 @@ class File { */ public function get($key) { $result = null; - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; if ($this->hasKey($key)) { $storage = $this->getStorage(); $result = $storage->file_get_contents($key); } - \OC_FileProxy::$enabled = $proxyStatus; return $result; } @@ -85,13 +82,10 @@ class File { */ public function size($key) { $result = 0; - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; if ($this->hasKey($key)) { $storage = $this->getStorage(); $result = $storage->filesize($key); } - \OC_FileProxy::$enabled = $proxyStatus; return $result; } @@ -101,7 +95,6 @@ class File { public function set($key, $value, $ttl = 0) { $storage = $this->getStorage(); $result = false; - $proxyStatus = \OC_FileProxy::$enabled; // unique id to avoid chunk collision, just in case $uniqueId = \OC::$server->getSecureRandom()->getLowStrengthGenerator()->generate( 16, @@ -111,7 +104,6 @@ class File { // use part file to prevent hasKey() to find the key // while it is being written $keyPart = $key . '.' . $uniqueId . '.part'; - \OC_FileProxy::$enabled = false; if ($storage and $storage->file_put_contents($keyPart, $value)) { if ($ttl === 0) { $ttl = 86400; // 60*60*24 @@ -119,7 +111,6 @@ class File { $result = $storage->touch($keyPart, time() + $ttl); $result &= $storage->rename($keyPart, $key); } - \OC_FileProxy::$enabled = $proxyStatus; return $result; } diff --git a/lib/private/connector/sabre/file.php b/lib/private/connector/sabre/file.php index 4fbcb732688..b4acaa15073 100644 --- a/lib/private/connector/sabre/file.php +++ b/lib/private/connector/sabre/file.php @@ -35,7 +35,24 @@ namespace OC\Connector\Sabre; -class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile { +use OC\Connector\Sabre\Exception\EntityTooLarge; +use OC\Connector\Sabre\Exception\FileLocked; +use OC\Connector\Sabre\Exception\UnsupportedMediaType; +use OCP\Encryption\Exceptions\GenericEncryptionException; +use OCP\Files\EntityTooLargeException; +use OCP\Files\InvalidContentException; +use OCP\Files\InvalidPathException; +use OCP\Files\LockNotAcquiredException; +use OCP\Files\NotPermittedException; +use OCP\Files\StorageNotAvailableException; +use Sabre\DAV\Exception; +use Sabre\DAV\Exception\BadRequest; +use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\Exception\NotImplemented; +use Sabre\DAV\Exception\ServiceUnavailable; +use Sabre\DAV\IFile; + +class File extends Node implements IFile { /** * Updates the data @@ -56,27 +73,22 @@ class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile { * * @param resource $data * - * @throws \Sabre\DAV\Exception\Forbidden - * @throws \OC\Connector\Sabre\Exception\UnsupportedMediaType - * @throws \Sabre\DAV\Exception\BadRequest - * @throws \Sabre\DAV\Exception - * @throws \OC\Connector\Sabre\Exception\EntityTooLarge - * @throws \Sabre\DAV\Exception\ServiceUnavailable + * @throws Forbidden + * @throws UnsupportedMediaType + * @throws BadRequest + * @throws Exception + * @throws EntityTooLarge + * @throws ServiceUnavailable * @return string|null */ public function put($data) { try { if ($this->info && $this->fileView->file_exists($this->path) && !$this->info->isUpdateable()) { - throw new \Sabre\DAV\Exception\Forbidden(); + throw new Forbidden(); } - } catch (\OCP\Files\StorageNotAvailableException $e) { - throw new \Sabre\DAV\Exception\ServiceUnavailable("File is not updatable: ".$e->getMessage()); - } - - // throw an exception if encryption was disabled but the files are still encrypted - if (\OC_Util::encryptedFiles()) { - throw new \Sabre\DAV\Exception\ServiceUnavailable("Encryption is disabled"); + } catch (StorageNotAvailableException $e) { + throw new ServiceUnavailable("File is not updatable: ".$e->getMessage()); } // verify path of the target @@ -104,31 +116,29 @@ class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile { \OC_Log::write('webdav', '\OC\Files\Filesystem::file_put_contents() failed', \OC_Log::ERROR); $this->fileView->unlink($partFilePath); // because we have no clue about the cause we can only throw back a 500/Internal Server Error - throw new \Sabre\DAV\Exception('Could not write file contents'); + throw new Exception('Could not write file contents'); } - } catch (\OCP\Files\NotPermittedException $e) { + } catch (NotPermittedException $e) { // a more general case - due to whatever reason the content could not be written - throw new \Sabre\DAV\Exception\Forbidden($e->getMessage()); - - } catch (\OCP\Files\EntityTooLargeException $e) { + throw new Forbidden($e->getMessage()); + } catch (EntityTooLargeException $e) { // the file is too big to be stored - throw new \OC\Connector\Sabre\Exception\EntityTooLarge($e->getMessage()); - - } catch (\OCP\Files\InvalidContentException $e) { + throw new EntityTooLarge($e->getMessage()); + } catch (InvalidContentException $e) { // the file content is not permitted - throw new \OC\Connector\Sabre\Exception\UnsupportedMediaType($e->getMessage()); - - } catch (\OCP\Files\InvalidPathException $e) { + throw new UnsupportedMediaType($e->getMessage()); + } catch (InvalidPathException $e) { // the path for the file was not valid // TODO: find proper http status code for this case - throw new \Sabre\DAV\Exception\Forbidden($e->getMessage()); - } catch (\OCP\Files\LockNotAcquiredException $e) { + throw new Forbidden($e->getMessage()); + } catch (LockNotAcquiredException $e) { // the file is currently being written to by another process - throw new \OC\Connector\Sabre\Exception\FileLocked($e->getMessage(), $e->getCode(), $e); - } catch (\OCA\Files_Encryption\Exception\EncryptionException $e) { - throw new \Sabre\DAV\Exception\Forbidden($e->getMessage()); - } catch (\OCP\Files\StorageNotAvailableException $e) { - throw new \Sabre\DAV\Exception\ServiceUnavailable("Failed to write file contents: ".$e->getMessage()); + throw new FileLocked($e->getMessage(), $e->getCode(), $e); + } catch (GenericEncryptionException $e) { + // returning 503 will allow retry of the operation at a later point in time + throw new ServiceUnavailable("Encryption not ready: " . $e->getMessage()); + } catch (StorageNotAvailableException $e) { + throw new ServiceUnavailable("Failed to write file contents: ".$e->getMessage()); } try { @@ -140,7 +150,7 @@ class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile { $actual = $this->fileView->filesize($partFilePath); if ($actual != $expected) { $this->fileView->unlink($partFilePath); - throw new \Sabre\DAV\Exception\BadRequest('expected filesize ' . $expected . ' got ' . $actual); + throw new BadRequest('expected filesize ' . $expected . ' got ' . $actual); } } @@ -152,12 +162,12 @@ class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile { if ($renameOkay === false || $fileExists === false) { \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); $this->fileView->unlink($partFilePath); - throw new \Sabre\DAV\Exception('Could not rename part file to final file'); + throw new Exception('Could not rename part file to final file'); } } - catch (\OCP\Files\LockNotAcquiredException $e) { + catch (LockNotAcquiredException $e) { // the file is currently being written to by another process - throw new \OC\Connector\Sabre\Exception\FileLocked($e->getMessage(), $e->getCode(), $e); + throw new FileLocked($e->getMessage(), $e->getCode(), $e); } } @@ -169,8 +179,8 @@ class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile { } } $this->refreshInfo(); - } catch (\OCP\Files\StorageNotAvailableException $e) { - throw new \Sabre\DAV\Exception\ServiceUnavailable("Failed to check file size: ".$e->getMessage()); + } catch (StorageNotAvailableException $e) { + throw new ServiceUnavailable("Failed to check file size: ".$e->getMessage()); } return '"' . $this->info->getEtag() . '"'; @@ -179,43 +189,39 @@ class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile { /** * Returns the data * @return string|resource - * @throws \Sabre\DAV\Exception\Forbidden - * @throws \Sabre\DAV\Exception\ServiceUnavailable + * @throws Forbidden + * @throws ServiceUnavailable */ public function get() { //throw exception if encryption is disabled but files are still encrypted - if (\OC_Util::encryptedFiles()) { - throw new \Sabre\DAV\Exception\ServiceUnavailable("Encryption is disabled"); - } else { - try { - return $this->fileView->fopen(ltrim($this->path, '/'), 'rb'); - } catch (\OCA\Files_Encryption\Exception\EncryptionException $e) { - throw new \Sabre\DAV\Exception\Forbidden($e->getMessage()); - } catch (\OCP\Files\StorageNotAvailableException $e) { - throw new \Sabre\DAV\Exception\ServiceUnavailable("Failed to open file: ".$e->getMessage()); - } + try { + return $this->fileView->fopen(ltrim($this->path, '/'), 'rb'); + } catch (GenericEncryptionException $e) { + // returning 503 will allow retry of the operation at a later point in time + throw new ServiceUnavailable("Encryption not ready: " . $e->getMessage()); + } catch (StorageNotAvailableException $e) { + throw new ServiceUnavailable("Failed to open file: ".$e->getMessage()); } - } /** * Delete the current file - * @throws \Sabre\DAV\Exception\Forbidden - * @throws \Sabre\DAV\Exception\ServiceUnavailable + * @throws Forbidden + * @throws ServiceUnavailable */ public function delete() { if (!$this->info->isDeletable()) { - throw new \Sabre\DAV\Exception\Forbidden(); + throw new Forbidden(); } try { if (!$this->fileView->unlink($this->path)) { // assume it wasn't possible to delete due to permissions - throw new \Sabre\DAV\Exception\Forbidden(); + throw new Forbidden(); } - } catch (\OCP\Files\StorageNotAvailableException $e) { - throw new \Sabre\DAV\Exception\ServiceUnavailable("Failed to unlink: ".$e->getMessage()); + } catch (StorageNotAvailableException $e) { + throw new ServiceUnavailable("Failed to unlink: ".$e->getMessage()); } } @@ -255,10 +261,10 @@ class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile { /** * @param resource $data * @return null|string - * @throws \Sabre\DAV\Exception - * @throws \Sabre\DAV\Exception\BadRequest - * @throws \Sabre\DAV\Exception\NotImplemented - * @throws \Sabre\DAV\Exception\ServiceUnavailable + * @throws Exception + * @throws BadRequest + * @throws NotImplemented + * @throws ServiceUnavailable */ private function createFileChunked($data) { @@ -266,7 +272,7 @@ class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile { $info = \OC_FileChunking::decodeName($name); if (empty($info)) { - throw new \Sabre\DAV\Exception\NotImplemented(); + throw new NotImplemented(); } $chunk_handler = new \OC_FileChunking($info); $bytesWritten = $chunk_handler->store($info['index'], $data); @@ -277,7 +283,7 @@ class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile { $expected = $_SERVER['CONTENT_LENGTH']; if ($bytesWritten != $expected) { $chunk_handler->remove($info['index']); - throw new \Sabre\DAV\Exception\BadRequest( + throw new BadRequest( 'expected filesize ' . $expected . ' got ' . $bytesWritten); } } @@ -303,7 +309,7 @@ class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile { if ($fileExists) { $this->fileView->unlink($targetPath); } - throw new \Sabre\DAV\Exception('Could not rename part file assembled from chunks'); + throw new Exception('Could not rename part file assembled from chunks'); } } else { // assemble directly into the final file @@ -320,8 +326,8 @@ class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile { $info = $this->fileView->getFileInfo($targetPath); return $info->getEtag(); - } catch (\OCP\Files\StorageNotAvailableException $e) { - throw new \Sabre\DAV\Exception\ServiceUnavailable("Failed to put file: ".$e->getMessage()); + } catch (StorageNotAvailableException $e) { + throw new ServiceUnavailable("Failed to put file: ".$e->getMessage()); } } diff --git a/lib/private/encryption/exceptions/decryptionfailedexception.php b/lib/private/encryption/exceptions/decryptionfailedexception.php new file mode 100644 index 00000000000..f8b4fdf07fa --- /dev/null +++ b/lib/private/encryption/exceptions/decryptionfailedexception.php @@ -0,0 +1,29 @@ +<?php + /** + * @author Clark Tomlinson <clark@owncloud.com> + * @since 2/25/15, 9:38 AM + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + + +namespace OC\Encryption\Exceptions; + +use OCP\Encryption\Exceptions\GenericEncryptionException; + +class DecryptionFailedException extends GenericEncryptionException { + +} diff --git a/lib/private/encryption/exceptions/emptyencryptiondataexception.php b/lib/private/encryption/exceptions/emptyencryptiondataexception.php new file mode 100644 index 00000000000..d3dc9230047 --- /dev/null +++ b/lib/private/encryption/exceptions/emptyencryptiondataexception.php @@ -0,0 +1,29 @@ +<?php + /** + * @author Clark Tomlinson <clark@owncloud.com> + * @since 2/25/15, 9:38 AM + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + + +namespace OC\Encryption\Exceptions; + +use OCP\Encryption\Exceptions\GenericEncryptionException; + +class EmptyEncryptionDataException extends GenericEncryptionException{ + +} diff --git a/lib/private/encryption/exceptions/encryptionfailedexception.php b/lib/private/encryption/exceptions/encryptionfailedexception.php new file mode 100644 index 00000000000..ac489c73254 --- /dev/null +++ b/lib/private/encryption/exceptions/encryptionfailedexception.php @@ -0,0 +1,29 @@ +<?php + /** + * @author Clark Tomlinson <clark@owncloud.com> + * @since 2/25/15, 9:37 AM + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + + +namespace OC\Encryption\Exceptions; + +use OCP\Encryption\Exceptions\GenericEncryptionException; + +class EncryptionFailedException extends GenericEncryptionException{ + +} diff --git a/lib/private/encryption/exceptions/encryptionheaderkeyexistsexception.php b/lib/private/encryption/exceptions/encryptionheaderkeyexistsexception.php index d401f0323ba..5e8e48efd78 100644 --- a/lib/private/encryption/exceptions/encryptionheaderkeyexistsexception.php +++ b/lib/private/encryption/exceptions/encryptionheaderkeyexistsexception.php @@ -23,7 +23,14 @@ namespace OC\Encryption\Exceptions; +use OCP\Encryption\Exceptions\GenericEncryptionException; -class EncryptionHeaderKeyExistsException extends \Exception { +class EncryptionHeaderKeyExistsException extends GenericEncryptionException { -}
\ No newline at end of file + /** + * @param string $key + */ + public function __construct($key) { + parent::__construct('header key "'. $key . '" already reserved by ownCloud'); + } +} diff --git a/lib/private/encryption/exceptions/encryptionheadertolargeexception.php b/lib/private/encryption/exceptions/encryptionheadertolargeexception.php new file mode 100644 index 00000000000..cdb5f940800 --- /dev/null +++ b/lib/private/encryption/exceptions/encryptionheadertolargeexception.php @@ -0,0 +1,33 @@ +<?php + /** + * @author Clark Tomlinson <clark@owncloud.com> + * @since 2/25/15, 9:35 AM + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + + +namespace OC\Encryption\Exceptions; + +use OCP\Encryption\Exceptions\GenericEncryptionException; + +class EncryptionHeaderToLargeException extends GenericEncryptionException { + + public function __construct() { + parent::__construct('max header size exceeded'); + } + +} diff --git a/lib/private/encryption/exceptions/modulealreadyexistsexception.php b/lib/private/encryption/exceptions/modulealreadyexistsexception.php index 41fc0188e24..fa1e70a5c36 100644 --- a/lib/private/encryption/exceptions/modulealreadyexistsexception.php +++ b/lib/private/encryption/exceptions/modulealreadyexistsexception.php @@ -23,6 +23,16 @@ namespace OC\Encryption\Exceptions; -class ModuleAlreadyExistsException extends \Exception { +use OCP\Encryption\Exceptions\GenericEncryptionException; + +class ModuleAlreadyExistsException extends GenericEncryptionException { + + /** + * @param string $id + * @param string $name + */ + public function __construct($id, $name) { + parent::__construct('Id "' . $id . '" already used by encryption module "' . $name . '"'); + } } diff --git a/lib/private/encryption/exceptions/moduledoesnotexistsexception.php b/lib/private/encryption/exceptions/moduledoesnotexistsexception.php index 5507bd03dab..2c699e8dc2d 100644 --- a/lib/private/encryption/exceptions/moduledoesnotexistsexception.php +++ b/lib/private/encryption/exceptions/moduledoesnotexistsexception.php @@ -23,6 +23,8 @@ namespace OC\Encryption\Exceptions; -class ModuleDoesNotExistsException extends \Exception { +use OCP\Encryption\Exceptions\GenericEncryptionException; + +class ModuleDoesNotExistsException extends GenericEncryptionException { } diff --git a/lib/private/encryption/exceptions/unknowncipherexception.php b/lib/private/encryption/exceptions/unknowncipherexception.php new file mode 100644 index 00000000000..188f7403848 --- /dev/null +++ b/lib/private/encryption/exceptions/unknowncipherexception.php @@ -0,0 +1,29 @@ +<?php + /** + * @author Clark Tomlinson <clark@owncloud.com> + * @since 2/25/15, 9:36 AM + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + + +namespace OC\Encryption\Exceptions; + +use OCP\Encryption\Exceptions\GenericEncryptionException; + +class UnknownCipherException extends GenericEncryptionException { + +} diff --git a/lib/private/encryption/file.php b/lib/private/encryption/file.php new file mode 100644 index 00000000000..3600936ed0e --- /dev/null +++ b/lib/private/encryption/file.php @@ -0,0 +1,79 @@ +<?php + +/** + * ownCloud + * + * @copyright (C) 2015 ownCloud, Inc. + * + * @author Bjoern Schiessle <schiessle@owncloud.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OC\Encryption; + +class File implements \OCP\Encryption\IFile { + + /** @var Util */ + protected $util; + + public function __construct(Util $util) { + $this->util = $util; + } + + + /** + * get list of users with access to the file + * + * @param string $path to the file + * @return array + */ + public function getAccessList($path) { + + // Make sure that a share key is generated for the owner too + list($owner, $ownerPath) = $this->util->getUidAndFilename($path); + + // always add owner to the list of users with access to the file + $userIds = array($owner); + + if (!$this->util->isFile($ownerPath)) { + return array('users' => $userIds, 'public' => false); + } + + $ownerPath = substr($ownerPath, strlen('/files')); + $ownerPath = $this->util->stripPartialFileExtension($ownerPath); + + // Find out who, if anyone, is sharing the file + $result = \OCP\Share::getUsersSharingFile($ownerPath, $owner); + $userIds = \array_merge($userIds, $result['users']); + $public = $result['public'] || $result['remote']; + + // check if it is a group mount + if (\OCP\App::isEnabled("files_external")) { + $mounts = \OC_Mount_Config::getSystemMountPoints(); + foreach ($mounts as $mount) { + if ($mount['mountpoint'] == substr($ownerPath, 1, strlen($mount['mountpoint']))) { + $mountedFor = $this->util->getUserWithAccessToMountPoint($mount['applicable']['users'], $mount['applicable']['groups']); + $userIds = array_merge($userIds, $mountedFor); + } + } + } + + // Remove duplicate UIDs + $uniqueUserIds = array_unique($userIds); + + return array('users' => $uniqueUserIds, 'public' => $public); + } + +} diff --git a/lib/private/encryption/keys/storage.php b/lib/private/encryption/keys/storage.php index 041db2a2cb8..42610bd0b41 100644 --- a/lib/private/encryption/keys/storage.php +++ b/lib/private/encryption/keys/storage.php @@ -25,7 +25,7 @@ namespace OC\Encryption\Keys; use OC\Encryption\Util; use OC\Files\View; -use OCA\Files_Encryption\Exception\EncryptionException; +use OCP\Encryption\Exceptions\GenericEncryptionException; class Storage implements \OCP\Encryption\Keys\IStorage { @@ -253,13 +253,13 @@ class Storage implements \OCP\Encryption\Keys\IStorage { * * @param string $path path to the file, relative to data/ * @return string - * @throws EncryptionException + * @throws GenericEncryptionException * @internal param string $keyId */ private function getFileKeyDir($path) { if ($this->view->is_dir($path)) { - throw new EncryptionException('file was expected but directory was given', EncryptionException::GENERIC); + throw new GenericEncryptionException("file was expected but directory was given: $path"); } list($owner, $filename) = $this->util->getUidAndFilename($path); @@ -283,7 +283,12 @@ class Storage implements \OCP\Encryption\Keys\IStorage { * @param string $owner * @param bool $systemWide */ - public function renameKeys($source, $target, $owner, $systemWide) { + public function renameKeys($source, $target) { + + list($owner, $source) = $this->util->getUidAndFilename($source); + list(, $target) = $this->util->getUidAndFilename($target); + $systemWide = $this->util->isSystemWideMountPoint($target); + if ($systemWide) { $sourcePath = $this->keys_base_dir . $source . '/'; $targetPath = $this->keys_base_dir . $target . '/'; @@ -299,6 +304,34 @@ class Storage implements \OCP\Encryption\Keys\IStorage { } /** + * copy keys if a file was renamed + * + * @param string $source + * @param string $target + * @param string $owner + * @param bool $systemWide + */ + public function copyKeys($source, $target) { + + list($owner, $source) = $this->util->getUidAndFilename($source); + list(, $target) = $this->util->getUidAndFilename($target); + $systemWide = $this->util->isSystemWideMountPoint($target); + + if ($systemWide) { + $sourcePath = $this->keys_base_dir . $source . '/'; + $targetPath = $this->keys_base_dir . $target . '/'; + } else { + $sourcePath = '/' . $owner . $this->keys_base_dir . $source . '/'; + $targetPath = '/' . $owner . $this->keys_base_dir . $target . '/'; + } + + if ($this->view->file_exists($sourcePath)) { + $this->keySetPreparation(dirname($targetPath)); + $this->view->copy($sourcePath, $targetPath); + } + } + + /** * Make preparations to filesystem for saving a keyfile * * @param string $path relative to the views root @@ -306,7 +339,7 @@ class Storage implements \OCP\Encryption\Keys\IStorage { protected function keySetPreparation($path) { // If the file resides within a subdirectory, create it if (!$this->view->file_exists($path)) { - $sub_dirs = explode('/', $path); + $sub_dirs = explode('/', ltrim($path, '/')); $dir = ''; foreach ($sub_dirs as $sub_dir) { $dir .= '/' . $sub_dir; diff --git a/lib/private/encryption/manager.php b/lib/private/encryption/manager.php index 5164025239c..484e0f540b2 100644 --- a/lib/private/encryption/manager.php +++ b/lib/private/encryption/manager.php @@ -23,7 +23,9 @@ namespace OC\Encryption; +use OC\Files\Storage\Wrapper\Encryption; use OCP\Encryption\IEncryptionModule; +use OCP\Files\Mount\IMountPoint; class Manager implements \OCP\Encryption\IManager { @@ -66,10 +68,9 @@ class Manager implements \OCP\Encryption\IManager { public function registerEncryptionModule(IEncryptionModule $module) { $id = $module->getId(); $name = $module->getDisplayName(); - if (isset($this->encryptionModules[$id])) { - $message = 'Id "' . $id . '" already used by encryption module "' . $name . '"'; - throw new Exceptions\ModuleAlreadyExistsException($message); + if (isset($this->encryptionModules[$id])) { + throw new Exceptions\ModuleAlreadyExistsException($id, $name); } $defaultEncryptionModuleId = $this->getDefaultEncryptionModuleId(); @@ -106,12 +107,24 @@ class Manager implements \OCP\Encryption\IManager { * @return IEncryptionModule * @throws Exceptions\ModuleDoesNotExistsException */ - public function getEncryptionModule($moduleId) { - if (isset($this->encryptionModules[$moduleId])) { - return $this->encryptionModules[$moduleId]; - } else { - $message = "Module with id: $moduleId does not exists."; - throw new Exceptions\ModuleDoesNotExistsException($message); + public function getEncryptionModule($moduleId = '') { + if (!empty($moduleId)) { + if (isset($this->encryptionModules[$moduleId])) { + return $this->encryptionModules[$moduleId]; + } else { + $message = "Module with id: $moduleId does not exists."; + throw new Exceptions\ModuleDoesNotExistsException($message); + } + } else { // get default module and return this + // For now we simply return the first module until we have a way + // to enable multiple modules and define a default module + $module = reset($this->encryptionModules); + if ($module) { + return $module; + } else { + $message = 'No encryption module registered'; + throw new Exceptions\ModuleDoesNotExistsException($message); + } } } @@ -166,5 +179,25 @@ class Manager implements \OCP\Encryption\IManager { } } - + public static function setupStorage() { + \OC\Files\Filesystem::addStorageWrapper('oc_encryption', function ($mountPoint, $storage, IMountPoint $mount) { + $parameters = [ + 'storage' => $storage, + 'mountPoint' => $mountPoint, + 'mount' => $mount]; + + if (!($storage instanceof \OC\Files\Storage\Shared)) { + $manager = \OC::$server->getEncryptionManager(); + $util = new \OC\Encryption\Util( + new \OC\Files\View(), \OC::$server->getUserManager(), \OC::$server->getConfig()); + $user = \OC::$server->getUserSession()->getUser(); + $logger = \OC::$server->getLogger(); + $uid = $user ? $user->getUID() : null; + $fileHelper = \OC::$server->getEncryptionFilesHelper(); + return new Encryption($parameters, $manager, $util, $logger, $fileHelper, $uid); + } else { + return $storage; + } + }, 2); + } } diff --git a/lib/private/encryption/update.php b/lib/private/encryption/update.php index 06dc330151e..1cfe935e584 100644 --- a/lib/private/encryption/update.php +++ b/lib/private/encryption/update.php @@ -46,12 +46,16 @@ class Update { /** @var string */ protected $uid; + /** @var \OC\Encryption\File */ + protected $file; + /** * * @param \OC\Files\View $view * @param \OC\Encryption\Util $util * @param \OC\Files\Mount\Manager $mountManager * @param \OC\Encryption\Manager $encryptionManager + * @param \OC\Encryption\File $file * @param string $uid */ public function __construct( @@ -59,6 +63,7 @@ class Update { Util $util, Mount\Manager $mountManager, Manager $encryptionManager, + File $file, $uid ) { @@ -66,6 +71,7 @@ class Update { $this->util = $util; $this->mountManager = $mountManager; $this->encryptionManager = $encryptionManager; + $this->file = $file; $this->uid = $uid; } @@ -87,25 +93,29 @@ class Update { * @param int $fileSource file source id */ private function update($fileSource) { - $path = \OC\Files\Filesystem::getPath($fileSource); - $absPath = '/' . $this->uid . '/files' . $path; - - $mount = $this->mountManager->find($path); - $mountPoint = $mount->getMountPoint(); - - // if a folder was shared, get a list of all (sub-)folders - if ($this->view->is_dir($absPath)) { - $allFiles = $this->util->getAllFiles($absPath, $mountPoint); - } else { - $allFiles = array($absPath); - } + $path = \OC\Files\Filesystem::getPath($fileSource); + $info = \OC\Files\Filesystem::getFileInfo($path); + $owner = \OC\Files\Filesystem::getOwner($path); + $view = new \OC\Files\View('/' . $owner . '/files'); + $ownerPath = $view->getPath($info->getId()); + $absPath = '/' . $owner . '/files' . $ownerPath; + + $mount = $this->mountManager->find($path); + $mountPoint = $mount->getMountPoint(); + + // if a folder was shared, get a list of all (sub-)folders + if ($this->view->is_dir($absPath)) { + $allFiles = $this->util->getAllFiles($absPath, $mountPoint); + } else { + $allFiles = array($absPath); + } - $encryptionModule = $this->encryptionManager->getDefaultEncryptionModule(); + $encryptionModule = $this->encryptionManager->getDefaultEncryptionModule(); - foreach ($allFiles as $path) { - $usersSharing = $this->util->getSharingUsersArray($path); - $encryptionModule->update($absPath, $this->uid, $usersSharing); - } + foreach ($allFiles as $path) { + $usersSharing = $this->file->getAccessList($path); + $encryptionModule->update($path, $this->uid, $usersSharing); + } } -}
\ No newline at end of file +} diff --git a/lib/private/encryption/util.php b/lib/private/encryption/util.php index 85e852ec2c9..6312d8813e3 100644 --- a/lib/private/encryption/util.php +++ b/lib/private/encryption/util.php @@ -23,9 +23,11 @@ namespace OC\Encryption; -use OC\Encryption\Exceptions\EncryptionHeaderToLargeException; use OC\Encryption\Exceptions\EncryptionHeaderKeyExistsException; +use OC\Encryption\Exceptions\EncryptionHeaderToLargeException; +use OC\Files\View; use OCP\Encryption\IEncryptionModule; +use OCP\IConfig; class Util { @@ -49,7 +51,7 @@ class Util { */ protected $blockSize = 8192; - /** @var \OC\Files\View */ + /** @var View */ protected $view; /** @var array */ @@ -58,19 +60,30 @@ class Util { /** @var \OC\User\Manager */ protected $userManager; + /** @var IConfig */ + protected $config; + /** @var array paths excluded from encryption */ protected $excludedPaths; /** - * @param \OC\Files\View $view root view + * + * @param \OC\Files\View $view + * @param \OC\User\Manager $userManager + * @param IConfig $config */ - public function __construct(\OC\Files\View $view, \OC\User\Manager $userManager) { + public function __construct( + \OC\Files\View $view, + \OC\User\Manager $userManager, + IConfig $config) { + $this->ocHeaderKeys = [ self::HEADER_ENCRYPTION_MODULE_KEY ]; $this->view = $view; $this->userManager = $userManager; + $this->config = $config; $this->excludedPaths[] = 'files_encryption'; } @@ -81,7 +94,7 @@ class Util { * @param array $header * @return string */ - public function getEncryptionModuleId(array $header) { + public function getEncryptionModuleId(array $header = null) { $id = ''; $encryptionModuleKey = self::HEADER_ENCRYPTION_MODULE_KEY; @@ -134,14 +147,14 @@ class Util { $header = self::HEADER_START . ':' . self::HEADER_ENCRYPTION_MODULE_KEY . ':' . $encryptionModule->getId() . ':'; foreach ($headerData as $key => $value) { if (in_array($key, $this->ocHeaderKeys)) { - throw new EncryptionHeaderKeyExistsException('header key "'. $key . '" already reserved by ownCloud'); + throw new EncryptionHeaderKeyExistsException($key); } $header .= $key . ':' . $value . ':'; } $header .= self::HEADER_END; if (strlen($header) > $this->getHeaderSize()) { - throw new EncryptionHeaderToLargeException('max header size exceeded', EncryptionException::ENCRYPTION_HEADER_TO_LARGE); + throw new EncryptionHeaderToLargeException(); } $paddedHeader = str_pad($header, $this->headerSize, self::HEADER_PADDING_CHAR, STR_PAD_RIGHT); @@ -150,53 +163,10 @@ class Util { } /** - * Find, sanitise and format users sharing a file - * @note This wraps other methods into a portable bundle - * @param string $path path relative to current users files folder - * @return array - */ - public function getSharingUsersArray($path) { - - // Make sure that a share key is generated for the owner too - list($owner, $ownerPath) = $this->getUidAndFilename($path); - - // always add owner to the list of users with access to the file - $userIds = array($owner); - - if (!$this->isFile($ownerPath)) { - return array('users' => $userIds, 'public' => false); - } - - $ownerPath = substr($ownerPath, strlen('/files')); - $ownerPath = $this->stripPartialFileExtension($ownerPath); - - // Find out who, if anyone, is sharing the file - $result = \OCP\Share::getUsersSharingFile($ownerPath, $owner); - $userIds = \array_merge($userIds, $result['users']); - $public = $result['public'] || $result['remote']; - - // check if it is a group mount - if (\OCP\App::isEnabled("files_external")) { - $mounts = \OC_Mount_Config::getSystemMountPoints(); - foreach ($mounts as $mount) { - if ($mount['mountpoint'] == substr($ownerPath, 1, strlen($mount['mountpoint']))) { - $mountedFor = $this->getUserWithAccessToMountPoint($mount['applicable']['users'], $mount['applicable']['groups']); - $userIds = array_merge($userIds, $mountedFor); - } - } - } - - // Remove duplicate UIDs - $uniqueUserIds = array_unique($userIds); - - return array('users' => $uniqueUserIds, 'public' => $public); - } - - /** * go recursively through a dir and collect all files and sub files. * * @param string $dir relative to the users files folder - * @param strinf $mountPoint + * @param string $mountPoint * @return array with list of files relative to the users files folder */ public function getAllFiles($dir, $mountPoint = '') { @@ -210,11 +180,11 @@ class Util { foreach ($content as $c) { // getDirectoryContent() returns the paths relative to the mount points, so we need // to re-construct the complete path - $path = ($mountPoint !== '') ? $mountPoint . '/' . $c['path'] : $c['path']; + $path = ($mountPoint !== '') ? $mountPoint . '/' . $c->getPath() : $c->getPath(); if ($c['type'] === 'dir') { - $dirList[] = $path; + $dirList[] = \OC\Files\Filesystem::normalizePath($path); } else { - $result[] = $path; + $result[] = \OC\Files\Filesystem::normalizePath($path); } } @@ -230,7 +200,7 @@ class Util { * @param string $path * @return boolean */ - protected function isFile($path) { + public function isFile($path) { if (substr($path, 0, strlen('/files/')) === '/files/') { return true; } @@ -256,7 +226,7 @@ class Util { } /** - * get the owner and the path for the owner + * get the owner and the path for the file relative to the owners files folder * * @param string $path * @return array @@ -270,55 +240,15 @@ class Util { $uid = $parts[1]; } if (!$this->userManager->userExists($uid)) { - throw new \BadMethodCallException('path needs to be relative to the system wide data folder and point to a user specific file'); - } - - $pathinfo = pathinfo($path); - $partfile = false; - $parentFolder = false; - if (array_key_exists('extension', $pathinfo) && $pathinfo['extension'] === 'part') { - // if the real file exists we check this file - $filePath = $pathinfo['dirname'] . '/' . $pathinfo['filename']; - if ($this->view->file_exists($filePath)) { - $pathToCheck = $pathinfo['dirname'] . '/' . $pathinfo['filename']; - } else { // otherwise we look for the parent - $pathToCheck = $pathinfo['dirname']; - $parentFolder = true; - } - $partfile = true; - } else { - $pathToCheck = $path; + throw new \BadMethodCallException( + 'path needs to be relative to the system wide data folder and point to a user specific file' + ); } - $pathToCheck = substr($pathToCheck, strlen('/' . $uid)); - - $this->view->chroot('/' . $uid); - $owner = $this->view->getOwner($pathToCheck); - - // Check that UID is valid - if (!$this->userManager->userExists($owner)) { - throw new \BadMethodCallException('path needs to be relative to the system wide data folder and point to a user specific file'); - } - - \OC\Files\Filesystem::initMountPoints($owner); - - $info = $this->view->getFileInfo($pathToCheck); - $this->view->chroot('/' . $owner); - $ownerPath = $this->view->getPath($info->getId()); - $this->view->chroot('/'); + $ownerPath = implode('/', array_slice($parts, 2)); - if ($parentFolder) { - $ownerPath = $ownerPath . '/'. $pathinfo['filename']; - } - - if ($partfile) { - $ownerPath = $ownerPath . '.' . $pathinfo['extension']; - } + return array($uid, \OC\Files\Filesystem::normalizePath($ownerPath)); - return array( - $owner, - \OC\Files\Filesystem::normalizePath($ownerPath) - ); } /** @@ -348,7 +278,7 @@ class Util { } } - protected function getUserWithAccessToMountPoint($users, $groups) { + public function getUserWithAccessToMountPoint($users, $groups) { $result = array(); if (in_array('all', $users)) { $result = \OCP\User::getUsers(); @@ -398,9 +328,6 @@ class Util { return true; } - $v1 = $this->userManager->userExists($root[1]); - $v2 = in_array($root[2], $this->excludedPaths); - // detect user specific folders if ($this->userManager->userExists($root[1]) && in_array($root[2], $this->excludedPaths)) { @@ -411,4 +338,16 @@ class Util { return false; } + /** + * check if recovery key is enabled for user + * + * @param string $uid + * @return boolean + */ + public function recoveryEnabled($uid) { + $enabled = $this->config->getUserValue($uid, 'encryption', 'recovery_enabled', '0'); + + return ($enabled === '1') ? true : false; + } + } diff --git a/lib/private/filechunking.php b/lib/private/filechunking.php index e8a58b2538d..82bf61fa7b1 100644 --- a/lib/private/filechunking.php +++ b/lib/private/filechunking.php @@ -189,8 +189,7 @@ class OC_FileChunking { $absolutePath = \OC\Files\Filesystem::normalizePath(\OC\Files\Filesystem::getView()->getAbsolutePath($path)); $data = ''; // use file_put_contents as method because that best matches what this function does - if (OC_FileProxy::runPreProxies('file_put_contents', $absolutePath, $data) - && \OC\Files\Filesystem::isValidPath($path)) { + if (\OC\Files\Filesystem::isValidPath($path)) { $path = \OC\Files\Filesystem::getView()->getRelativePath($absolutePath); $exists = \OC\Files\Filesystem::file_exists($path); $run = true; @@ -231,7 +230,6 @@ class OC_FileChunking { \OC\Files\Filesystem::signal_post_write, array( \OC\Files\Filesystem::signal_param_path => $path) ); - OC_FileProxy::runPostProxies('file_put_contents', $absolutePath, $count); return $count > 0; }else{ return false; diff --git a/lib/private/fileproxy.php b/lib/private/fileproxy.php deleted file mode 100644 index 8b28e866ac2..00000000000 --- a/lib/private/fileproxy.php +++ /dev/null @@ -1,138 +0,0 @@ -<?php -/** - * @author Bart Visscher <bartv@thisnet.nl> - * @author Felix Moeller <mail@felixmoeller.de> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Robin McCorkell <rmccorkell@karoshi.org.uk> - * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2015, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -/** - * Class for manipulating filesystem requests - * - * Manipulation happens by using 2 kind of proxy operations, pre and post proxies - * that manipulate the filesystem call and the result of the call respectively - * - * A pre-proxy recieves the filepath as arugments (or 2 filespaths in case of - * operations like copy or move) and return a boolean - * If a pre-proxy returns false the file operation will be canceled - * All filesystem operations have a pre-proxy - * - * A post-proxy recieves 2 arguments, the filepath and the result of the operation. - * The return value of the post-proxy will be used as the new result of the operation - * The operations that have a post-proxy are: - * file_get_contents, is_file, is_dir, file_exists, stat, is_readable, - * is_writable, filemtime, filectime, file_get_contents, - * getMimeType, hash, fopen, free_space and search - */ - -class OC_FileProxy{ - private static $proxies=array(); - public static $enabled=true; - - /** - * fallback function when a proxy operation is not implemented - * @param string $function the name of the proxy operation - * @param mixed $arguments - * - * this implements a dummy proxy for all operations - */ - public function __call($function, $arguments) { - if(substr($function, 0, 3)=='pre') { - return true; - }else{ - return $arguments[1]; - } - } - - /** - * register a proxy to be used - * @param OC_FileProxy $proxy - */ - public static function register($proxy) { - self::$proxies[]=$proxy; - } - - /** - * @param string $operation - */ - public static function getProxies($operation = null) { - if ($operation === null) { - // return all - return self::$proxies; - } - $proxies=array(); - foreach(self::$proxies as $proxy) { - if(method_exists($proxy, $operation)) { - $proxies[]=$proxy; - } - } - return $proxies; - } - - /** - * @param string $operation - * @param string|boolean $filepath - */ - public static function runPreProxies($operation,&$filepath,&$filepath2=null) { - if(!self::$enabled) { - return true; - } - $operation='pre'.$operation; - $proxies=self::getProxies($operation); - foreach($proxies as $proxy) { - if(!is_null($filepath2)) { - if($proxy->$operation($filepath, $filepath2)===false) { - return false; - } - }else{ - if($proxy->$operation($filepath)===false) { - return false; - } - } - } - return true; - } - - /** - * @param string $operation - * @param string|boolean $path - * - * @return string - */ - public static function runPostProxies($operation, $path, $result) { - if(!self::$enabled) { - return $result; - } - $operation='post'.$operation; - $proxies=self::getProxies($operation); - foreach($proxies as $proxy) { - $result=$proxy->$operation($path, $result); - } - return $result; - } - - public static function clearProxies() { - self::$proxies=array(); - } -} diff --git a/lib/private/files.php b/lib/private/files.php index d0c1baa0c1e..97f9d8163b1 100644 --- a/lib/private/files.php +++ b/lib/private/files.php @@ -122,7 +122,7 @@ class OC_Files { if ($get_type === self::FILE) { $zip = false; - if ($xsendfile && OC_App::isEnabled('files_encryption')) { + if ($xsendfile && \OC::$server->getEncryptionManager()->isEnabled()) { $xsendfile = false; } } else { diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php index 9a785d071f7..c5e118946e5 100644 --- a/lib/private/files/cache/cache.php +++ b/lib/private/files/cache/cache.php @@ -152,7 +152,7 @@ class Cache { $params = array($file); } $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, - `storage_mtime`, `encrypted`, `unencrypted_size`, `etag`, `permissions` + `storage_mtime`, `encrypted`, `etag`, `permissions` FROM `*PREFIX*filecache` ' . $where; $result = \OC_DB::executeAudited($sql, $params); $data = $result->fetchRow(); @@ -175,7 +175,6 @@ class Cache { $data['mtime'] = (int)$data['mtime']; $data['storage_mtime'] = (int)$data['storage_mtime']; $data['encrypted'] = (bool)$data['encrypted']; - $data['unencrypted_size'] = 0 + $data['unencrypted_size']; $data['storage'] = $this->storageId; $data['mimetype'] = $this->getMimetype($data['mimetype']); $data['mimepart'] = $this->getMimetype($data['mimepart']); @@ -208,7 +207,7 @@ class Cache { public function getFolderContentsById($fileId) { if ($fileId > -1) { $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, - `storage_mtime`, `encrypted`, `unencrypted_size`, `etag`, `permissions` + `storage_mtime`, `encrypted`, `etag`, `permissions` FROM `*PREFIX*filecache` WHERE `parent` = ? ORDER BY `name` ASC'; $result = \OC_DB::executeAudited($sql, array($fileId)); $files = $result->fetchAll(); @@ -218,10 +217,6 @@ class Cache { if ($file['storage_mtime'] == 0) { $file['storage_mtime'] = $file['mtime']; } - if ($file['encrypted'] or ($file['unencrypted_size'] > 0 and $file['mimetype'] === 'httpd/unix-directory')) { - $file['encrypted_size'] = $file['size']; - $file['size'] = $file['unencrypted_size']; - } $file['permissions'] = (int)$file['permissions']; $file['mtime'] = (int)$file['mtime']; $file['storage_mtime'] = (int)$file['storage_mtime']; @@ -325,7 +320,7 @@ class Cache { */ function buildParts(array $data) { $fields = array( - 'path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'storage_mtime', 'encrypted', 'unencrypted_size', + 'path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'storage_mtime', 'encrypted', 'etag', 'permissions'); $params = array(); $queryParts = array(); @@ -521,7 +516,7 @@ class Cache { $sql = ' SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, - `unencrypted_size`, `etag`, `permissions` + `etag`, `permissions` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `name` ILIKE ?'; $result = \OC_DB::executeAudited($sql, @@ -549,7 +544,7 @@ class Cache { } else { $where = '`mimepart` = ?'; } - $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag`, `permissions` + $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag`, `permissions` FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?'; $mimetype = $this->getMimetypeId($mimetype); $result = \OC_DB::executeAudited($sql, array($mimetype, $this->getNumericStorageId())); @@ -574,7 +569,7 @@ class Cache { public function searchByTag($tag, $userId) { $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, ' . '`mimetype`, `mimepart`, `size`, `mtime`, ' . - '`encrypted`, `unencrypted_size`, `etag`, `permissions` ' . + '`encrypted`, `etag`, `permissions` ' . 'FROM `*PREFIX*filecache` `file`, ' . '`*PREFIX*vcategory_to_object` `tagmap`, ' . '`*PREFIX*vcategory` `tag` ' . @@ -638,17 +633,15 @@ class Cache { } if (isset($entry['mimetype']) && $entry['mimetype'] === 'httpd/unix-directory') { $id = $entry['fileid']; - $sql = 'SELECT SUM(`size`) AS f1, MIN(`size`) AS f2, ' . - 'SUM(`unencrypted_size`) AS f3 ' . + $sql = 'SELECT SUM(`size`) AS f1, MIN(`size`) AS f2 ' . 'FROM `*PREFIX*filecache` ' . 'WHERE `parent` = ? AND `storage` = ?'; $result = \OC_DB::executeAudited($sql, array($id, $this->getNumericStorageId())); if ($row = $result->fetchRow()) { $result->closeCursor(); - list($sum, $min, $unencryptedSum) = array_values($row); + list($sum, $min) = array_values($row); $sum = 0 + $sum; $min = 0 + $min; - $unencryptedSum = 0 + $unencryptedSum; if ($min === -1) { $totalSize = $min; } else { @@ -658,15 +651,9 @@ class Cache { if ($entry['size'] !== $totalSize) { $update['size'] = $totalSize; } - if (!isset($entry['unencrypted_size']) or $entry['unencrypted_size'] !== $unencryptedSum) { - $update['unencrypted_size'] = $unencryptedSum; - } if (count($update) > 0) { $this->update($id, $update); } - if ($totalSize !== -1 and $unencryptedSum > 0) { - $totalSize = $unencryptedSum; - } } else { $result->closeCursor(); } diff --git a/lib/private/files/cache/homecache.php b/lib/private/files/cache/homecache.php index aa075d41221..1b85462d615 100644 --- a/lib/private/files/cache/homecache.php +++ b/lib/private/files/cache/homecache.php @@ -48,26 +48,18 @@ class HomeCache extends Cache { } if ($entry && $entry['mimetype'] === 'httpd/unix-directory') { $id = $entry['fileid']; - $sql = 'SELECT SUM(`size`) AS f1, ' . - 'SUM(`unencrypted_size`) AS f2 FROM `*PREFIX*filecache` ' . + $sql = 'SELECT SUM(`size`) AS f1 ' . + 'FROM `*PREFIX*filecache` ' . 'WHERE `parent` = ? AND `storage` = ? AND `size` >= 0'; $result = \OC_DB::executeAudited($sql, array($id, $this->getNumericStorageId())); if ($row = $result->fetchRow()) { $result->closeCursor(); - list($sum, $unencryptedSum) = array_values($row); + list($sum) = array_values($row); $totalSize = 0 + $sum; - $unencryptedSize = 0 + $unencryptedSum; $entry['size'] += 0; - if (!isset($entry['unencrypted_size'])) { - $entry['unencrypted_size'] = 0; - } - $entry['unencrypted_size'] += 0; if ($entry['size'] !== $totalSize) { $this->update($id, array('size' => $totalSize)); } - if ($entry['unencrypted_size'] !== $unencryptedSize) { - $this->update($id, array('unencrypted_size' => $unencryptedSize)); - } } } return $totalSize; diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php index 03aad56e103..82c8f3de690 100644 --- a/lib/private/files/fileinfo.php +++ b/lib/private/files/fileinfo.php @@ -170,13 +170,6 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { /** * @return int */ - public function getUnencryptedSize() { - return isset($this->data['unencrypted_size']) ? $this->data['unencrypted_size'] : 0; - } - - /** - * @return int - */ public function getPermissions() { return $this->data['permissions']; } diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php index 9fef53fa95a..ed85d3c07cc 100644 --- a/lib/private/files/storage/common.php +++ b/lib/private/files/storage/common.php @@ -56,6 +56,9 @@ use OCP\Files\ReservedWordException; * in classes which extend it, e.g. $this->stat() . */ abstract class Common implements Storage { + + use LocalTempFileTrait; + protected $cache; protected $scanner; protected $watcher; @@ -63,11 +66,6 @@ abstract class Common implements Storage { protected $mountOptions = []; - /** - * @var string[] - */ - protected $cachedFiles = array(); - public function __construct($parameters) { } @@ -247,27 +245,6 @@ abstract class Common implements Storage { return $this->getCachedFile($path); } - /** - * @param string $path - * @return string - */ - protected function toTmpFile($path) { //no longer in the storage api, still useful here - $source = $this->fopen($path, 'r'); - if (!$source) { - return false; - } - if ($pos = strrpos($path, '.')) { - $extension = substr($path, $pos); - } else { - $extension = ''; - } - $tmpFile = \OC_Helper::tmpFile($extension); - $target = fopen($tmpFile, 'w'); - \OC_Helper::streamCopy($source, $target); - fclose($target); - return $tmpFile; - } - public function getLocalFolder($path) { $baseDir = \OC_Helper::tmpFolder(); $this->addLocalFolder($path, $baseDir); @@ -451,20 +428,6 @@ abstract class Common implements Storage { } /** - * @param string $path - */ - protected function getCachedFile($path) { - if (!isset($this->cachedFiles[$path])) { - $this->cachedFiles[$path] = $this->toTmpFile($path); - } - return $this->cachedFiles[$path]; - } - - protected function removeCachedFile($path) { - unset($this->cachedFiles[$path]); - } - - /** * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class * * @param string $class diff --git a/lib/private/files/storage/localtempfiletrait.php b/lib/private/files/storage/localtempfiletrait.php new file mode 100644 index 00000000000..444e4e2e89e --- /dev/null +++ b/lib/private/files/storage/localtempfiletrait.php @@ -0,0 +1,85 @@ +<?php +/** + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC\Files\Storage; + +use OC\Files\Cache\Cache; +use OC\Files\Cache\Scanner; +use OC\Files\Filesystem; +use OC\Files\Cache\Watcher; +use OCP\Files\FileNameTooLongException; +use OCP\Files\InvalidCharacterInPathException; +use OCP\Files\InvalidPathException; +use OCP\Files\ReservedWordException; + +/** + * Storage backend class for providing common filesystem operation methods + * which are not storage-backend specific. + * + * \OC\Files\Storage\Common is never used directly; it is extended by all other + * storage backends, where its methods may be overridden, and additional + * (backend-specific) methods are defined. + * + * Some \OC\Files\Storage\Common methods call functions which are first defined + * in classes which extend it, e.g. $this->stat() . + */ +trait LocalTempFileTrait { + + /** + * @var string[] + */ + protected $cachedFiles = array(); + + /** + * @param string $path + */ + protected function getCachedFile($path) { + if (!isset($this->cachedFiles[$path])) { + $this->cachedFiles[$path] = $this->toTmpFile($path); + } + return $this->cachedFiles[$path]; + } + + protected function removeCachedFile($path) { + unset($this->cachedFiles[$path]); + } + + /** + * @param string $path + * @return string + */ + protected function toTmpFile($path) { //no longer in the storage api, still useful here + $source = $this->fopen($path, 'r'); + if (!$source) { + return false; + } + if ($pos = strrpos($path, '.')) { + $extension = substr($path, $pos); + } else { + $extension = ''; + } + $tmpFile = \OC_Helper::tmpFile($extension); + $target = fopen($tmpFile, 'w'); + \OC_Helper::streamCopy($source, $target); + fclose($target); + return $tmpFile; + } +} diff --git a/lib/private/files/storage/wrapper/encryption.php b/lib/private/files/storage/wrapper/encryption.php index 0e70c99c8d7..5245fe4cc45 100644 --- a/lib/private/files/storage/wrapper/encryption.php +++ b/lib/private/files/storage/wrapper/encryption.php @@ -24,9 +24,13 @@ namespace OC\Files\Storage\Wrapper; use OC\Encryption\Exceptions\ModuleDoesNotExistsException; +use OC\Files\Storage\LocalTempFileTrait; +use OCP\Files\Mount\IMountPoint; class Encryption extends Wrapper { + use LocalTempFileTrait; + /** @var string */ private $mountPoint; @@ -45,11 +49,18 @@ class Encryption extends Wrapper { /** @var array */ private $unencryptedSize; + /** @var \OC\Encryption\File */ + private $fileHelper; + + /** @var IMountPoint */ + private $mount; + /** * @param array $parameters * @param \OC\Encryption\Manager $encryptionManager * @param \OC\Encryption\Util $util * @param \OC\Log $logger + * @param \OC\Encryption\File $fileHelper * @param string $uid user who perform the read/write operation (null for public access) */ public function __construct( @@ -57,14 +68,17 @@ class Encryption extends Wrapper { \OC\Encryption\Manager $encryptionManager = null, \OC\Encryption\Util $util = null, \OC\Log $logger = null, + \OC\Encryption\File $fileHelper = null, $uid = null ) { $this->mountPoint = $parameters['mountPoint']; + $this->mount = $parameters['mount']; $this->encryptionManager = $encryptionManager; $this->util = $util; $this->logger = $logger; $this->uid = $uid; + $this->fileHelper = $fileHelper; $this->unencryptedSize = array(); parent::__construct($parameters); } @@ -77,27 +91,18 @@ class Encryption extends Wrapper { * @return int */ public function filesize($path) { - $size = 0; $fullPath = $this->getFullPath($path); - - $encryptedSize = $this->storage->filesize($path); + $size = $this->storage->filesize($path); $info = $this->getCache()->get($path); - if($encryptedSize > 0 && $info['encrypted']) { - $size = $info['unencrypted_size']; - if ($size <= 0) { - $encryptionModule = $this->getEncryptionModule($path); - if ($encryptionModule) { - $size = $encryptionModule->calculateUnencryptedSize($fullPath); - $this->getCache()->update($info['fileid'], array('unencrypted_size' => $size)); - } - } - } else if (isset($this->unencryptedSize[$fullPath]) && isset($info['fileid'])) { + if (isset($this->unencryptedSize[$fullPath])) { $size = $this->unencryptedSize[$fullPath]; + } + + if (isset($info['fileid'])) { $info['encrypted'] = true; - $info['unencrypted_size'] = $size; - $info['size'] = $encryptedSize; + $info['size'] = $size; $this->getCache()->put($path, $info); } @@ -112,23 +117,18 @@ class Encryption extends Wrapper { */ public function file_get_contents($path) { - $data = null; $encryptionModule = $this->getEncryptionModule($path); if ($encryptionModule) { - - $handle = $this->fopen($path, 'r'); - - if (is_resource($handle)) { - while (!feof($handle)) { - $data .= fread($handle, $this->util->getBlockSize()); - } + $handle = $this->fopen($path, "r"); + if (!$handle) { + return false; } - } else { - $data = $this->storage->file_get_contents($path); + $data = stream_get_contents($handle); + fclose($handle); + return $data; } - - return $data; + return $this->storage->file_get_contents($path); } /** @@ -141,8 +141,9 @@ class Encryption extends Wrapper { public function file_put_contents($path, $data) { // file put content will always be translated to a stream write $handle = $this->fopen($path, 'w'); - fwrite($handle, $data); - return fclose($handle); + $written = fwrite($handle, $data); + fclose($handle); + return $written; } /** @@ -158,8 +159,8 @@ class Encryption extends Wrapper { $encryptionModule = $this->getEncryptionModule($path); if ($encryptionModule) { - $keyStorage = \OC::$server->getEncryptionKeyStorage($encryptionModule->getId()); - $keyStorage->deleteAllFileKeys($this->getFullPath($path)); + $keyStorage = $this->getKeyStorage($encryptionModule->getId()); + $keyStorage->deleteAllFileKeys($this->getFullPath($path)); } return $this->storage->unlink($path); @@ -177,17 +178,14 @@ class Encryption extends Wrapper { return $this->storage->rename($path1, $path2); } - $fullPath1 = $this->getFullPath($path1); - list($owner, $source) = $this->util->getUidAndFilename($fullPath1); + $source = $this->getFullPath($path1); $result = $this->storage->rename($path1, $path2); if ($result) { - $fullPath2 = $this->getFullPath($path2); - $systemWide = $this->util->isSystemWideMountPoint($this->mountPoint); - list(, $target) = $this->util->getUidAndFilename($fullPath2); + $target = $this->getFullPath($path2); $encryptionModule = $this->getEncryptionModule($path2); if ($encryptionModule) { - $keyStorage = \OC::$server->getEncryptionKeyStorage($encryptionModule->getId()); - $keyStorage->renameKeys($source, $target, $owner, $systemWide); + $keyStorage = $this->getKeyStorage($encryptionModule->getId()); + $keyStorage->renameKeys($source, $target); } } @@ -202,9 +200,22 @@ class Encryption extends Wrapper { * @return bool */ public function copy($path1, $path2) { - // todo copy encryption keys, get users with access to the file and reencrypt - // or is this to encryption module specific? Then we can hand this over - return $this->storage->copy($path1, $path2); + if ($this->util->isExcluded($path1)) { + return $this->storage->rename($path1, $path2); + } + + $source = $this->getFullPath($path1); + $result = $this->storage->copy($path1, $path2); + if ($result) { + $target = $this->getFullPath($path2); + $encryptionModule = $this->getEncryptionModule($path2); + if ($encryptionModule) { + $keyStorage = $this->getKeyStorage($encryptionModule->getId()); + $keyStorage->copyKeys($source, $target); + } + } + + return $result; } /** @@ -223,7 +234,17 @@ class Encryption extends Wrapper { $encryptionModuleId = $this->util->getEncryptionModuleId($header); $size = $unencryptedSize = 0; - if ($this->file_exists($path)) { + $targetExists = $this->file_exists($path); + $targetIsEncrypted = false; + if ($targetExists) { + // in case the file exists we require the explicit module as + // specified in the file header - otherwise we need to fail hard to + // prevent data loss on client side + if (!empty($encryptionModuleId)) { + $targetIsEncrypted = true; + $encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId); + } + $size = $this->storage->filesize($path); $unencryptedSize = $this->filesize($path); } @@ -254,10 +275,18 @@ class Encryption extends Wrapper { '" not found, file will be stored unencrypted'); } + // encryption disabled on write of new file and write to existing unencrypted file -> don't encrypt + $encEnabled = $this->encryptionManager->isEnabled(); + if (!$encEnabled || !$this->mount->getOption('encrypt', true)) { + if (!$targetExists || !$targetIsEncrypted) { + $shouldEncrypt = false; + } + } + if($shouldEncrypt === true && !$this->util->isExcluded($fullPath) && $encryptionModule !== null) { $source = $this->storage->fopen($path, $mode); $handle = \OC\Files\Stream\Encryption::wrap($source, $path, $fullPath, $header, - $this->uid, $encryptionModule, $this->storage, $this, $this->util, $mode, + $this->uid, $encryptionModule, $this->storage, $this, $this->util, $this->fileHelper, $mode, $size, $unencryptedSize); return $handle; } else { @@ -266,6 +295,57 @@ class Encryption extends Wrapper { } /** + * 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) { + return $this->getCachedFile($path); + } + + /** + * Returns the wrapped storage's value for isLocal() + * + * @return bool wrapped storage's isLocal() value + */ + public function isLocal() { + return false; + } + + /** + * see http://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); + $fileSize = $this->filesize($path); + $stat['size'] = $fileSize; + $stat[7] = $fileSize; + return $stat; + } + + /** + * see http://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); + hash_update_stream($ctx, $fh); + fclose($fh); + return hash_final($ctx, $raw); + } + + /** * return full path, including mount point * * @param string $path relative to mount point @@ -295,7 +375,9 @@ class Encryption extends Wrapper { * read encryption module needed to read/write the file located at $path * * @param string $path - * @return \OCP\Encryption\IEncryptionModule|null + * @return null|\OCP\Encryption\IEncryptionModule + * @throws ModuleDoesNotExistsException + * @throws \Exception */ protected function getEncryptionModule($path) { $encryptionModule = null; @@ -305,7 +387,7 @@ class Encryption extends Wrapper { try { $encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId); } catch (ModuleDoesNotExistsException $e) { - $this->logger->critical('Encryption module defined in "' . $path . '" mot loaded!'); + $this->logger->critical('Encryption module defined in "' . $path . '" not loaded!'); throw $e; } } @@ -316,4 +398,13 @@ class Encryption extends Wrapper { $this->unencryptedSize[$path] = $unencryptedSize; } + /** + * @param string $encryptionModuleId + * @return \OCP\Encryption\Keys\IStorage + */ + protected function getKeyStorage($encryptionModuleId) { + $keyStorage = \OC::$server->getEncryptionKeyStorage($encryptionModuleId); + return $keyStorage; + } + } diff --git a/lib/private/files/storage/wrapper/quota.php b/lib/private/files/storage/wrapper/quota.php index 34bd2589947..3c0fda98dad 100644 --- a/lib/private/files/storage/wrapper/quota.php +++ b/lib/private/files/storage/wrapper/quota.php @@ -60,11 +60,6 @@ class Quota extends Wrapper { $cache = $this->getCache(); $data = $cache->get($path); if (is_array($data) and isset($data['size'])) { - if (isset($data['unencrypted_size']) - && $data['unencrypted_size'] > 0 - ) { - return $data['unencrypted_size']; - } return $data['size']; } else { return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED; diff --git a/lib/private/files/stream/encryption.php b/lib/private/files/stream/encryption.php index ddef9067bad..b4e06c99943 100644 --- a/lib/private/files/stream/encryption.php +++ b/lib/private/files/stream/encryption.php @@ -31,6 +31,9 @@ class Encryption extends Wrapper { /** @var \OC\Encryption\Util */ protected $util; + /** @var \OC\Encryption\File */ + protected $file; + /** @var \OCP\Encryption\IEncryptionModule */ protected $encryptionModule; @@ -43,6 +46,9 @@ class Encryption extends Wrapper { /** @var string */ protected $internalPath; + /** @var string */ + protected $cache; + /** @var integer */ protected $size; @@ -72,13 +78,16 @@ class Encryption extends Wrapper { /** * user who perform the read/write operation null for public access * - * @var string + * @var string */ protected $uid; /** @var bool */ protected $readOnly; + /** @var bool */ + protected $writeFlag; + /** @var array */ protected $expectedContextProperties; @@ -91,6 +100,7 @@ class Encryption extends Wrapper { 'encryptionModule', 'header', 'uid', + 'file', 'util', 'size', 'unencryptedSize', @@ -106,11 +116,12 @@ class Encryption extends Wrapper { * @param string $internalPath relative to mount point * @param string $fullPath relative to data/ * @param array $header - * @param sting $uid + * @param string $uid * @param \OCP\Encryption\IEncryptionModule $encryptionModule * @param \OC\Files\Storage\Storage $storage - * @param OC\Files\Storage\Wrapper\Encryption $encStorage + * @param \OC\Files\Storage\Wrapper\Encryption $encStorage * @param \OC\Encryption\Util $util + * @param \OC\Encryption\File $file * @param string $mode * @param int $size * @param int $unencryptedSize @@ -119,9 +130,15 @@ class Encryption extends Wrapper { * @throws \BadMethodCallException */ public static function wrap($source, $internalPath, $fullPath, array $header, - $uid, \OCP\Encryption\IEncryptionModule $encryptionModule, - \OC\Files\Storage\Storage $storage, \OC\Files\Storage\Wrapper\Encryption $encStorage, - \OC\Encryption\Util $util, $mode, $size, $unencryptedSize) { + $uid, + \OCP\Encryption\IEncryptionModule $encryptionModule, + \OC\Files\Storage\Storage $storage, + \OC\Files\Storage\Wrapper\Encryption $encStorage, + \OC\Encryption\Util $util, + \OC\Encryption\File $file, + $mode, + $size, + $unencryptedSize) { $context = stream_context_create(array( 'ocencryption' => array( @@ -133,6 +150,7 @@ class Encryption extends Wrapper { 'header' => $header, 'uid' => $uid, 'util' => $util, + 'file' => $file, 'size' => $size, 'unencryptedSize' => $unencryptedSize, 'encryptionStorage' => $encStorage @@ -180,7 +198,7 @@ class Encryption extends Wrapper { $context = parent::loadContext($name); foreach ($this->expectedContextProperties as $property) { - if (isset($context[$property])) { + if (array_key_exists($property, $context)) { $this->{$property} = $context[$property]; } else { throw new \BadMethodCallException('Invalid context, "' . $property . '" options not set'); @@ -194,6 +212,8 @@ class Encryption extends Wrapper { $this->loadContext('ocencryption'); $this->position = 0; + $this->cache = ''; + $this->writeFlag = false; $this->unencryptedBlockSize = $this->encryptionModule->getUnencryptedBlockSize(); if ( @@ -216,7 +236,7 @@ class Encryption extends Wrapper { $sharePath = dirname($path); } - $accessList = $this->util->getSharingUsersArray($sharePath); + $accessList = $this->file->getAccessList($sharePath); $this->newHeader = $this->encryptionModule->begin($this->fullPath, $this->uid, $this->header, $accessList); return true; @@ -228,25 +248,26 @@ class Encryption extends Wrapper { $result = ''; // skip the header if we read the file from the beginning - if ($this->position === 0 && !empty($this->header)) { - parent::stream_read($this->util->getBlockSize()); + if ($this->position === 0) { + parent::stream_read($this->util->getHeaderSize()); } +// $count = min($count, $this->unencryptedSize - $this->position); while ($count > 0) { $remainingLength = $count; // update the cache of the current block - $data = parent::stream_read($this->util->getBlockSize()); - $decrypted = $this->encryptionModule->decrypt($data); + $this->readCache(); // determine the relative position in the current block $blockPosition = ($this->position % $this->unencryptedBlockSize); // if entire read inside current block then only position needs to be updated if ($remainingLength < ($this->unencryptedBlockSize - $blockPosition)) { - $result .= substr($decrypted, $blockPosition, $remainingLength); + $result .= substr($this->cache, $blockPosition, $remainingLength); $this->position += $remainingLength; $count = 0; - // otherwise remainder of current block is fetched, the block is flushed and the position updated + // otherwise remainder of current block is fetched, the block is flushed and the position updated } else { - $result .= substr($decrypted, $blockPosition); + $result .= substr($this->cache, $blockPosition); + $this->flush(); $this->position += ($this->unencryptedBlockSize - $blockPosition); $count -= ($this->unencryptedBlockSize - $blockPosition); } @@ -259,6 +280,7 @@ class Encryption extends Wrapper { if ($this->position === 0) { $this->writeHeader(); + $this->size+=$this->util->getHeaderSize(); } $length = 0; @@ -266,9 +288,8 @@ class Encryption extends Wrapper { while (strlen($data) > 0) { $remainingLength = strlen($data); - // read current block - $currentBlock = parent::stream_read($this->util->getBlockSize()); - $decrypted = $this->encryptionModule->decrypt($currentBlock, $this->uid); + // set the cache to the current 6126 block + $this->readCache(); // for seekable streams the pointer is moved back to the beginning of the encrypted block // flush will start writing there when the position moves to another block @@ -277,7 +298,10 @@ class Encryption extends Wrapper { $resultFseek = parent::stream_seek($positionInFile); // only allow writes on seekable streams, or at the end of the encrypted stream - if ($resultFseek || $positionInFile === $this->size) { + if (!($this->readOnly) && ($resultFseek || $positionInFile === $this->size)) { + + // switch the writeFlag so flush() will write the block + $this->writeFlag = true; // determine the relative position in the current block $blockPosition = ($this->position % $this->unencryptedBlockSize); @@ -285,28 +309,22 @@ class Encryption extends Wrapper { // if so, overwrite existing data (if any) // update position and liberate $data if ($remainingLength < ($this->unencryptedBlockSize - $blockPosition)) { - $decrypted = substr($decrypted, 0, $blockPosition) - . $data . substr($decrypted, $blockPosition + $remainingLength); - $encrypted = $this->encryptionModule->encrypt($decrypted); - parent::stream_write($encrypted); + $this->cache = substr($this->cache, 0, $blockPosition) + . $data . substr($this->cache, $blockPosition + $remainingLength); $this->position += $remainingLength; $length += $remainingLength; $data = ''; - // if $data doens't fit the current block, the fill the current block and reiterate - // after the block is filled, it is flushed and $data is updatedxxx + // if $data doesn't fit the current block, the fill the current block and reiterate + // after the block is filled, it is flushed and $data is updatedxxx } else { - $decrypted = substr($decrypted, 0, $blockPosition) . + $this->cache = substr($this->cache, 0, $blockPosition) . substr($data, 0, $this->unencryptedBlockSize - $blockPosition); - $encrypted = $this->encryptionModule->encrypt($decrypted); - parent::stream_write($encrypted); + $this->flush(); $this->position += ($this->unencryptedBlockSize - $blockPosition); - $this->size = max($this->size, $this->stream_tell()); $length += ($this->unencryptedBlockSize - $blockPosition); $data = substr($data, $this->unencryptedBlockSize - $blockPosition); } } else { - $encrypted = $this->encryptionModule->encrypt($data); - parent::stream_write($encrypted); $data = ''; } } @@ -345,7 +363,11 @@ class Encryption extends Wrapper { $newFilePosition = floor($newPosition / $this->unencryptedBlockSize) * $this->util->getBlockSize() + $this->util->getHeaderSize(); + $oldFilePosition = parent::stream_tell(); if (parent::stream_seek($newFilePosition)) { + parent::stream_seek($oldFilePosition); + $this->flush(); + parent::stream_seek($newFilePosition); $this->position = $newPosition; $return = true; } @@ -355,13 +377,6 @@ class Encryption extends Wrapper { public function stream_close() { $this->flush(); - return parent::stream_close(); - } - - /** - * tell encryption module that we are done and write remaining data to the file - */ - protected function flush() { $remainingData = $this->encryptionModule->end($this->fullPath); if ($this->readOnly === false) { if(!empty($remainingData)) { @@ -369,17 +384,50 @@ class Encryption extends Wrapper { } $this->encryptionStorage->updateUnencryptedSize($this->fullPath, $this->unencryptedSize); } + return parent::stream_close(); } + /** + * write block to file + */ + protected function flush() { + // write to disk only when writeFlag was set to 1 + if ($this->writeFlag) { + // Disable the file proxies so that encryption is not + // automatically attempted when the file is written to disk - + // we are handling that separately here and we don't want to + // get into an infinite loop + $encrypted = $this->encryptionModule->encrypt($this->cache); + parent::stream_write($encrypted); + $this->writeFlag = false; + $this->size = max($this->size, parent::stream_tell()); + } + // always empty the cache (otherwise readCache() will not fill it with the new block) + $this->cache = ''; + } + + /** + * read block to file + */ + protected function readCache() { + // cache should always be empty string when this function is called + // don't try to fill the cache when trying to write at the end of the unencrypted file when it coincides with new block + if ($this->cache === '' && !($this->position === $this->unencryptedSize && ($this->position % $this->unencryptedBlockSize) === 0)) { + // Get the data from the file handle + $data = parent::stream_read($this->util->getBlockSize()); + $this->cache = $this->encryptionModule->decrypt($data); + } + } /** * write header at beginning of encrypted file * + * @return integer * @throws EncryptionHeaderKeyExistsException if header key is already in use */ private function writeHeader() { $header = $this->util->createHeader($this->newHeader, $this->encryptionModule); - parent::stream_write($header); + return parent::stream_write($header); } } diff --git a/lib/private/files/view.php b/lib/private/files/view.php index f8ec4a0eb43..0f371bbc5ea 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -515,8 +515,7 @@ class View { public function file_put_contents($path, $data) { if (is_resource($data)) { //not having to deal with streams in file_put_contents makes life easier $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); - if (\OC_FileProxy::runPreProxies('file_put_contents', $absolutePath, $data) - and Filesystem::isValidPath($path) + if (Filesystem::isValidPath($path) and !Filesystem::isFileBlacklisted($path) ) { $path = $this->getRelativePath($absolutePath); @@ -537,7 +536,6 @@ class View { if ($this->shouldEmitHooks($path) && $result !== false) { $this->emit_file_hooks_post($exists, $path); } - \OC_FileProxy::runPostProxies('file_put_contents', $absolutePath, $count); return $result; } else { return false; @@ -591,8 +589,7 @@ class View { $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1)); $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2)); if ( - \OC_FileProxy::runPreProxies('rename', $absolutePath1, $absolutePath2) - and Filesystem::isValidPath($path2) + Filesystem::isValidPath($path2) and Filesystem::isValidPath($path1) and !Filesystem::isFileBlacklisted($path2) ) { @@ -635,14 +632,12 @@ class View { $sourceMountPoint = $mount->getMountPoint(); $result = $mount->moveMount($absolutePath2); $manager->moveMount($sourceMountPoint, $mount->getMountPoint()); - \OC_FileProxy::runPostProxies('rename', $absolutePath1, $absolutePath2); } else { $result = false; } } elseif ($mp1 == $mp2) { if ($storage1) { $result = $storage1->rename($internalPath1, $internalPath2); - \OC_FileProxy::runPostProxies('rename', $absolutePath1, $absolutePath2); } else { $result = false; } @@ -718,8 +713,7 @@ class View { $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1)); $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2)); if ( - \OC_FileProxy::runPreProxies('copy', $absolutePath1, $absolutePath2) - and Filesystem::isValidPath($path2) + Filesystem::isValidPath($path2) and Filesystem::isValidPath($path1) and !Filesystem::isFileBlacklisted($path2) ) { @@ -927,7 +921,7 @@ class View { public function hash($type, $path, $raw = false) { $postFix = (substr($path, -1, 1) === '/') ? '/' : ''; $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); - if (\OC_FileProxy::runPreProxies('hash', $absolutePath) && Filesystem::isValidPath($path)) { + if (Filesystem::isValidPath($path)) { $path = $this->getRelativePath($absolutePath); if ($path == null) { return false; @@ -942,7 +936,6 @@ class View { list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix); if ($storage) { $result = $storage->hash($type, $internalPath, $raw); - $result = \OC_FileProxy::runPostProxies('hash', $absolutePath, $result); return $result; } } @@ -975,8 +968,7 @@ class View { private function basicOperation($operation, $path, $hooks = array(), $extraParam = null) { $postFix = (substr($path, -1, 1) === '/') ? '/' : ''; $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); - if (\OC_FileProxy::runPreProxies($operation, $absolutePath, $extraParam) - and Filesystem::isValidPath($path) + if (Filesystem::isValidPath($path) and !Filesystem::isFileBlacklisted($path) ) { $path = $this->getRelativePath($absolutePath); @@ -993,8 +985,6 @@ class View { $result = $storage->$operation($internalPath); } - $result = \OC_FileProxy::runPostProxies($operation, $this->getAbsolutePath($path), $result); - if (in_array('delete', $hooks) and $result) { $this->updater->remove($path); } @@ -1168,8 +1158,6 @@ class View { $data['permissions'] |= \OCP\Constants::PERMISSION_DELETE; } - $data = \OC_FileProxy::runPostProxies('getFileInfo', $path, $data); - return new FileInfo($path, $storage, $internalPath, $data, $mount); } diff --git a/lib/private/hook.php b/lib/private/hook.php index d2a0fa898dd..c4ea1999b09 100644 --- a/lib/private/hook.php +++ b/lib/private/hook.php @@ -32,38 +32,39 @@ class OC_Hook{ /** * connects a function to a hook - * @param string $signalclass class name of emitter - * @param string $signalname name of signal - * @param string $slotclass class name of slot - * @param string $slotname name of slot + * + * @param string $signalClass class name of emitter + * @param string $signalName name of signal + * @param string|object $slotClass class name of slot + * @param string $slotName name of slot * @return bool * * This function makes it very easy to connect to use hooks. * * TODO: write example */ - static public function connect( $signalclass, $signalname, $slotclass, $slotname ) { + static public function connect($signalClass, $signalName, $slotClass, $slotName ) { // If we're trying to connect to an emitting class that isn't // yet registered, register it - if( !array_key_exists( $signalclass, self::$registered )) { - self::$registered[$signalclass] = array(); + if( !array_key_exists($signalClass, self::$registered )) { + self::$registered[$signalClass] = array(); } // If we're trying to connect to an emitting method that isn't // yet registered, register it with the emitting class - if( !array_key_exists( $signalname, self::$registered[$signalclass] )) { - self::$registered[$signalclass][$signalname] = array(); + if( !array_key_exists( $signalName, self::$registered[$signalClass] )) { + self::$registered[$signalClass][$signalName] = array(); } // dont connect hooks twice - foreach (self::$registered[$signalclass][$signalname] as $hook) { - if ($hook['class'] === $slotclass and $hook['name'] === $slotname) { + foreach (self::$registered[$signalClass][$signalName] as $hook) { + if ($hook['class'] === $slotClass and $hook['name'] === $slotName) { return false; } } // Connect the hook handler to the requested emitter - self::$registered[$signalclass][$signalname][] = array( - "class" => $slotclass, - "name" => $slotname + self::$registered[$signalClass][$signalName][] = array( + "class" => $slotClass, + "name" => $slotName ); // No chance for failure ;-) @@ -72,8 +73,9 @@ class OC_Hook{ /** * emits a signal - * @param string $signalclass class name of emitter - * @param string $signalname name of signal + * + * @param string $signalClass class name of emitter + * @param string $signalName name of signal * @param mixed $params default: array() array with additional data * @return bool true if slots exists or false if not * @@ -81,28 +83,36 @@ class OC_Hook{ * * TODO: write example */ - static public function emit( $signalclass, $signalname, $params = array()) { + static public function emit($signalClass, $signalName, $params = array()) { // Return false if no hook handlers are listening to this // emitting class - if( !array_key_exists( $signalclass, self::$registered )) { + if( !array_key_exists($signalClass, self::$registered )) { return false; } // Return false if no hook handlers are listening to this // emitting method - if( !array_key_exists( $signalname, self::$registered[$signalclass] )) { + if( !array_key_exists( $signalName, self::$registered[$signalClass] )) { return false; } // Call all slots - foreach( self::$registered[$signalclass][$signalname] as $i ) { + foreach( self::$registered[$signalClass][$signalName] as $i ) { try { call_user_func( array( $i["class"], $i["name"] ), $params ); } catch (Exception $e){ self::$thrownExceptions[] = $e; + $class = $i["class"]; + if (is_object($i["class"])) { + $class = get_class($i["class"]); + } + $message = $e->getMessage(); + if (empty($message)) { + $message = get_class($e); + } OC_Log::write('hook', - 'error while running hook (' . $i["class"] . '::' . $i["name"] . '): '.$e->getMessage(), + 'error while running hook (' . $class . '::' . $i["name"] . '): ' . $message, OC_Log::ERROR); } } diff --git a/lib/private/server.php b/lib/private/server.php index 8c5169f229e..661aaf6786d 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -87,6 +87,11 @@ class Server extends SimpleContainer implements IServerContainer { return new Encryption\Manager($c->getConfig()); }); + $this->registerService('EncryptionFileHelper', function (Server $c) { + $util = new \OC\Encryption\Util(new \OC\Files\View(), $c->getUserManager(), $c->getConfig()); + return new Encryption\File($util); + }); + $this->registerService('EncryptionKeyStorageFactory', function ($c) { return new Encryption\Keys\Factory(); }); @@ -408,13 +413,20 @@ class Server extends SimpleContainer implements IServerContainer { } /** + * @return \OC\Encryption\File + */ + function getEncryptionFilesHelper() { + return $this->query('EncryptionFileHelper'); + } + + /** * @param string $encryptionModuleId encryption module ID * * @return \OCP\Encryption\Keys\IStorage */ function getEncryptionKeyStorage($encryptionModuleId) { $view = new \OC\Files\View(); - $util = new \OC\Encryption\Util($view, \OC::$server->getUserManager()); + $util = new \OC\Encryption\Util($view, \OC::$server->getUserManager(), \OC::$server->getConfig()); return $this->query('EncryptionKeyStorageFactory')->get($encryptionModuleId, $view, $util); } @@ -496,19 +508,7 @@ class Server extends SimpleContainer implements IServerContainer { $dir = '/files'; if (!$folder->nodeExists($dir)) { $folder = $folder->newFolder($dir); - - if (\OCP\App::isEnabled('files_encryption')) { - // disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - } - \OC_Util::copySkeleton($user, $folder); - - if (\OCP\App::isEnabled('files_encryption')) { - // re-enable proxy - our work is done - \OC_FileProxy::$enabled = $proxyStatus; - } } else { $folder = $folder->get($dir); } diff --git a/lib/private/share/share.php b/lib/private/share/share.php index 90f3f28f2ee..98c612d5eb6 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -2214,7 +2214,7 @@ class Share extends \OC\Share\Constants { $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, ' . '`share_type`, `share_with`, `file_source`, `path`, `file_target`, `stime`, ' . '`*PREFIX*share`.`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, ' - . '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `unencrypted_size`, `encrypted`, `etag`, `mail_send`'; + . '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`, `mail_send`'; } else { $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`,' . '`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`,' diff --git a/lib/private/util.php b/lib/private/util.php index e6dd307faea..3fd0f844684 100644 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -812,51 +812,6 @@ class OC_Util { return $errors; } - - /** - * check if there are still some encrypted files stored - * - * @return boolean - */ - public static function encryptedFiles() { - //check if encryption was enabled in the past - $encryptedFiles = false; - if (OC_App::isEnabled('files_encryption') === false) { - $view = new OC\Files\View('/' . OCP\User::getUser()); - $keysPath = '/files_encryption/keys'; - if ($view->is_dir($keysPath)) { - $dircontent = $view->getDirectoryContent($keysPath); - if (!empty($dircontent)) { - $encryptedFiles = true; - } - } - } - - return $encryptedFiles; - } - - /** - * check if a backup from the encryption keys exists - * - * @return boolean - */ - public static function backupKeysExists() { - //check if encryption was enabled in the past - $backupExists = false; - if (OC_App::isEnabled('files_encryption') === false) { - $view = new OC\Files\View('/' . OCP\User::getUser()); - $backupPath = '/files_encryption/backup.decryptAll'; - if ($view->is_dir($backupPath)) { - $dircontent = $view->getDirectoryContent($backupPath); - if (!empty($dircontent)) { - $backupExists = true; - } - } - } - - return $backupExists; - } - /** * Check for correct file permissions of data directory * diff --git a/lib/public/encryption/exceptions/genericencryptionexception.php b/lib/public/encryption/exceptions/genericencryptionexception.php new file mode 100644 index 00000000000..b7addd3b0c1 --- /dev/null +++ b/lib/public/encryption/exceptions/genericencryptionexception.php @@ -0,0 +1,34 @@ +<?php + /** + * @author Clark Tomlinson <clark@owncloud.com> + * @since 2/25/15, 9:30 AM + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\Encryption\Exceptions; + + +class GenericEncryptionException extends \Exception { + + public function __construct($message = "", $code = 0, \Exception $previous = null) { + if (empty($message)) { + $message = 'Unspecified encryption exception'; + } + parent::__construct($message, $code, $previous); + } + +} diff --git a/lib/public/encryption/ifile.php b/lib/public/encryption/ifile.php new file mode 100644 index 00000000000..464f41509d2 --- /dev/null +++ b/lib/public/encryption/ifile.php @@ -0,0 +1,36 @@ +<?php + +/** + * ownCloud + * + * @copyright (C) 2015 ownCloud, Inc. + * + * @author Bjoern Schiessle <schiessle@owncloud.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCP\Encryption; + +interface IFile { + + /** + * get list of users with access to the file + * + * @param string $path to the file + * @return array + */ + public function getAccessList($path); + +} diff --git a/lib/public/encryption/imanager.php b/lib/public/encryption/imanager.php index 9a12e401593..2691604ac37 100644 --- a/lib/public/encryption/imanager.php +++ b/lib/public/encryption/imanager.php @@ -22,9 +22,7 @@ */ namespace OCP\Encryption; -// -// TODO: move exceptions to OCP -// + use OC\Encryption\Exceptions\ModuleDoesNotExistsException; use OC\Encryption\Exceptions\ModuleAlreadyExistsException; diff --git a/lib/public/encryption/keys/istorage.php b/lib/public/encryption/keys/istorage.php index 4c2b01f4ad0..2d1672face5 100644 --- a/lib/public/encryption/keys/istorage.php +++ b/lib/public/encryption/keys/istorage.php @@ -122,4 +122,20 @@ interface IStorage { */ public function deleteSystemUserKey($keyId); + /** + * copy keys if a file was renamed + * + * @param string $source + * @param string $target + */ + public function renameKeys($source, $target); + + /** + * move keys if a file was renamed + * + * @param string $source + * @param string $target + */ + public function copyKeys($source, $target); + } diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index d7df884adf8..509e5894d47 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -150,13 +150,19 @@ interface IServerContainer { function getHasher(); /** + * Returns a SecureRandom instance + * + * @return \OCP\Security\ISecureRandom + */ + function getSecureRandom(); + + /** * Returns an instance of the db facade * @deprecated use getDatabaseConnection, will be removed in ownCloud 10 * @return \OCP\IDb */ function getDb(); - /** * Returns the app config manager * @@ -173,6 +179,23 @@ interface IServerContainer { function getL10N($app, $lang = null); /** + * @return \OC\Encryption\Manager + */ + function getEncryptionManager(); + + /** + * @return \OC\Encryption\File + */ + function getEncryptionFilesHelper(); + + /** + * @param string $encryptionModuleId encryption module ID + * + * @return \OCP\Encryption\Keys\IStorage + */ + function getEncryptionKeyStorage($encryptionModuleId); + + /** * Returns the URL generator * * @return \OCP\IURLGenerator diff --git a/lib/public/util.php b/lib/public/util.php index b50ce54839b..721bcaadb62 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -219,9 +219,11 @@ class Util { /** * check if some encrypted files are stored * @return bool + * + * @deprecated No longer required */ public static function encryptedFiles() { - return \OC_Util::encryptedFiles(); + return false; } /** @@ -392,18 +394,19 @@ class Util { /** * connects a function to a hook - * @param string $signalclass class name of emitter - * @param string $signalname name of signal - * @param string $slotclass class name of slot - * @param string $slotname name of slot + * + * @param string $signalClass class name of emitter + * @param string $signalName name of signal + * @param string|object $slotClass class name of slot + * @param string $slotName name of slot * @return bool * * This function makes it very easy to connect to use hooks. * * TODO: write example */ - static public function connectHook( $signalclass, $signalname, $slotclass, $slotname ) { - return(\OC_Hook::connect( $signalclass, $signalname, $slotclass, $slotname )); + static public function connectHook($signalClass, $signalName, $slotClass, $slotName ) { + return(\OC_Hook::connect($signalClass, $signalName, $slotClass, $slotName )); } /** |