diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/private/app/codechecker.php | 2 | ||||
-rw-r--r-- | lib/private/connector/sabre/blocklegacyclientplugin.php | 79 | ||||
-rw-r--r-- | lib/private/encryption/file.php | 4 | ||||
-rw-r--r-- | lib/private/encryption/keys/storage.php | 9 | ||||
-rw-r--r-- | lib/private/encryption/manager.php | 20 | ||||
-rw-r--r-- | lib/private/encryption/update.php | 66 | ||||
-rw-r--r-- | lib/private/encryption/util.php | 20 | ||||
-rw-r--r-- | lib/private/files/storage/wrapper/encryption.php | 58 | ||||
-rw-r--r-- | lib/private/files/stream/encryption.php | 40 | ||||
-rw-r--r-- | lib/public/encryption/keys/istorage.php | 2 |
10 files changed, 232 insertions, 68 deletions
diff --git a/lib/private/app/codechecker.php b/lib/private/app/codechecker.php index c8c66d6dcab..75db9ab3560 100644 --- a/lib/private/app/codechecker.php +++ b/lib/private/app/codechecker.php @@ -99,7 +99,7 @@ class CodeChecker extends BasicEmitter { $excludes = array_map(function($item) use ($folder) { return $folder . '/' . $item; - }, ['vendor', '3rdparty', '.git', 'l10n']); + }, ['vendor', '3rdparty', '.git', 'l10n', 'tests', 'test']); $iterator = new RecursiveDirectoryIterator($folder, RecursiveDirectoryIterator::SKIP_DOTS); $iterator = new RecursiveCallbackFilterIterator($iterator, function($item) use ($folder, $excludes){ diff --git a/lib/private/connector/sabre/blocklegacyclientplugin.php b/lib/private/connector/sabre/blocklegacyclientplugin.php new file mode 100644 index 00000000000..9480cd1f06d --- /dev/null +++ b/lib/private/connector/sabre/blocklegacyclientplugin.php @@ -0,0 +1,79 @@ +<?php +/** + * @author Lukas Reschke <lukas@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/> + * + */ + +namespace OC\Connector\Sabre; + +use OCP\IConfig; +use Sabre\HTTP\RequestInterface; +use Sabre\DAV\ServerPlugin; +use Sabre\DAV\Exception; + +/** + * Class BlockLegacyClientPlugin is used to detect old legacy sync clients and + * returns a 403 status to those clients + * + * @package OC\Connector\Sabre + */ +class BlockLegacyClientPlugin extends ServerPlugin { + /** @var \Sabre\DAV\Server */ + protected $server; + /** @var IConfig */ + protected $config; + + /** + * @param IConfig $config + */ + public function __construct(IConfig $config) { + $this->config = $config; + } + + /** + * @param \Sabre\DAV\Server $server + * @return void + */ + public function initialize(\Sabre\DAV\Server $server) { + $this->server = $server; + $this->server->on('beforeMethod', [$this, 'beforeHandler'], 200); + } + + /** + * Detects all unsupported clients and throws a \Sabre\DAV\Exception\Forbidden + * exception which will result in a 403 to them. + * @param RequestInterface $request + * @throws \Sabre\DAV\Exception\Forbidden If the client version is not supported + */ + public function beforeHandler(RequestInterface $request) { + $userAgent = $request->getHeader('User-Agent'); + if($userAgent === null) { + return; + } + + $minimumSupportedDesktopVersion = $this->config->getSystemValue('minimum.supported.desktop.version', '1.7.0'); + + // Match on the mirall version which is in scheme "Mozilla/5.0 (%1) mirall/%2" or + // "mirall/%1" for older releases + preg_match("/(?:mirall\\/)([\d.]+)/i", $userAgent, $versionMatches); + if(isset($versionMatches[1]) && + version_compare($versionMatches[1], $minimumSupportedDesktopVersion) === -1) { + throw new \Sabre\DAV\Exception\Forbidden('Unsupported client version.'); + } + } +} diff --git a/lib/private/encryption/file.php b/lib/private/encryption/file.php index 48cd0d1187b..5a7357b9e28 100644 --- a/lib/private/encryption/file.php +++ b/lib/private/encryption/file.php @@ -36,7 +36,7 @@ class File implements \OCP\Encryption\IFile { * get list of users with access to the file * * @param string $path to the file - * @return array + * @return array ['users' => $uniqueUserIds, 'public' => $public] */ public function getAccessList($path) { @@ -46,7 +46,7 @@ class File implements \OCP\Encryption\IFile { // always add owner to the list of users with access to the file $userIds = array($owner); - if (!$this->util->isFile($ownerPath)) { + if (!$this->util->isFile($owner . '/' . $ownerPath)) { return array('users' => $userIds, 'public' => false); } diff --git a/lib/private/encryption/keys/storage.php b/lib/private/encryption/keys/storage.php index e34d7370ef1..118c8dc920d 100644 --- a/lib/private/encryption/keys/storage.php +++ b/lib/private/encryption/keys/storage.php @@ -235,6 +235,7 @@ class Storage implements IStorage { * * @param string $source * @param string $target + * @return boolean */ public function renameKeys($source, $target) { @@ -253,7 +254,11 @@ class Storage implements IStorage { if ($this->view->file_exists($sourcePath)) { $this->keySetPreparation(dirname($targetPath)); $this->view->rename($sourcePath, $targetPath); + + return true; } + + return false; } /** @@ -261,6 +266,7 @@ class Storage implements IStorage { * * @param string $source * @param string $target + * @return boolean */ public function copyKeys($source, $target) { @@ -279,7 +285,10 @@ class Storage implements IStorage { if ($this->view->file_exists($sourcePath)) { $this->keySetPreparation(dirname($targetPath)); $this->view->copy($sourcePath, $targetPath); + return true; } + + return false; } /** diff --git a/lib/private/encryption/manager.php b/lib/private/encryption/manager.php index 97203b7756d..8e080507c81 100644 --- a/lib/private/encryption/manager.php +++ b/lib/private/encryption/manager.php @@ -22,6 +22,7 @@ namespace OC\Encryption; +use OC\Files\Filesystem; use OC\Files\Storage\Shared; use OC\Files\Storage\Wrapper\Encryption; use OC\Files\View; @@ -222,7 +223,24 @@ class Manager implements IManager { $uid = $user ? $user->getUID() : null; $fileHelper = \OC::$server->getEncryptionFilesHelper(); $keyStorage = \OC::$server->getEncryptionKeyStorage(); - return new Encryption($parameters, $manager, $util, $logger, $fileHelper, $uid, $keyStorage); + $update = new Update( + new View(), + $util, + Filesystem::getMountManager(), + $manager, + $fileHelper, + $uid + ); + return new Encryption( + $parameters, + $manager, + $util, + $logger, + $fileHelper, + $uid, + $keyStorage, + $update + ); } else { return $storage; } diff --git a/lib/private/encryption/update.php b/lib/private/encryption/update.php index 7a170a03adc..f262099a3c5 100644 --- a/lib/private/encryption/update.php +++ b/lib/private/encryption/update.php @@ -22,6 +22,7 @@ namespace OC\Encryption; +use OC\Files\Filesystem; use \OC\Files\Mount; use \OC\Files\View; @@ -74,46 +75,73 @@ class Update { $this->uid = $uid; } + /** + * hook after file was shared + * + * @param array $params + */ public function postShared($params) { if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') { - $this->update($params['fileSource']); + $path = Filesystem::getPath($params['fileSource']); + list($owner, $ownerPath) = $this->getOwnerPath($path); + $absPath = '/' . $owner . '/files/' . $ownerPath; + $this->update($absPath); } } + /** + * hook after file was unshared + * + * @param array $params + */ public function postUnshared($params) { if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') { - $this->update($params['fileSource']); + $path = Filesystem::getPath($params['fileSource']); + list($owner, $ownerPath) = $this->getOwnerPath($path); + $absPath = '/' . $owner . '/files/' . $ownerPath; + $this->update($absPath); } } /** - * update keyfiles and share keys recursively + * get owner and path relative to data/<owner>/files * - * @param int $fileSource file source id + * @param string $path path to file for current user + * @return array ['owner' => $owner, 'path' => $path] + * @throw \InvalidArgumentException */ - private function update($fileSource) { - $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; + private function getOwnerPath($path) { + $info = Filesystem::getFileInfo($path); + $owner = Filesystem::getOwner($path); + $view = new View('/' . $owner . '/files'); + $path = $view->getPath($info->getId()); + if ($path === null) { + throw new \InvalidArgumentException('No file found for ' . $info->getId()); + } + + return array($owner, $path); + } - $mount = $this->mountManager->find($path); - $mountPoint = $mount->getMountPoint(); + /** + * notify encryption module about added/removed users from a file/folder + * + * @param string $path relative to data/ + * @throws Exceptions\ModuleDoesNotExistsException + */ + public function update($path) { // if a folder was shared, get a list of all (sub-)folders - if ($this->view->is_dir($absPath)) { - $allFiles = $this->util->getAllFiles($absPath, $mountPoint); + if ($this->view->is_dir($path)) { + $allFiles = $this->util->getAllFiles($path); } else { - $allFiles = array($absPath); + $allFiles = array($path); } $encryptionModule = $this->encryptionManager->getDefaultEncryptionModule(); - foreach ($allFiles as $path) { - $usersSharing = $this->file->getAccessList($path); - $encryptionModule->update($path, $this->uid, $usersSharing); + foreach ($allFiles as $file) { + $usersSharing = $this->file->getAccessList($file); + $encryptionModule->update($file, $this->uid, $usersSharing); } } diff --git a/lib/private/encryption/util.php b/lib/private/encryption/util.php index 98a38012dba..032ac83f37e 100644 --- a/lib/private/encryption/util.php +++ b/lib/private/encryption/util.php @@ -25,6 +25,7 @@ namespace OC\Encryption; use OC\Encryption\Exceptions\EncryptionHeaderKeyExistsException; use OC\Encryption\Exceptions\EncryptionHeaderToLargeException; use OC\Encryption\Exceptions\ModuleDoesNotExistsException; +use OC\Files\Filesystem; use OC\Files\View; use OCP\Encryption\IEncryptionModule; use OCP\IConfig; @@ -181,10 +182,9 @@ class Util { * go recursively through a dir and collect all files and sub files. * * @param string $dir relative to the users files folder - * @param string $mountPoint * @return array with list of files relative to the users files folder */ - public function getAllFiles($dir, $mountPoint = '') { + public function getAllFiles($dir) { $result = array(); $dirList = array($dir); @@ -193,13 +193,10 @@ class Util { $content = $this->view->getDirectoryContent($dir); 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->getPath() : $c->getPath(); - if ($c['type'] === 'dir') { - $dirList[] = \OC\Files\Filesystem::normalizePath($path); + if ($c->getType() === 'dir') { + $dirList[] = $c->getPath(); } else { - $result[] = \OC\Files\Filesystem::normalizePath($path); + $result[] = $c->getPath(); } } @@ -212,11 +209,12 @@ class Util { * check if it is a file uploaded by the user stored in data/user/files * or a metadata file * - * @param string $path + * @param string $path relative to the data/ folder * @return boolean */ public function isFile($path) { - if (substr($path, 0, strlen('/files/')) === '/files/') { + $parts = explode('/', Filesystem::normalizePath($path), 4); + if (isset($parts[2]) && $parts[2] === 'files') { return true; } return false; @@ -262,7 +260,7 @@ class Util { $ownerPath = implode('/', array_slice($parts, 2)); - return array($uid, \OC\Files\Filesystem::normalizePath($ownerPath)); + return array($uid, Filesystem::normalizePath($ownerPath)); } diff --git a/lib/private/files/storage/wrapper/encryption.php b/lib/private/files/storage/wrapper/encryption.php index 0a9e6d61d2e..0dc59cbb2a0 100644 --- a/lib/private/files/storage/wrapper/encryption.php +++ b/lib/private/files/storage/wrapper/encryption.php @@ -23,10 +23,15 @@ namespace OC\Files\Storage\Wrapper; use OC\Encryption\Exceptions\ModuleDoesNotExistsException; -use OC\Encryption\File; +use OC\Encryption\Update; +use OC\Encryption\Util; use OC\Files\Filesystem; use OC\Files\Storage\LocalTempFileTrait; +use OCP\Encryption\IFile; +use OCP\Encryption\IManager; +use OCP\Encryption\Keys\IStorage; use OCP\Files\Mount\IMountPoint; +use OCP\ILogger; class Encryption extends Wrapper { @@ -38,10 +43,10 @@ class Encryption extends Wrapper { /** @var \OC\Encryption\Util */ private $util; - /** @var \OC\Encryption\Manager */ + /** @var \OCP\Encryption\IManager */ private $encryptionManager; - /** @var \OC\Log */ + /** @var \OCP\ILogger */ private $logger; /** @var string */ @@ -50,7 +55,7 @@ class Encryption extends Wrapper { /** @var array */ private $unencryptedSize; - /** @var File */ + /** @var \OCP\Encryption\IFile */ private $fileHelper; /** @var IMountPoint */ @@ -59,22 +64,28 @@ class Encryption extends Wrapper { /** @var \OCP\Encryption\Keys\IStorage */ private $keyStorage; + /** @var \OC\Encryption\Update */ + private $update; + /** * @param array $parameters - * @param \OC\Encryption\Manager $encryptionManager + * @param \OCP\Encryption\IManager $encryptionManager * @param \OC\Encryption\Util $util - * @param \OC\Log $logger - * @param File $fileHelper + * @param \OCP\ILogger $logger + * @param \OCP\Encryption\IFile $fileHelper * @param string $uid user who perform the read/write operation (null for public access) + * @param IStorage $keyStorage + * @param Update $update */ public function __construct( $parameters, - \OC\Encryption\Manager $encryptionManager = null, - \OC\Encryption\Util $util = null, - \OC\Log $logger = null, - File $fileHelper = null, + IManager $encryptionManager = null, + Util $util = null, + ILogger $logger = null, + IFile $fileHelper = null, $uid = null, - $keyStorage = null + IStorage $keyStorage = null, + Update $update = null ) { $this->mountPoint = $parameters['mountPoint']; @@ -86,6 +97,7 @@ class Encryption extends Wrapper { $this->fileHelper = $fileHelper; $this->keyStorage = $keyStorage; $this->unencryptedSize = array(); + $this->update = $update; parent::__construct($parameters); } @@ -207,19 +219,24 @@ class Encryption extends Wrapper { * @return bool */ public function rename($path1, $path2) { - $fullPath1 = $this->getFullPath($path1); - if ($this->util->isExcluded($fullPath1)) { + $source = $this->getFullPath($path1); + if ($this->util->isExcluded($source)) { return $this->storage->rename($path1, $path2); } - $source = $this->getFullPath($path1); $result = $this->storage->rename($path1, $path2); if ($result) { $target = $this->getFullPath($path2); if (isset($this->unencryptedSize[$source])) { $this->unencryptedSize[$target] = $this->unencryptedSize[$source]; } - $this->keyStorage->renameKeys($source, $target); + $keysRenamed = $this->keyStorage->renameKeys($source, $target); + if ($keysRenamed && + dirname($source) !== dirname($target) && + $this->util->isFile($target) + ) { + $this->update->update($target); + } } return $result; @@ -242,9 +259,12 @@ class Encryption extends Wrapper { $result = $this->storage->copy($path1, $path2); if ($result) { $target = $this->getFullPath($path2); - $encryptionModule = $this->getEncryptionModule($path2); - if ($encryptionModule) { - $this->keyStorage->copyKeys($source, $target); + $keysCopied = $this->keyStorage->copyKeys($source, $target); + if ($keysCopied && + dirname($source) !== dirname($target) && + $this->util->isFile($target) + ) { + $this->update->update($target); } } diff --git a/lib/private/files/stream/encryption.php b/lib/private/files/stream/encryption.php index 910357eef45..5f39207db87 100644 --- a/lib/private/files/stream/encryption.php +++ b/lib/private/files/stream/encryption.php @@ -1,7 +1,7 @@ <?php /** * @author Björn Schießle <schiessle@owncloud.com> - * @author jknockaert <jasper@knockaert.nl> + * @author Jasper Knockaert <jasper@knockaert.nl> * @author Thomas Müller <thomas.mueller@tmit.eu> * * @copyright Copyright (c) 2015, ownCloud, Inc. @@ -221,10 +221,9 @@ class Encryption extends Wrapper { || $mode === 'w+' || $mode === 'wb' || $mode === 'wb+' + || $mode === 'r+' + || $mode === 'rb+' ) { - // We're writing a new file so start write counter with 0 bytes - $this->unencryptedSize = 0; - $this->size = 0; $this->readOnly = false; } else { $this->readOnly = true; @@ -238,6 +237,20 @@ class Encryption extends Wrapper { $accessList = $this->file->getAccessList($sharePath); $this->newHeader = $this->encryptionModule->begin($this->fullPath, $this->uid, $this->header, $accessList); + if ( + $mode === 'w' + || $mode === 'w+' + || $mode === 'wb' + || $mode === 'wb+' + ) { + // We're writing a new file so start write counter with 0 bytes + $this->unencryptedSize = 0; + $this->writeHeader(); + $this->size = $this->util->getHeaderSize(); + } else { + $this->skipHeader(); + } + return true; } @@ -250,11 +263,6 @@ class Encryption extends Wrapper { $result = ''; - // skip the header if we read the file from the beginning - if ($this->position === 0) { - parent::stream_read($this->util->getHeaderSize()); - } - // $count = min($count, $this->unencryptedSize - $this->position); while ($count > 0) { $remainingLength = $count; @@ -281,11 +289,6 @@ class Encryption extends Wrapper { public function stream_write($data) { - if ($this->position === 0) { - $this->writeHeader(); - $this->size = $this->util->getHeaderSize(); - } - $length = 0; // loop over $data to fit it in 6126 sized unencrypted blocks while (strlen($data) > 0) { @@ -428,9 +431,16 @@ class Encryption extends Wrapper { * @return integer * @throws EncryptionHeaderKeyExistsException if header key is already in use */ - private function writeHeader() { + protected function writeHeader() { $header = $this->util->createHeader($this->newHeader, $this->encryptionModule); return parent::stream_write($header); } + /** + * read first block to skip the header + */ + protected function skipHeader() { + parent::stream_read($this->util->getHeaderSize()); + } + } diff --git a/lib/public/encryption/keys/istorage.php b/lib/public/encryption/keys/istorage.php index 696d5373310..752c073375d 100644 --- a/lib/public/encryption/keys/istorage.php +++ b/lib/public/encryption/keys/istorage.php @@ -153,6 +153,7 @@ interface IStorage { * * @param string $source * @param string $target + * @return boolean * @since 8.1.0 */ public function renameKeys($source, $target); @@ -162,6 +163,7 @@ interface IStorage { * * @param string $source * @param string $target + * @return boolean * @since 8.1.0 */ public function copyKeys($source, $target); |