[Pkg-owncloud-commits] [owncloud] 35/215: update share keys if a file is moved to a shared folder

David Prévot taffit at moszumanska.debian.org
Tue May 5 01:01:18 UTC 2015


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch stable8
in repository owncloud.

commit 2990b0e07e418577d55368c21200ada86c381b51
Author: Bjoern Schiessle <schiessle at owncloud.com>
Date:   Thu Apr 23 16:48:11 2015 +0200

    update share keys if a file is moved to a shared folder
---
 lib/private/encryption/file.php                  |   4 +-
 lib/private/encryption/manager.php               |  20 +++-
 lib/private/encryption/update.php                |  66 ++++++++----
 lib/private/encryption/util.php                  |  20 ++--
 lib/private/files/storage/wrapper/encryption.php |  28 +++--
 tests/lib/encryption/updatetest.php              | 129 +++++++++++++++++++++++
 tests/lib/encryption/utiltest.php                |  21 ++++
 tests/lib/files/storage/wrapper/encryption.php   |  59 +++++++++--
 8 files changed, 301 insertions(+), 46 deletions(-)

diff --git a/lib/private/encryption/file.php b/lib/private/encryption/file.php
index 48cd0d1..5a7357b 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/manager.php b/lib/private/encryption/manager.php
index 97203b7..8e08050 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 7a170a0..f262099 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 98a3801..032ac83 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 0a9e6d6..089da94 100644
--- a/lib/private/files/storage/wrapper/encryption.php
+++ b/lib/private/files/storage/wrapper/encryption.php
@@ -24,8 +24,13 @@ namespace OC\Files\Storage\Wrapper;
 
 use OC\Encryption\Exceptions\ModuleDoesNotExistsException;
 use OC\Encryption\File;
+use OC\Encryption\Manager;
+use OC\Encryption\Update;
+use OC\Encryption\Util;
 use OC\Files\Filesystem;
 use OC\Files\Storage\LocalTempFileTrait;
+use OC\Log;
+use OCP\Encryption\Keys\IStorage;
 use OCP\Files\Mount\IMountPoint;
 
 class Encryption extends Wrapper {
@@ -59,6 +64,9 @@ 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
@@ -66,15 +74,18 @@ class Encryption extends Wrapper {
 	 * @param \OC\Log $logger
 	 * @param File $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,
+			Manager $encryptionManager = null,
+			Util $util = null,
+			Log $logger = null,
 			File $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,12 +219,11 @@ 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);
@@ -220,6 +231,9 @@ class Encryption extends Wrapper {
 				$this->unencryptedSize[$target] = $this->unencryptedSize[$source];
 			}
 			$this->keyStorage->renameKeys($source, $target);
+			if (dirname($source) !== dirname($target) && $this->util->isFile($target)) {
+				$this->update->update($target);
+			}
 		}
 
 		return $result;
diff --git a/tests/lib/encryption/updatetest.php b/tests/lib/encryption/updatetest.php
new file mode 100644
index 0000000..28bb003
--- /dev/null
+++ b/tests/lib/encryption/updatetest.php
@@ -0,0 +1,129 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle at 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 Test\Encryption;
+
+
+use OC\Encryption\Update;
+use Test\TestCase;
+
+class UpdateTest extends TestCase {
+
+	/** @var \OC\Encryption\Update */
+	private $update;
+
+	/** @var string */
+	private $uid;
+
+	/** @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject */
+	private $view;
+
+	/** @var \OC\Encryption\Util | \PHPUnit_Framework_MockObject_MockObject */
+	private $util;
+
+	/** @var \OC\Files\Mount\Manager | \PHPUnit_Framework_MockObject_MockObject */
+	private $mountManager;
+
+	/** @var \OC\Encryption\Manager | \PHPUnit_Framework_MockObject_MockObject */
+	private $encryptionManager;
+
+	/** @var \OCP\Encryption\IEncryptionModule | \PHPUnit_Framework_MockObject_MockObject */
+	private $encryptionModule;
+
+	/** @var \OC\Encryption\File | \PHPUnit_Framework_MockObject_MockObject */
+	private $fileHelper;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->view = $this->getMockBuilder('\OC\Files\View')
+			->disableOriginalConstructor()->getMock();
+		$this->util = $this->getMockBuilder('\OC\Encryption\Util')
+			->disableOriginalConstructor()->getMock();
+		$this->mountManager = $this->getMockBuilder('\OC\Files\Mount\Manager')
+			->disableOriginalConstructor()->getMock();
+		$this->encryptionManager = $this->getMockBuilder('\OC\Encryption\Manager')
+			->disableOriginalConstructor()->getMock();
+		$this->fileHelper = $this->getMockBuilder('\OC\Encryption\File')
+			->disableOriginalConstructor()->getMock();
+		$this->encryptionModule = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule')
+			->disableOriginalConstructor()->getMock();
+
+		$this->encryptionManager->expects($this->once())
+			->method('getDefaultEncryptionModule')
+			->willReturn($this->encryptionModule);
+
+		$this->uid = 'testUser1';
+
+		$this->update = new Update(
+			$this->view,
+			$this->util,
+			$this->mountManager,
+			$this->encryptionManager,
+			$this->fileHelper,
+			$this->uid);
+	}
+
+	/**
+	 * @dataProvider dataTestUpdate
+	 *
+	 * @param string $path
+	 * @param boolean $isDir
+	 * @param array $allFiles
+	 * @param integer $numberOfFiles
+	 */
+	public function testUpdate($path, $isDir, $allFiles, $numberOfFiles) {
+
+		$this->view->expects($this->once())
+			->method('is_dir')
+			->willReturn($isDir);
+
+		if($isDir) {
+			$this->util->expects($this->once())
+				->method('getAllFiles')
+				->willReturn($allFiles);
+		}
+
+		$this->fileHelper->expects($this->exactly($numberOfFiles))
+			->method('getAccessList')
+			->willReturn(['users' => [], 'public' => false]);
+
+		$this->encryptionModule->expects($this->exactly($numberOfFiles))
+			->method('update')
+			->willReturn(true);
+
+		$this->update->update($path);
+	}
+
+	/**
+	 * data provider for testUpdate()
+	 *
+	 * @return array
+	 */
+	public function dataTestUpdate() {
+		return array(
+			array('/user/files/foo', true, ['/user/files/foo/file1.txt', '/user/files/foo/file1.txt'], 2),
+			array('/user/files/test.txt', false, [], 1),
+		);
+	}
+
+}
diff --git a/tests/lib/encryption/utiltest.php b/tests/lib/encryption/utiltest.php
index dc6205e..7de5704 100644
--- a/tests/lib/encryption/utiltest.php
+++ b/tests/lib/encryption/utiltest.php
@@ -152,4 +152,25 @@ class UtilTest extends TestCase {
 		return false;
 	}
 
