diff options
Diffstat (limited to 'apps/files_encryption/lib')
-rw-r--r-- | apps/files_encryption/lib/crypt.php | 3 | ||||
-rw-r--r-- | apps/files_encryption/lib/helper.php | 135 | ||||
-rw-r--r-- | apps/files_encryption/lib/proxy.php | 4 | ||||
-rw-r--r-- | apps/files_encryption/lib/stream.php | 65 | ||||
-rw-r--r-- | apps/files_encryption/lib/util.php | 4 |
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 |