Skip to content

Commit

Permalink
fix keystorage and add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Bjoern Schiessle committed Mar 17, 2015
1 parent b07da6c commit 429cab1
Show file tree
Hide file tree
Showing 6 changed files with 374 additions and 66 deletions.
52 changes: 52 additions & 0 deletions lib/private/encryption/keys/factory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

/**
* ownCloud
*
* @copyright (C) 2015 ownCloud, Inc.
*
* @author Bjoern Schiessle <[email protected]>
*
* 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\Keys;

use OC\Encryption\Util;
use OC\Files\View;
use OC\User;

/**
* Factory provides KeyStorage for different encryption modules
*/
class Factory {
/** @var array */
protected $instances = array();

/**
* get a KeyStorage instance
*
* @param string $encryptionModuleId
* @param View $view
* @param Util $util
* @return Storage
*/
public function get($encryptionModuleId,View $view, Util $util) {
if (!isset($this->instances[$encryptionModuleId])) {
$this->instances[$encryptionModuleId] = new Storage($encryptionModuleId, $view, $util);
}
return $this->instances[$encryptionModuleId];
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/

namespace OC\Encryption;
namespace OC\Encryption\Keys;

use OC\Encryption\Util;
use OC\Files\View;
use OCA\Files_Encryption\Exception\EncryptionException;

class KeyStorage implements \OCP\Encryption\IKeyStorage {
class Storage implements \OCP\Encryption\Keys\IStorage {

/** @var View */
private $view;
Expand All @@ -36,18 +36,26 @@ class KeyStorage implements \OCP\Encryption\IKeyStorage {
private $util;

// base dir where all the file related keys are stored
private static $keys_base_dir = '/files_encryption/keys/';
private static $encryption_base_dir = '/files_encryption';
private $keys_base_dir;
private $encryption_base_dir;

private $keyCache = array();

/** @var string */
private $encryptionModuleId;

/**
* @param string $encryptionModuleId
* @param View $view
* @param Util $util
*/
public function __construct(View $view, Util $util) {
public function __construct($encryptionModuleId, View $view, Util $util) {
$this->view = $view;
$this->util = $util;
$this->encryptionModuleId = $encryptionModuleId;

$this->encryption_base_dir = '/files_encryption';
$this->keys_base_dir = $this->encryption_base_dir .'/keys';
}

/**
Expand All @@ -59,7 +67,8 @@ public function __construct(View $view, Util $util) {
* @return mixed key
*/
public function getUserKey($uid, $keyId) {
$path = '/' . $uid . self::$encryption_base_dir . '/' . $uid . '.' . $keyId;
$path = '/' . $uid . $this->encryption_base_dir . '/'
. $this->encryptionModuleId . '/' . $uid . '.' . $keyId;
return $this->getKey($path);
}

Expand All @@ -85,7 +94,7 @@ public function getFileKey($path, $keyId) {
* @return mixed key
*/
public function getSystemUserKey($keyId) {
$path = '/' . self::$encryption_base_dir . '/' . $keyId;
$path = $this->encryption_base_dir . '/' . $this->encryptionModuleId . '/' . $keyId;
return $this->getKey($path);
}

Expand All @@ -97,7 +106,8 @@ public function getSystemUserKey($keyId) {
* @param mixed $key
*/
public function setUserKey($uid, $keyId, $key) {
$path = '/' . $uid . self::$encryption_base_dir . '/' . $uid . '.' . $keyId;
$path = '/' . $uid . $this->encryption_base_dir . '/'
. $this->encryptionModuleId . '/' . $uid . '.' . $keyId;
return $this->setKey($path, $key);
}

Expand All @@ -123,7 +133,8 @@ public function setFileKey($path, $keyId, $key) {
* @return mixed key
*/
public function setSystemUserKey($keyId, $key) {
$path = '/' . self::$encryption_base_dir . '/' . $keyId;
$path = $this->encryption_base_dir . '/'
. $this->encryptionModuleId . '/' . $keyId;
return $this->setKey($path, $key);
}

Expand All @@ -138,18 +149,13 @@ private function getKey($path) {

$key = '';

if (isset($this->keyCache[$path])) {
$key = $this->keyCache[$path];
} else {

/** @var \OCP\Files\Storage $storage */
list($storage, $internalPath) = $this->view->resolvePath($path);

if ($storage->file_exists($internalPath)) {
$key = $storage->file_get_contents($internalPath);
if ($this->view->file_exists($path)) {
if (isset($this->keyCache[$path])) {
$key = $this->keyCache[$path];
} else {
$key = $this->view->file_get_contents($path);
$this->keyCache[$path] = $key;
}

}

return $key;
Expand All @@ -166,9 +172,7 @@ private function getKey($path) {
private function setKey($path, $key) {
$this->keySetPreparation(dirname($path));

/** @var \OCP\Files\Storage $storage */
list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($path);
$result = $storage->file_put_contents($internalPath, $key);
$result = $this->view->file_put_contents($path, $key);

if (is_int($result) && $result > 0) {
$this->keyCache[$path] = $key;
Expand All @@ -181,32 +185,28 @@ private function setKey($path, $key) {
/**
* get path to key folder for a given file
*
* @param string $path path to the file, relative to the users file directory
* @param string $path path to the file, relative to data/
* @return string
* @throws EncryptionException
* @internal param string $keyId
*/
private function getFileKeyDir($path) {

//
// TODO: NO DEPRICATED API !!!
//
if ($this->view->is_dir('/' . \OCP\User::getUser() . '/' . $path)) {
if ($this->view->is_dir($path)) {
throw new EncryptionException('file was expected but directory was given', EncryptionException::GENERIC);
}

list($owner, $filename) = $this->util->getUidAndFilename($path);
$filename = $this->util->stripPartialFileExtension($filename);
$filePath_f = ltrim($filename, '/');

// in case of system wide mount points the keys are stored directly in the data directory
if ($this->util->isSystemWideMountPoint($filename)) {
$keyPath = self::$keys_base_dir . $filePath_f . '/';
$keyPath = $this->keys_base_dir . $filename . '/';
} else {
$keyPath = '/' . $owner . self::$keys_base_dir . $filePath_f . '/';
$keyPath = '/' . $owner . $this->keys_base_dir . $filename . '/';
}

return $keyPath;
return \OC\Files\Filesystem::normalizePath($keyPath . $this->encryptionModuleId . '/', false);

This comment has been minimized.

Copy link
@DeepDiver1975

DeepDiver1975 Mar 18, 2015

Member

isn't there a normalizePath on the view as well?

}

/**
Expand All @@ -228,23 +228,4 @@ protected function keySetPreparation($path) {
}
}

/**
* Check if encryption system is ready to begin encrypting
* all the things
*
* @return bool
*/
public function ready() {
$paths = [
self::$encryption_base_dir,
self::$keys_base_dir
];
foreach ($paths as $path) {
if (!$this->view->file_exists($path)) {
return false;
}
}
return true;
}

}
74 changes: 70 additions & 4 deletions lib/private/encryption/util.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,25 @@ class Util {
*/
protected $blockSize = 8192;

/** $var array */
/** @var \OC\Files\View */
protected $view;

/** @var array */
protected $ocHeaderKeys;

public function __construct() {
/** @var \OC\User\Manager */
protected $userManager;

/**
* @param \OC\Files\View $view root view
*/
public function __construct(\OC\Files\View $view, \OC\User\Manager $userManager) {
$this->ocHeaderKeys = [
self::HEADER_ENCRYPTION_MODULE => self::HEADER_ENCRYPTION_MODULE_KEY
];

$this->view = $view;
$this->userManager = $userManager;
}

/**
Expand Down Expand Up @@ -186,8 +198,62 @@ public function getBlockSize() {
return $this->blockSize;
}

public function getUidAndFilename($filename) {
// TODO find a better implementation than in the current encyption app
public function getUidAndFilename($path) {

$parts = explode('/', $path);
if (count($parts) > 2) {
$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;
}

$pathToCheck = substr($pathToCheck, strlen('/' . $uid));

$this->view->chroot('/' . $uid);
$owner = $this->view->getOwner($pathToCheck);

// Check that UID is valid
if (!\OCP\User::userExists($owner)) {

This comment has been minimized.

Copy link
@DeepDiver1975

DeepDiver1975 Mar 18, 2015

Member

static call

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);

This comment has been minimized.

Copy link
@DeepDiver1975

DeepDiver1975 Mar 18, 2015

Member

@icewind1991 we need a non static approach to this - please advise - THX

This comment has been minimized.

Copy link
@icewind1991

icewind1991 Mar 18, 2015

Contributor

One day.... #11091


$info = $this->view->getFileInfo($pathToCheck);
$this->view->chroot('/' . $owner);
$ownerPath = $this->view->getPath($info->getId());
$this->view->chroot('/');

if ($parentFolder) {
$ownerPath = $ownerPath . '/'. $pathinfo['filename'];
}

if ($partfile) {
$ownerPath = $ownerPath . '.' . $pathinfo['extension'];
}

return array(
$owner,
\OC\Files\Filesystem::normalizePath($ownerPath)
);
}

/**
Expand Down
12 changes: 8 additions & 4 deletions lib/private/server.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ function __construct($webRoot) {
return new Encryption\Manager($c->getConfig());
});

$this->registerService('EncryptionKeyStorage', function ($c) {
return new Encryption\KeyStorage(new \OC\Files\View(), new \OC\Encryption\Util());
$this->registerService('EncryptionKeyStorageFactory', function ($c) {
return new Encryption\Keys\Factory();
});

$this->registerService('PreviewManager', function ($c) {
Expand Down Expand Up @@ -338,10 +338,14 @@ function getEncryptionManager() {
}

/**
* @param string $encryptionModuleId encryption module ID
*
* @return \OCP\Encryption\IKeyStorage
*/
function getEncryptionKeyStorage() {
return $this->query('EncryptionKeyStorage');
function getEncryptionKeyStorage($encryptionModuleId) {
$view = new \OC\Files\View();
$util = new \OC\Encryption\Util($view, new \OC\User\Manager());
return $this->query('EncryptionKeyStorageFactory')->get($encryptionModuleId, $view, $util);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/

namespace OCP\Encryption;
namespace OCP\Encryption\Keys;

interface IKeyStorage {
interface IStorage {

/**
* get user specific key
Expand Down Expand Up @@ -84,10 +84,4 @@ public function setFileKey($path, $keyId, $key);
*/
public function setSystemUserKey($keyId, $key);

/**
* Return if encryption is setup and ready encrypt things
*
* @return bool
*/
public function ready();
}
Loading

0 comments on commit 429cab1

Please sign in to comment.