+	/**
+	 * @dataProvider dataTestIsFile
+	 */
+	public function testIsFile($path, $expected) {
+		$this->assertSame($expected,
+			$this->util->isFile($path)
+		);
+	}
+
+	public function dataTestIsFile() {
+		return array(
+			array('/user/files/test.txt', true),
+			array('/user/files', true),
+			array('/user/files_versions/test.txt', false),
+			array('/user/foo/files/test.txt', false),
+			array('/files/foo/files/test.txt', false),
+			array('/user', false),
+			array('/user/test.txt', false),
+		);
+	}
+
 }
diff --git a/tests/lib/files/storage/wrapper/encryption.php b/tests/lib/files/storage/wrapper/encryption.php
index 1d77655..12309c5 100644
--- a/tests/lib/files/storage/wrapper/encryption.php
+++ b/tests/lib/files/storage/wrapper/encryption.php
@@ -13,10 +13,25 @@ class Encryption extends \Test\Files\Storage\Storage {
 	private $sourceStorage;
 
 	/**
+	 * @var \OC\Files\Storage\Wrapper\Encryption
+	 */
+	protected $instance;
+
+	/**
 	 * @var \OC\Encryption\Keys\Storage | \PHPUnit_Framework_MockObject_MockObject
 	 */
 	private $keyStore;
 
+	/**
+	 * @var \OC\Encryption\Util | \PHPUnit_Framework_MockObject_MockObject
+	 */
+	private $util;
+
+	/**
+	 * @var \OC\Encryption\Update | \PHPUnit_Framework_MockObject_MockObject
+	 */
+	private $update;
+
 	public function setUp() {
 
 		parent::setUp();
@@ -43,8 +58,8 @@ class Encryption extends \Test\Files\Storage\Storage {
 			->disableOriginalConstructor()
 			->getMock();
 
-		$util = $this->getMock('\OC\Encryption\Util', ['getUidAndFilename'], [new View(), new \OC\User\Manager(), $groupManager, $config]);
-		$util->expects($this->any())
+		$this->util = $this->getMock('\OC\Encryption\Util', ['getUidAndFilename', 'isFile'], [new View(), new \OC\User\Manager(), $groupManager, $config]);
+		$this->util->expects($this->any())
 			->method('getUidAndFilename')
 			->willReturnCallback(function ($path) {
 				return ['user1', $path];
@@ -61,6 +76,8 @@ class Encryption extends \Test\Files\Storage\Storage {
 		$this->sourceStorage = new Temporary(array());
 		$this->keyStore = $this->getMockBuilder('\OC\Encryption\Keys\Storage')
 			->disableOriginalConstructor()->getMock();
+		$this->update = $this->getMockBuilder('\OC\Encryption\Update')
+			->disableOriginalConstructor()->getMock();
 		$mount = $this->getMockBuilder('\OC\Files\Mount\MountPoint')
 			->disableOriginalConstructor()
 			->setMethods(['getOption'])
@@ -72,7 +89,7 @@ class Encryption extends \Test\Files\Storage\Storage {
 			'mountPoint' => '/',
 			'mount' => $mount
 		],
-			$encryptionManager, $util, $logger, $file, null, $this->keyStore
+			$encryptionManager, $this->util, $logger, $file, null, $this->keyStore, $this->update
 		);
 	}
 
@@ -97,11 +114,41 @@ class Encryption extends \Test\Files\Storage\Storage {
 		return $encryptionModule;
 	}
 
-	public function testRename() {
+	/**
+	 * @dataProvider dataTestRename
+	 *
+	 * @param string $source
+	 * @param string $target
+	 * @param boolean $shouldUpdate
+	 */
+	public function testRename($source, $target, $shouldUpdate) {
 		$this->keyStore
 			->expects($this->once())
 			->method('renameKeys');
-		$this->instance->mkdir('folder');
-		$this->instance->rename('folder', 'flodder');
+		$this->util->expects($this->any())
+			->method('isFile')->willReturn(true);
+		if ($shouldUpdate) {
+			$this->update->expects($this->once())
+				->method('update');
+		} else {
+			$this->update->expects($this->never())
+				->method('update');
+		}
+
+		$this->instance->mkdir($source);
+		$this->instance->mkdir(dirname($target));
+		$this->instance->rename($source, $target);
+	}
+
+	/**
+	 * data provider for testRename()
+	 *
+	 * @return array
+	 */
+	public function dataTestRename() {
+		return array(
+			array('source', 'target', false),
+			array('source', '/subFolder/target', true),
+		);
 	}
 }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-owncloud/owncloud.git



More information about the Pkg-owncloud-commits mailing list