summaryrefslogtreecommitdiffstats
path: root/apps/files_encryption/lib
diff options
context:
space:
mode:
authorBjoern Schiessle <schiessle@owncloud.com>2015-01-08 20:57:49 +0100
committerBjoern Schiessle <schiessle@owncloud.com>2015-01-09 12:46:24 +0100
commitd699d3151810784d01b59019fdf40f0924556ddc (patch)
tree20b6b81817cbe19f3689c51730c935ce5495f868 /apps/files_encryption/lib
parent5311d92c5c9dc0de297e36e4009b1e99f386e6bd (diff)
downloadnextcloud-server-d699d3151810784d01b59019fdf40f0924556ddc.tar.gz
nextcloud-server-d699d3151810784d01b59019fdf40f0924556ddc.zip
make versions of shared files downloadable
Diffstat (limited to 'apps/files_encryption/lib')
-rw-r--r--apps/files_encryption/lib/crypt.php3
-rw-r--r--apps/files_encryption/lib/helper.php135
-rw-r--r--apps/files_encryption/lib/proxy.php4
-rw-r--r--apps/files_encryption/lib/stream.php65
-rw-r--r--apps/files_encryption/lib/util.php4
5 files changed, 131 insertions, 80 deletions
diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php
index 38993ba65b0..cdc2df4cdd8 100644
--- a/apps/files_encryption/lib/crypt.php
+++ b/apps/files_encryption/lib/crypt.php
@@ -148,9 +148,6 @@ class Crypt {
// Fetch encryption metadata from end of file
$meta = substr($noPadding, -22);
- // Fetch IV from end of file
- $iv = substr($meta, -16);
-
// Fetch identifier from start of metadata
$identifier = substr($meta, 0, 6);
diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php
index b9d45f67363..553c52e72fe 100644
--- a/apps/files_encryption/lib/helper.php
+++ b/apps/files_encryption/lib/helper.php
@@ -250,15 +250,14 @@ class Helper {
* @return string e.g. turns '/admin/files/test.txt' into 'test.txt'
*/
public static function stripUserFilesPath($path) {
- $trimmed = ltrim($path, '/');
- $split = explode('/', $trimmed);
+ $split = self::splitPath($path);
// it is not a file relative to data/user/files
- if (count($split) < 3 || $split[1] !== 'files') {
+ if (count($split) < 4 || $split[2] !== 'files') {
return false;
}
- $sliced = array_slice($split, 2);
+ $sliced = array_slice($split, 3);
$relPath = implode('/', $sliced);
return $relPath;
@@ -267,7 +266,7 @@ class Helper {
/**
* try to get the user from the path if no user is logged in
* @param string $path
- * @return mixed user or false if we couldn't determine a user
+ * @return string user
*/
public static function getUser($path) {
@@ -281,65 +280,85 @@ class Helper {
// if no user is logged in we try to access a publicly shared files.
// In this case we need to try to get the user from the path
+ return self::getUserFromPath($path);
+ }
- $trimmed = ltrim($path, '/');
- $split = explode('/', $trimmed);
+ /**
+ * extract user from path
+ *
+ * @param string $path
+ * @return string user id
+ * @throws Exception\EncryptionException
+ */
+ public static function getUserFromPath($path) {
+ $split = self::splitPath($path);
- // it is not a file relative to data/user/files
- if (count($split) < 2 || ($split[1] !== 'files' && $split[1] !== 'cache')) {
- return false;
- }
+ if (count($split) > 3 && (
+ $split[2] === 'files' || $split[2] === 'files_versions' || $split[2] === 'cache')) {
- $user = $split[0];
+ $user = $split[1];
- if (\OCP\User::userExists($user)) {
- return $user;
+ if (\OCP\User::userExists($user)) {
+ return $user;
+ }
}
- return false;
+ throw new Exception\EncryptionException('Could not determine user', Exception\EncryptionException::GENERIC);
}
/**
* get path to the corresponding file in data/user/files if path points
- * to a version or to a file in cache
- * @param string $path path to a version or a file in the trash
+ * to a file in cache
+ *
+ * @param string $path path to a file in cache
* @return string path to corresponding file relative to data/user/files
+ * @throws Exception\EncryptionException
*/
- public static function getPathToRealFile($path) {
- $trimmed = ltrim($path, '/');
- $split = explode('/', $trimmed);
- $result = false;
-
- if (count($split) >= 3 && ($split[1] === "files_versions" || $split[1] === 'cache')) {
- $sliced = array_slice($split, 2);
- $result = implode('/', $sliced);
- if ($split[1] === "files_versions") {
- // we skip user/files
- $sliced = array_slice($split, 2);
- $relPath = implode('/', $sliced);
- //remove the last .v
- $result = substr($relPath, 0, strrpos($relPath, '.v'));
- }
- if ($split[1] === "cache") {
- // we skip /user/cache/transactionId
- $sliced = array_slice($split, 3);
- $result = implode('/', $sliced);
- //prepare the folders
- self::mkdirr($path, new \OC\Files\View('/'));
- }
+ public static function getPathFromCachedFile($path) {
+ $split = self::splitPath($path);
+
+ if (count($split) < 5) {
+ throw new Exception\EncryptionException('no valid cache file path', Exception\EncryptionException::GENERIC);
}
- return $result;
+ // we skip /user/cache/transactionId
+ $sliced = array_slice($split, 4);
+
+ return implode('/', $sliced);
+ }
+
+
+ /**
+ * get path to the corresponding file in data/user/files for a version
+ *
+ * @param string $path path to a version
+ * @return string path to corresponding file relative to data/user/files
+ * @throws Exception\EncryptionException
+ */
+ public static function getPathFromVersion($path) {
+ $split = self::splitPath($path);
+
+ if (count($split) < 4) {
+ throw new Exception\EncryptionException('no valid path to a version', Exception\EncryptionException::GENERIC);
+ }
+
+ // we skip user/files_versions
+ $sliced = array_slice($split, 3);
+ $relPath = implode('/', $sliced);
+ //remove the last .v
+ $realPath = substr($relPath, 0, strrpos($relPath, '.v'));
+
+ return $realPath;
}
/**
* create directory recursively
+ *
* @param string $path
* @param \OC\Files\View $view
*/
public static function mkdirr($path, \OC\Files\View $view) {
- $dirname = \OC\Files\Filesystem::normalizePath(dirname($path));
- $dirParts = explode('/', $dirname);
+ $dirParts = self::splitPath(dirname($path));
$dir = "";
foreach ($dirParts as $part) {
$dir = $dir . '/' . $part;
@@ -454,6 +473,32 @@ class Helper {
}
/**
+ * detect file type, encryption can read/write regular files, versions
+ * and cached files
+ *
+ * @param string $path
+ * @return int
+ * @throws Exception\EncryptionException
+ */
+ public static function detectFileType($path) {
+ $parts = self::splitPath($path);
+
+ if (count($parts) > 2) {
+ switch ($parts[2]) {
+ case 'files':
+ return Util::FILE_TYPE_FILE;
+ case 'files_versions':
+ return Util::FILE_TYPE_VERSION;
+ case 'cache':
+ return Util::FILE_TYPE_CACHE;
+ }
+ }
+
+ // thow exception if we couldn't detect a valid file type
+ throw new Exception\EncryptionException('Could not detect file type', Exception\EncryptionException::GENERIC);
+ }
+
+ /**
* read the cipher used for encryption from the config.php
*
* @return string
@@ -472,5 +517,11 @@ class Helper {
return $cipher;
}
+
+ public static function splitPath($path) {
+ $normalized = \OC\Files\Filesystem::normalizePath($path);
+ return explode('/', $normalized);
+ }
+
}
diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php
index ba78c81aa35..3ee7d83f04c 100644
--- a/apps/files_encryption/lib/proxy.php
+++ b/apps/files_encryption/lib/proxy.php
@@ -56,10 +56,12 @@ class Proxy extends \OC_FileProxy {
$path = \OC\Files\Filesystem::normalizePath($path);
+ $parts = explode('/', $path);
+
// we only encrypt/decrypt files in the files and files_versions folder
if(
strpos($path, '/' . $uid . '/files/') !== 0 &&
- strpos($path, '/' . $uid . '/files_versions/') !== 0) {
+ !($parts[2] === 'files_versions' && \OCP\User::userExists($parts[1]))) {
return true;
}
diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php
index 17da4eb1cdc..1bc0d54e1bc 100644
--- a/apps/files_encryption/lib/stream.php
+++ b/apps/files_encryption/lib/stream.php
@@ -75,6 +75,8 @@ class Stream {
private $headerWritten = false;
private $containHeader = false; // the file contain a header
private $cipher; // cipher used for encryption/decryption
+ /** @var \OCA\Files_Encryption\Util */
+ private $util;
/**
* @var \OC\Files\View
@@ -103,9 +105,7 @@ class Stream {
// assume that the file already exist before we decide it finally in getKey()
$this->newFile = false;
- if (!isset($this->rootView)) {
- $this->rootView = new \OC\Files\View('/');
- }
+ $this->rootView = new \OC\Files\View('/');
$this->session = new Session($this->rootView);
@@ -116,7 +116,8 @@ class Stream {
}
$normalizedPath = \OC\Files\Filesystem::normalizePath(str_replace('crypt://', '', $path));
- if ($originalFile = Helper::getPathFromTmpFile($normalizedPath)) {
+ $originalFile = Helper::getPathFromTmpFile($normalizedPath);
+ if ($originalFile) {
$this->rawPath = $originalFile;
$this->isLocalTmpFile = true;
$this->localTmpFile = $normalizedPath;
@@ -124,24 +125,31 @@ class Stream {
$this->rawPath = $normalizedPath;
}
- $this->userId = Helper::getUser($this->rawPath);
-
- $util = new Util($this->rootView, $this->userId);
+ $this->util = new Util($this->rootView, Helper::getUser($this->rawPath));
// get the key ID which we want to use, can be the users key or the
// public share key
- $this->keyId = $util->getKeyId();
+ $this->keyId = $this->util->getKeyId();
- // Strip identifier text from path, this gives us the path relative to data/<user>/files
- $this->relPath = Helper::stripUserFilesPath($this->rawPath);
- // if raw path doesn't point to a real file, check if it is a version or a file in the trash bin
- if ($this->relPath === false) {
- $this->relPath = Helper::getPathToRealFile($this->rawPath);
- }
+ $fileType = Helper::detectFileType($this->rawPath);
- if($this->relPath === false) {
- \OCP\Util::writeLog('Encryption library', 'failed to open file "' . $this->rawPath . '" expecting a path to "files", "files_versions" or "cache"', \OCP\Util::ERROR);
- return false;
+ switch ($fileType) {
+ case Util::FILE_TYPE_FILE:
+ $this->relPath = Helper::stripUserFilesPath($this->rawPath);
+ $this->userId = \OC::$server->getUserSession()->getUser()->getUID();
+ break;
+ case Util::FILE_TYPE_VERSION:
+ $this->relPath = Helper::getPathFromVersion($this->rawPath);
+ $this->userId = Helper::getUserFromPath($this->rawPath);
+ break;
+ case Util::FILE_TYPE_CACHE:
+ $this->relPath = Helper::getPathFromCachedFile($this->rawPath);
+ Helper::mkdirr($this->rawPath, new \OC\Files\View('/'));
+ $this->userId = \OC::$server->getUserSession()->getUser()->getUID();
+ break;
+ default:
+ \OCP\Util::writeLog('Encryption library', 'failed to open file "' . $this->rawPath . '" expecting a path to "files", "files_versions" or "cache"', \OCP\Util::ERROR);
+ return false;
}
// Disable fileproxies so we can get the file size and open the source file without recursive encryption
@@ -154,22 +162,12 @@ class Stream {
or $mode === 'wb'
or $mode === 'wb+'
) {
-
// We're writing a new file so start write counter with 0 bytes
$this->size = 0;
$this->unencryptedSize = 0;
-
} else {
-
- if($this->privateKey === false) {
- // if private key is not valid redirect user to a error page
- Helper::redirectToErrorPage($this->session);
- }
-
$this->size = $this->rootView->filesize($this->rawPath);
-
$this->readHeader();
-
}
if ($this->isLocalTmpFile) {
@@ -328,9 +326,10 @@ class Stream {
}
+ $util = new Util($this->rootView, $this->userId);
+
// Fetch and decrypt keyfile
// Fetch existing keyfile
- $util = new Util($this->rootView, $this->userId);
$this->encKeyfile = Keymanager::getFileKey($this->rootView, $util, $this->relPath);
// If a keyfile already exists
@@ -614,11 +613,9 @@ class Stream {
// Check if OC sharing api is enabled
$sharingEnabled = \OCP\Share::isEnabled();
- $util = new Util($this->rootView, $this->userId);
-
// Get all users sharing the file includes current user
- $uniqueUserIds = $util->getSharingUsersArray($sharingEnabled, $this->relPath);
- $checkedUserIds = $util->filterShareReadyUsers($uniqueUserIds);
+ $uniqueUserIds = $this->util->getSharingUsersArray($sharingEnabled, $this->relPath);
+ $checkedUserIds = $this->util->filterShareReadyUsers($uniqueUserIds);
// Fetch public keys for all sharing users
$publicKeys = Keymanager::getPublicKeys($this->rootView, $checkedUserIds['ready']);
@@ -627,10 +624,10 @@ class Stream {
$this->encKeyfiles = Crypt::multiKeyEncrypt($this->plainKey, $publicKeys);
// Save the new encrypted file key
- Keymanager::setFileKey($this->rootView, $util, $this->relPath, $this->encKeyfiles['data']);
+ Keymanager::setFileKey($this->rootView, $this->util, $this->relPath, $this->encKeyfiles['data']);
// Save the sharekeys
- Keymanager::setShareKeys($this->rootView, $util, $this->relPath, $this->encKeyfiles['keys']);
+ Keymanager::setShareKeys($this->rootView, $this->util, $this->relPath, $this->encKeyfiles['keys']);
// Re-enable proxy - our work is done
\OC_FileProxy::$enabled = $proxyStatus;
diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php
index 4aaf7aa2571..1b140822724 100644
--- a/apps/files_encryption/lib/util.php
+++ b/apps/files_encryption/lib/util.php
@@ -39,6 +39,10 @@ class Util {
const MIGRATION_IN_PROGRESS = -1; // migration is running
const MIGRATION_OPEN = 0; // user still needs to be migrated
+ const FILE_TYPE_FILE = 0;
+ const FILE_TYPE_VERSION = 1;
+ const FILE_TYPE_CACHE = 2;
+
private $view; // OC\Files\View object for filesystem operations
private $userId; // ID of the user we use to encrypt/decrypt files
private $keyId; // ID of the key we want to manipulate