From 1aba986d9f219a872c83b5f8b46f641e2699a222 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Sat, 9 Feb 2013 12:42:18 +0000 Subject: Fixed bug causing nested file read over webdav to fail --- apps/files_encryption/lib/proxy.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 55cddf2bec8..7ae36e34ce1 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -281,7 +281,7 @@ class Proxy extends \OC_FileProxy { // Reformat path for use with OC_FSV $path_split = explode( '/', $path ); - $path_f = implode( array_slice( $path_split, 3 ) ); + $path_f = implode( '/', array_slice( $path_split, 3 ) ); // Disable encryption proxy to prevent recursive calls \OC_FileProxy::$enabled = false; -- cgit v1.2.3 From b3e59ca1e31f162d7ac720d8729958f438b23a02 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Sat, 9 Feb 2013 18:39:32 +0000 Subject: Work on post_share hook for files_encryption New method in OCP\Share{}:: getUsersSharingFile() Development shapshot --- apps/files_encryption/hooks/hooks.php | 71 +++- apps/files_encryption/lib/keymanager.php | 585 +++++++++++++++---------------- apps/files_encryption/lib/proxy.php | 32 +- lib/public/share.php | 54 +++ 4 files changed, 430 insertions(+), 312 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 8bdeee0937b..c6d4c16115a 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -166,14 +166,77 @@ class Hooks { */ public static function postShared( $params ) { - // Delete existing catfile - Keymanager::deleteFileKey( ); + // NOTE: $params is an array with these keys: + // itemSource -> int, filecache file ID + // shareWith -> string, uid of user being shared to + // fileTarget -> path of file being shared + // uidOwner -> owner of the original file being shared - // Generate new catfile and env keys - Crypt::multiKeyEncrypt( $plainContent, $publicKeys ); + $view = new \OC_FilesystemView( '/' ); + $userId = \OCP\User::getUser(); + $util = new Util( $view, $userId ); + + $shares = \OCP\Share::getUsersSharingFile( $params['fileTarget'] ); + + $userIds = array(); + + foreach ( $shares as $share ) { + + $util = new Util( $view, $share['userId'] ); + + // Check that the user is encryption capable + if ( $util->ready() ) { + + // Construct array of just UIDs for Keymanager{} + $userIds[] = $share['userId']; + + } else { + + // Log warning; we can't do necessary setup here + // because we don't have the user passphrase + // TODO: Provide user feedback indicating that + // sharing failed + \OC_Log::write( 'Encryption library', 'File cannot be shared: user "'.$share['userId'].'" is not setup for encryption', \OC_Log::WARN ); + + } + + } + + trigger_error("UIDS = ".var_export($userIds, 1)); + + $userPubKeys = Keymanager::getPublicKeys( $view, $userIds ); + +// trigger_error("PUB KEYS = ".var_export($userPubKeys, 1)); + + // TODO: Fetch path from Crypt{} getter + $plainContent = $view->file_get_contents( $userId . '/' . 'files'. '/' . $params['fileTarget'] ); + + // Generate new catfile and share keys + if ( ! $encrypted = Crypt::multiKeyEncrypt( $plainContent, $userPubKeys ) ) { + + // If the re-encryption failed, don't risk deleting data + return false; + + } + + trigger_error("ENCRYPTED = ". var_export($encrypted, 1)); // Save env keys to user folders + foreach ( $encrypted['keys'] as $key ) { + +// Keymanager::setShareKey( $view, $params['fileTarget'], $userId, $key ); + + } + // Delete existing catfile + // Check if keyfile exists (it won't if file has been shared before) + // Do this last to ensure file is recoverable in case of error + if ( $util->isEncryptedPath( $params['fileTarget'] ) ) { + + // NOTE: This will trigger an error if keyfile isn't found +// Keymanager::deleteFileKey( $params['fileTarget'] ); + + } } diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 0d0380db6ec..3160572ba1b 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -1,267 +1,244 @@ - - * - * 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 . - * - */ - -namespace OCA\Encryption; - -/** - * @brief Class to manage storage and retrieval of encryption keys - * @note Where a method requires a view object, it's root must be '/' - */ -class Keymanager { - - /** - * @brief retrieve the ENCRYPTED private key from a user - * - * @return string private key or false - * @note the key returned by this method must be decrypted before use - */ - public static function getPrivateKey( \OC_FilesystemView $view, $user ) { - - $path = '/' . $user . '/' . 'files_encryption' . '/' . $user.'.private.key'; - - $key = $view->file_get_contents( $path ); - - return $key; - } - - /** - * @brief retrieve public key for a specified user + + * + * 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 . + * + */ + +namespace OCA\Encryption; + +/** + * @brief Class to manage storage and retrieval of encryption keys + * @note Where a method requires a view object, it's root must be '/' + */ +class Keymanager { + + /** + * @brief retrieve the ENCRYPTED private key from a user + * + * @return string private key or false + * @note the key returned by this method must be decrypted before use + */ + public static function getPrivateKey( \OC_FilesystemView $view, $user ) { + + $path = '/' . $user . '/' . 'files_encryption' . '/' . $user.'.private.key'; + + $key = $view->file_get_contents( $path ); + + return $key; + } + + /** + * @brief retrieve public key for a specified user * @param \OC_FilesystemView $view * @param $userId - * @return string public key or false - */ - public static function getPublicKey( \OC_FilesystemView $view, $userId ) { - - return $view->file_get_contents( '/public-keys/' . '/' . $userId . '.public.key' ); - - } - - /** - * @brief retrieve both keys from a user (private and public) + * @return string public key or false + */ + public static function getPublicKey( \OC_FilesystemView $view, $userId ) { + + return $view->file_get_contents( '/public-keys/' . '/' . $userId . '.public.key' ); + + } + + /** + * @brief Retrieve a user's public and private key * @param \OC_FilesystemView $view * @param $userId - * @return array keys: privateKey, publicKey - */ - public static function getUserKeys( \OC_FilesystemView $view, $userId ) { - - return array( - 'publicKey' => self::getPublicKey( $view, $userId ) - , 'privateKey' => self::getPrivateKey( $view, $userId ) - ); - - } - - /** - * @brief Retrieve public keys of all users with access to a file - * @param string $path Path to file - * @return array of public keys for the given file - * @note Checks that the sharing app is enabled should be performed - * by client code, that isn't checked here - */ - public static function getPublicKeys( \OC_FilesystemView $view, $userId, $filePath ) { - - $path = ltrim( $path, '/' ); - - $filepath = '/' . $userId . '/files/' . $filePath; - - // Check if sharing is enabled - if ( OC_App::isEnabled( 'files_sharing' ) ) { - - - - } else { - - // check if it is a file owned by the user and not shared at all - $userview = new \OC_FilesystemView( '/'.$userId.'/files/' ); - - if ( $userview->file_exists( $path ) ) { - - $users[] = $userId; - - } - - } - - $view = new \OC_FilesystemView( '/public-keys/' ); - - $keylist = array(); - - $count = 0; - - foreach ( $users as $user ) { - - $keylist['key'.++$count] = $view->file_get_contents( $user.'.public.key' ); - - } - - return $keylist; - - } - - /** - * @brief store file encryption key - * - * @param string $path relative path of the file, including filename - * @param string $key - * @return bool true/false - * @note The keyfile is not encrypted here. Client code must - * asymmetrically encrypt the keyfile before passing it to this method - */ - public static function setFileKey( \OC_FilesystemView $view, $path, $userId, $catfile ) { - - $basePath = '/' . $userId . '/files_encryption/keyfiles'; - - $targetPath = self::keySetPreparation( $view, $path, $basePath, $userId ); - - if ( $view->is_dir( $basePath . '/' . $targetPath ) ) { - - - - } else { - - // Save the keyfile in parallel directory - return $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); - - } - - } - - /** - * @brief retrieve keyfile for an encrypted file + * @return array keys: privateKey, publicKey + */ + public static function getUserKeys( \OC_FilesystemView $view, $userId ) { + + return array( + 'publicKey' => self::getPublicKey( $view, $userId ) + , 'privateKey' => self::getPrivateKey( $view, $userId ) + ); + + } + + /** + * @brief Retrieve public keys for given users + * @param \OC_FilesystemView $view + * @param array $userIds + * @return array of public keys for the specified users + */ + public static function getPublicKeys( \OC_FilesystemView $view, $userIds ) { + + $i = 0; + $keys = array(); + + foreach ( $userIds as $userId ) { + + $i++; + $keys[$userId] = self::getPublicKey( $view, $userId ); + + } + + $keys['total'] = $i; + + return $keys; + + } + + /** + * @brief store file encryption key + * + * @param string $path relative path of the file, including filename + * @param string $key + * @return bool true/false + * @note The keyfile is not encrypted here. Client code must + * asymmetrically encrypt the keyfile before passing it to this method + */ + public static function setFileKey( \OC_FilesystemView $view, $path, $userId, $catfile ) { + + $basePath = '/' . $userId . '/files_encryption/keyfiles'; + + $targetPath = self::keySetPreparation( $view, $path, $basePath, $userId ); + + if ( $view->is_dir( $basePath . '/' . $targetPath ) ) { + + + + } else { + + // Save the keyfile in parallel directory + return $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); + + } + + } + + /** + * @brief retrieve keyfile for an encrypted file * @param \OC_FilesystemView $view * @param $userId * @param $filePath * @internal param \OCA\Encryption\file $string name * @return string file key or false - * @note The keyfile returned is asymmetrically encrypted. Decryption - * of the keyfile must be performed by client code - */ - public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) { - - $filePath_f = ltrim( $filePath, '/' ); - - $catfilePath = '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key'; - - if ( $view->file_exists( $catfilePath ) ) { - - return $view->file_get_contents( $catfilePath ); - - } else { - - return false; - - } - - } - - /** - * @brief Delete a keyfile - * + * @note The keyfile returned is asymmetrically encrypted. Decryption + * of the keyfile must be performed by client code + */ + public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) { + + $filePath_f = ltrim( $filePath, '/' ); + + $catfilePath = '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key'; + + if ( $view->file_exists( $catfilePath ) ) { + + return $view->file_get_contents( $catfilePath ); + + } else { + + return false; + + } + + } + + /** + * @brief Delete a keyfile + * * @param OC_FilesystemView $view * @param string $userId username * @param string $path path of the file the key belongs to * @return bool Outcome of unlink operation * @note $path must be relative to data/user/files. e.g. mydoc.txt NOT * /data/admin/files/mydoc.txt - */ - public static function deleteFileKey( \OC_FilesystemView $view, $userId, $path ) { - - $trimmed = ltrim( $path, '/' ); - $keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed . '.key'; - - // Unlink doesn't tell us if file was deleted (not found returns - // true), so we perform our own test - if ( $view->file_exists( $keyPath ) ) { - - return $view->unlink( $keyPath ); - - } else { - - \OC_Log::write( 'Encryption library', 'Could not delete keyfile; does not exist: "' . $keyPath, \OC_Log::ERROR ); - - return false; - - } - - } - - /** - * @brief store private key from the user - * @param string key - * @return bool - * @note Encryption of the private key must be performed by client code - * as no encryption takes place here - */ - public static function setPrivateKey( $key ) { - - $user = \OCP\User::getUser(); - - $view = new \OC_FilesystemView( '/' . $user . '/files_encryption' ); - - \OC_FileProxy::$enabled = false; - - if ( !$view->file_exists( '' ) ) $view->mkdir( '' ); - - return $view->file_put_contents( $user . '.private.key', $key ); - - \OC_FileProxy::$enabled = true; - - } - - /** - * @brief store private keys from the user - * - * @param string privatekey - * @param string publickey - * @return bool true/false - */ - public static function setUserKeys($privatekey, $publickey) { - - return ( self::setPrivateKey( $privatekey ) && self::setPublicKey( $publickey ) ); - - } - - /** - * @brief store public key of the user - * - * @param string key - * @return bool true/false - */ - public static function setPublicKey( $key ) { - - $view = new \OC_FilesystemView( '/public-keys' ); - - \OC_FileProxy::$enabled = false; - - if ( !$view->file_exists( '' ) ) $view->mkdir( '' ); - - return $view->file_put_contents( \OCP\User::getUser() . '.public.key', $key ); - - \OC_FileProxy::$enabled = true; - - } - - /** + */ + public static function deleteFileKey( \OC_FilesystemView $view, $userId, $path ) { + + $trimmed = ltrim( $path, '/' ); + $keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed . '.key'; + + // Unlink doesn't tell us if file was deleted (not found returns + // true), so we perform our own test + if ( $view->file_exists( $keyPath ) ) { + + return $view->unlink( $keyPath ); + + } else { + + \OC_Log::write( 'Encryption library', 'Could not delete keyfile; does not exist: "' . $keyPath, \OC_Log::ERROR ); + + return false; + + } + + } + + /** + * @brief store private key from the user + * @param string key + * @return bool + * @note Encryption of the private key must be performed by client code + * as no encryption takes place here + */ + public static function setPrivateKey( $key ) { + + $user = \OCP\User::getUser(); + + $view = new \OC_FilesystemView( '/' . $user . '/files_encryption' ); + + \OC_FileProxy::$enabled = false; + + if ( !$view->file_exists( '' ) ) $view->mkdir( '' ); + + return $view->file_put_contents( $user . '.private.key', $key ); + + \OC_FileProxy::$enabled = true; + + } + + /** + * @brief store private keys from the user + * + * @param string privatekey + * @param string publickey + * @return bool true/false + */ + public static function setUserKeys($privatekey, $publickey) { + + return ( self::setPrivateKey( $privatekey ) && self::setPublicKey( $publickey ) ); + + } + + /** + * @brief store public key of the user + * + * @param string key + * @return bool true/false + */ + public static function setPublicKey( $key ) { + + $view = new \OC_FilesystemView( '/public-keys' ); + + \OC_FileProxy::$enabled = false; + + if ( !$view->file_exists( '' ) ) $view->mkdir( '' ); + + return $view->file_put_contents( \OCP\User::getUser() . '.public.key', $key ); + + \OC_FileProxy::$enabled = true; + + } + + /** * @brief store file encryption key * * @param string $path relative path of the file, including filename @@ -271,70 +248,70 @@ class Keymanager { * @return bool true/false * @note The keyfile is not encrypted here. Client code must * asymmetrically encrypt the keyfile before passing it to this method - */ - public static function setShareKey( \OC_FilesystemView $view, $path, $userId, $shareKey ) { - - $basePath = '/' . $userId . '/files_encryption/share-keys'; - - $shareKeyPath = self::keySetPreparation( $view, $path, $basePath, $userId ); - - return $view->file_put_contents( $basePath . '/' . $shareKeyPath . '.shareKey', $shareKey ); - + */ + public static function setShareKey( \OC_FilesystemView $view, $path, $userId, $shareKey ) { + + $basePath = '/' . $userId . '/files_encryption/share-keys'; + + $shareKeyPath = self::keySetPreparation( $view, $path, $basePath, $userId ); + + return $view->file_put_contents( $basePath . '/' . $shareKeyPath . '.shareKey', $shareKey ); + } /** * @brief Make preparations to vars and filesystem for saving a keyfile */ public static function keySetPreparation( \OC_FilesystemView $view, $path, $basePath, $userId ) { - - $targetPath = ltrim( $path, '/' ); - - $path_parts = pathinfo( $targetPath ); - - // If the file resides within a subdirectory, create it + + $targetPath = ltrim( $path, '/' ); + + $path_parts = pathinfo( $targetPath ); + + // If the file resides within a subdirectory, create it if ( isset( $path_parts['dirname'] ) && ! $view->file_exists( $basePath . '/' . $path_parts['dirname'] ) - ) { - - $view->mkdir( $basePath . '/' . $path_parts['dirname'] ); - - } - + ) { + + $view->mkdir( $basePath . '/' . $path_parts['dirname'] ); + + } + return $targetPath; - } - - /** - * @brief change password of private encryption key - * - * @param string $oldpasswd old password - * @param string $newpasswd new password - * @return bool true/false - */ - public static function changePasswd($oldpasswd, $newpasswd) { - - if ( \OCP\User::checkPassword(\OCP\User::getUser(), $newpasswd) ) { - return Crypt::changekeypasscode($oldpasswd, $newpasswd); - } - return false; - - } - - /** - * @brief Fetch the legacy encryption key from user files - * @param string $login used to locate the legacy key - * @param string $passphrase used to decrypt the legacy key - * @return true / false - * - * if the key is left out, the default handeler will be used - */ - public function getLegacyKey() { - - $user = \OCP\User::getUser(); - $view = new \OC_FilesystemView( '/' . $user ); - return $view->file_get_contents( 'encryption.key' ); - - } - + } + + /** + * @brief change password of private encryption key + * + * @param string $oldpasswd old password + * @param string $newpasswd new password + * @return bool true/false + */ + public static function changePasswd($oldpasswd, $newpasswd) { + + if ( \OCP\User::checkPassword(\OCP\User::getUser(), $newpasswd) ) { + return Crypt::changekeypasscode($oldpasswd, $newpasswd); + } + return false; + + } + + /** + * @brief Fetch the legacy encryption key from user files + * @param string $login used to locate the legacy key + * @param string $passphrase used to decrypt the legacy key + * @return true / false + * + * if the key is left out, the default handeler will be used + */ + public function getLegacyKey() { + + $user = \OCP\User::getUser(); + $view = new \OC_FilesystemView( '/' . $user ); + return $view->file_get_contents( 'encryption.key' ); + + } + } \ No newline at end of file diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 7ae36e34ce1..58b9bc0725b 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -95,7 +95,8 @@ class Proxy extends \OC_FileProxy { if ( self::shouldEncrypt( $path ) ) { - if ( !is_resource( $data ) ) { //stream put contents should have been converted to fopen + // Stream put contents should have been converted to fopen + if ( !is_resource( $data ) ) { $userId = \OCP\USER::getUser(); @@ -107,10 +108,33 @@ class Proxy extends \OC_FileProxy { // Disable encryption proxy to prevent recursive calls \OC_FileProxy::$enabled = false; - // TODO: Check if file is shared, if so, use multiKeyEncrypt + $fileOwner = \OC\Files\Filesystem::getOwner( $path ); - // Encrypt plain data and fetch key - $encrypted = Crypt::keyEncryptKeyfile( $data, Keymanager::getPublicKey( $rootView, $userId ) ); + // Check if the keyfile needs to be shared + if ( + $fileOwner !== true + or $fileOwner !== $userId + ) { + + // Shared storage backend isn't loaded + + $users = \OCP\Share::getItemShared( 'file', $path, \OC_Share_backend_File::FORMAT_SHARED_STORAGE ); +// + trigger_error("SHARE USERS = ". var_export($users, 1)); +// +// $publicKeys = Keymanager::getPublicKeys( $rootView, $users); +// +// // Encrypt plain data to multiple users +// $encrypted = Crypt::multiKeyEncrypt( $data, $publicKeys ); + + } else { + + $publicKey = Keymanager::getPublicKey( $rootView, $userId ); + + // Encrypt plain data to a single user + $encrypted = Crypt::keyEncryptKeyfile( $data, $publicKey ); + + } // Replace plain content with encrypted content by reference $data = $encrypted['data']; diff --git a/lib/public/share.php b/lib/public/share.php index af2a538e252..936f85021c0 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -91,6 +91,60 @@ class Share { } return false; } + + /** + * @brief Find which users can access a shared item + * @param string Item type + * @param int Format (optional) Format type must be defined by the backend + * @param int Number of items to return (optional) Returns all by default + * @return Return depends on format + */ + public static function getUsersSharingFile( $path ) { + + // Fetch all shares of this file path from DB + $query = \OC_DB::prepare( + 'SELECT + share_type + , share_with + , permissions + FROM + `*PREFIX*share` + WHERE + file_target = ?' + ); + + $result = $query->execute( array( $path ) ); + + if ( \OC_DB::isError( $result ) ) { + + \OC_Log::write( 'OCP\Share', \OC_DB::getErrorMessage($result) . ', path=' . $path, \OC_Log::ERROR ); + + } + + $shares = array(); + + while( $row = $result->fetchRow() ) { + + // Set helpful array keys + $shares[] = array( + 'userId' => $row['share_with'] + , 'shareType' => $row['share_type'] + , 'permissions' => $row['permissions'] + ); + + } + + if ( ! empty( $shares ) ) { + + return $shares; + + } else { + + return false; + + } + + } /** * @brief Get the items of item type shared with the current user -- cgit v1.2.3 From 92f06243be62945b5ff5e7542e9984f7bb45d74b Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Mon, 11 Feb 2013 10:21:23 +0000 Subject: Implementing sharing support New file-specific methods in lib/public/share Changes to how keyfiles are stored --- apps/files_encryption/hooks/hooks.php | 47 +++++++------ apps/files_encryption/lib/crypt.php | 41 ++++++++--- apps/files_encryption/lib/keymanager.php | 97 +++++++++++++++++++++++--- apps/files_encryption/lib/proxy.php | 113 +++++++++++++++++-------------- apps/files_encryption/test/crypt.php | 8 +-- lib/public/share.php | 82 ++++++++++++++++++++-- 6 files changed, 283 insertions(+), 105 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index c6d4c16115a..9252a341fb7 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -82,8 +82,12 @@ class Hooks { } + \OC_FileProxy::$enabled = false; + $publicKey = Keymanager::getPublicKey( $view, $params['uid'] ); + \OC_FileProxy::$enabled = false; + // Encrypt existing user files: // This serves to upgrade old versions of the encryption // app (see appinfo/spec.txt) @@ -175,8 +179,9 @@ class Hooks { $view = new \OC_FilesystemView( '/' ); $userId = \OCP\User::getUser(); $util = new Util( $view, $userId ); + $session = new Session(); - $shares = \OCP\Share::getUsersSharingFile( $params['fileTarget'] ); + $shares = \OCP\Share::getUsersSharingFile( $params['fileTarget'], 1 ); $userIds = array(); @@ -202,41 +207,35 @@ class Hooks { } - trigger_error("UIDS = ".var_export($userIds, 1)); - $userPubKeys = Keymanager::getPublicKeys( $view, $userIds ); -// trigger_error("PUB KEYS = ".var_export($userPubKeys, 1)); - - // TODO: Fetch path from Crypt{} getter - $plainContent = $view->file_get_contents( $userId . '/' . 'files'. '/' . $params['fileTarget'] ); + \OC_FileProxy::$enabled = false; - // Generate new catfile and share keys - if ( ! $encrypted = Crypt::multiKeyEncrypt( $plainContent, $userPubKeys ) ) { + // get the keyfile + $encKeyfile = Keymanager::getFileKey( $view, $userId, $params['fileTarget'] ); - // If the re-encryption failed, don't risk deleting data - return false; - - } + $privateKey = $session->getPrivateKey(); - trigger_error("ENCRYPTED = ". var_export($encrypted, 1)); + // decrypt the keyfile + $plainKeyfile = Crypt::keyDecrypt( $encKeyfile, $privateKey ); - // Save env keys to user folders - foreach ( $encrypted['keys'] as $key ) { + // re-enc keyfile to sharekeys + $shareKeys = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys ); -// Keymanager::setShareKey( $view, $params['fileTarget'], $userId, $key ); + // save sharekeys + if ( ! Keymanager::setShareKeys( $view, $params['fileTarget'], $shareKeys['keys'] ) ) { + trigger_error( "SET Share keys failed" ); + } - // Delete existing catfile - // Check if keyfile exists (it won't if file has been shared before) + // Delete existing keyfile // Do this last to ensure file is recoverable in case of error - if ( $util->isEncryptedPath( $params['fileTarget'] ) ) { - - // NOTE: This will trigger an error if keyfile isn't found -// Keymanager::deleteFileKey( $params['fileTarget'] ); +// Keymanager::deleteFileKey( $view, $userId, $params['fileTarget'] ); - } + \OC_FileProxy::$enabled = true; + + return true; } diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index e3d23023db3..fdee03eeaf5 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -370,22 +370,41 @@ class Crypt { /** * @brief Create asymmetrically encrypted keyfile content using a generated key * @param string $plainContent content to be encrypted - * @returns array keys: key, encrypted - * @note symmetricDecryptFileContent() can be used to decrypt files created using this method - * - * This function decrypts a file + * @param array $publicKeys array keys must be the userId of corresponding user + * @returns array keys: keys (array, key = userId), encrypted + * @note symmetricDecryptFileContent() can decrypt files created using this method */ public static function multiKeyEncrypt( $plainContent, array $publicKeys ) { - + + // openssl_seal returns false without errors if $plainContent + // is empty, so trigger our own error + if ( empty( $plainContent ) ) { + + trigger_error( "Cannot mutliKeyEncrypt empty plain content" ); + throw new \Exception( 'Cannot mutliKeyEncrypt empty plain content' ); + + } + // Set empty vars to be set by openssl by reference $sealed = ''; - $envKeys = array(); + $shareKeys = array(); - if( openssl_seal( $plainContent, $sealed, $envKeys, $publicKeys ) ) { + if( openssl_seal( $plainContent, $sealed, $shareKeys, $publicKeys ) ) { + + $i = 0; + + // Ensure each shareKey is labelled with its + // corresponding userId + foreach ( $publicKeys as $userId => $publicKey ) { + + $mappedShareKeys[$userId] = $shareKeys[$i]; + $i++; + + } return array( - 'keys' => $envKeys - , 'encrypted' => $sealed + 'keys' => $mappedShareKeys + , 'data' => $sealed ); } else { @@ -404,7 +423,7 @@ class Crypt { * * This function decrypts a file */ - public static function multiKeyDecrypt( $encryptedContent, $envKey, $privateKey ) { + public static function multiKeyDecrypt( $encryptedContent, $shareKey, $privateKey ) { if ( !$encryptedContent ) { @@ -412,7 +431,7 @@ class Crypt { } - if ( openssl_open( $encryptedContent, $plainContent, $envKey, $privateKey ) ) { + if ( openssl_open( $encryptedContent, $plainContent, $shareKey, $privateKey ) ) { return $plainContent; diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 3160572ba1b..5f9eea1a0bc 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -52,8 +52,11 @@ class Keymanager { */ public static function getPublicKey( \OC_FilesystemView $view, $userId ) { + \OC_FileProxy::$enabled = false; + return $view->file_get_contents( '/public-keys/' . '/' . $userId . '.public.key' ); + \OC_FileProxy::$enabled = true; } /** @@ -77,20 +80,16 @@ class Keymanager { * @param array $userIds * @return array of public keys for the specified users */ - public static function getPublicKeys( \OC_FilesystemView $view, $userIds ) { + public static function getPublicKeys( \OC_FilesystemView $view, array $userIds ) { - $i = 0; $keys = array(); foreach ( $userIds as $userId ) { - $i++; $keys[$userId] = self::getPublicKey( $view, $userId ); } - $keys['total'] = $i; - return $keys; } @@ -137,11 +136,11 @@ class Keymanager { $filePath_f = ltrim( $filePath, '/' ); - $catfilePath = '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key'; + $keyfilePath = '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key'; - if ( $view->file_exists( $catfilePath ) ) { + if ( $view->file_exists( $keyfilePath ) ) { - return $view->file_get_contents( $catfilePath ); + return $view->file_get_contents( $keyfilePath ); } else { @@ -239,7 +238,7 @@ class Keymanager { } /** - * @brief store file encryption key + * @brief store share key * * @param string $path relative path of the file, including filename * @param string $key @@ -255,7 +254,85 @@ class Keymanager { $shareKeyPath = self::keySetPreparation( $view, $path, $basePath, $userId ); - return $view->file_put_contents( $basePath . '/' . $shareKeyPath . '.shareKey', $shareKey ); + $writePath = $basePath . '/' . $shareKeyPath . '.shareKey'; + + \OC_FileProxy::$enabled = false; + + $result = $view->file_put_contents( $writePath, $shareKey ); + + if ( + is_int( $result ) + && $result > 0 + ) { + + return true; + + } else { + + return false; + + } + + } + + /** + * @brief store multiple share keys for a single file + * @return bool + */ + public static function setShareKeys( \OC_FilesystemView $view, $path, array $shareKeys ) { + + // $shareKeys must be an array with the following format: + // [userId] => [encrypted key] + + $result = true; + + foreach ( $shareKeys as $userId => $shareKey ) { + + if ( ! self::setShareKey( $view, $path, $userId, $shareKey ) ) { + + // If any of the keys are not set, flag false + $result = false; + + } + + } + + // Returns false if any of the keys weren't set + return $result; + + } + + /** + * @brief retrieve shareKey for an encrypted file + * @param \OC_FilesystemView $view + * @param $userId + * @param $filePath + * @internal param \OCA\Encryption\file $string name + * @return string file key or false + * @note The sharekey returned is encrypted. Decryption + * of the keyfile must be performed by client code + */ + public static function getShareKey( \OC_FilesystemView $view, $userId, $filePath ) { + + \OC_FileProxy::$enabled = false; + + $filePath_f = ltrim( $filePath, '/' ); + + $shareKeyPath = '/' . $userId . '/files_encryption/share-keys/' . $filePath_f . '.shareKey'; + + if ( $view->file_exists( $shareKeyPath ) ) { + + $result = $view->file_get_contents( $shareKeyPath ); + + } else { + + $result = false; + + } + + \OC_FileProxy::$enabled = true; + + return $result; } diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 58b9bc0725b..b5e59e89b9e 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -99,58 +99,65 @@ class Proxy extends \OC_FileProxy { if ( !is_resource( $data ) ) { $userId = \OCP\USER::getUser(); - $rootView = new \OC_FilesystemView( '/' ); - + $util = new Util( $rootView, $userId ); + $filePath = $util->stripUserFilesPath( $path ); // Set the filesize for userland, before encrypting $size = strlen( $data ); // Disable encryption proxy to prevent recursive calls \OC_FileProxy::$enabled = false; - $fileOwner = \OC\Files\Filesystem::getOwner( $path ); + // Encrypt data + $encData = Crypt::symmetricEncryptFileContentKeyfile( $data ); // Check if the keyfile needs to be shared - if ( - $fileOwner !== true - or $fileOwner !== $userId - ) { + if ( \OCP\Share::isSharedFile( $filePath ) ) { + +// $fileOwner = \OC\Files\Filesystem::getOwner( $path ); + + // List everyone sharing the file + $shares = \OCP\Share::getUsersSharingFile( $filePath, 1 ); + + $userIds = array(); + + foreach ( $shares as $share ) { + + $userIds[] = $share['userId']; + + } + + $publicKeys = Keymanager::getPublicKeys( $rootView, $userIds ); + + \OC_FileProxy::$enabled = false; + + // Encrypt plain keyfile to multiple sharefiles + $multiEncrypted = Crypt::multiKeyEncrypt( $encData['key'], $publicKeys ); + + // Save sharekeys to user folders + Keymanager::setShareKeys( $rootView, $filePath, $multiEncrypted['keys'] ); + + // Set encrypted keyfile as common varname + $encKey = $multiEncrypted['encrypted']; - // Shared storage backend isn't loaded - $users = \OCP\Share::getItemShared( 'file', $path, \OC_Share_backend_File::FORMAT_SHARED_STORAGE ); -// - trigger_error("SHARE USERS = ". var_export($users, 1)); -// -// $publicKeys = Keymanager::getPublicKeys( $rootView, $users); -// -// // Encrypt plain data to multiple users -// $encrypted = Crypt::multiKeyEncrypt( $data, $publicKeys ); } else { $publicKey = Keymanager::getPublicKey( $rootView, $userId ); // Encrypt plain data to a single user - $encrypted = Crypt::keyEncryptKeyfile( $data, $publicKey ); + $encKey = Crypt::keyEncrypt( $encData['key'], $publicKey ); } - // Replace plain content with encrypted content by reference - $data = $encrypted['data']; - - $filePath = explode( '/', $path ); - - $filePath = array_slice( $filePath, 3 ); - - $filePath = '/' . implode( '/', $filePath ); - - // TODO: make keyfile dir dynamic from app config - - $view = new \OC_FilesystemView( '/' ); + // TODO: Replace userID with ownerId so keyfile is saved centrally // Save keyfile for newly encrypted file in parallel directory tree - Keymanager::setFileKey( $view, $filePath, $userId, $encrypted['key'] ); + Keymanager::setFileKey( $rootView, $filePath, $userId, $encKey ); + + // Replace plain content with encrypted content by reference + $data = $encData['encrypted']; // Update the file cache with file info \OC\Files\Filesystem::putFileInfo( $path, array( 'encrypted'=>true, 'size' => $size ), '' ); @@ -168,8 +175,6 @@ class Proxy extends \OC_FileProxy { * @param string $data Data that has been read from file */ public function postFile_get_contents( $path, $data ) { - - // TODO: Use dependency injection to add required args for view and user etc. to this method // Disable encryption proxy to prevent recursive calls \OC_FileProxy::$enabled = false; @@ -180,45 +185,55 @@ class Proxy extends \OC_FileProxy { && Crypt::isCatfile( $data ) ) { - $split = explode( '/', $path ); - - $filePath = array_slice( $split, 3 ); + $view = new \OC_FilesystemView( '/' ); + $userId = \OCP\USER::getUser(); + $session = new Session(); + $util = new Util( $view, $userId ); + $filePath = $util->stripUserFilesPath( $path ); + $privateKey = $session->getPrivateKey( $userId ); - $filePath = '/' . implode( '/', $filePath ); + // Get the encrypted keyfile + $encKeyfile = Keymanager::getFileKey( $view, $userId, $filePath ); - //$cached = \OC\Files\Filesystem::getFileInfo( $path, '' ); + // Check if key is shared or not + if ( \OCP\Share::isSharedFile( $filePath ) ) { - $view = new \OC_FilesystemView( '' ); + // If key is shared, fetch the user's shareKey + $shareKey = Keymanager::getShareKey( $view, $userId, $filePath ); + + \OC_FileProxy::$enabled = false; + + // Decrypt keyfile with shareKey + $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); - $userId = \OCP\USER::getUser(); + } else { + + // If key is unshared, decrypt with user private key + $plainKeyfile = Crypt::keyDecrypt( $encKeyfile, $privateKey ); - // TODO: Check if file is shared, if so, use multiKeyDecrypt + } - $encryptedKeyfile = Keymanager::getFileKey( $view, $userId, $filePath ); + $plainData = Crypt::symmetricDecryptFileContent( $data, $plainKeyfile ); - $session = new Session(); - - $decrypted = Crypt::keyDecryptKeyfile( $data, $encryptedKeyfile, $session->getPrivateKey( $split[1] ) ); - } elseif ( Crypt::mode() == 'server' && isset( $_SESSION['legacyenckey'] ) && Crypt::isEncryptedMeta( $path ) ) { - $decrypted = Crypt::legacyDecrypt( $data, $_SESSION['legacyenckey'] ); + $plainData = Crypt::legacyDecrypt( $data, $session->getLegacyKey() ); } \OC_FileProxy::$enabled = true; - if ( ! isset( $decrypted ) ) { + if ( ! isset( $plainData ) ) { - $decrypted = $data; + $plainData = $data; } - return $decrypted; + return $plainData; } diff --git a/apps/files_encryption/test/crypt.php b/apps/files_encryption/test/crypt.php index aa87ec32821..48ad2ee0075 100755 --- a/apps/files_encryption/test/crypt.php +++ b/apps/files_encryption/test/crypt.php @@ -439,14 +439,14 @@ class Test_Crypt extends \PHPUnit_Framework_TestCase { $this->assertTrue( strlen( $pair1['privateKey'] ) > 1 ); - $crypted = Encryption\Crypt::multiKeyEncrypt( $this->dataUrl, array( $pair1['publicKey'] ) ); + $crypted = Encryption\Crypt::multiKeyEncrypt( $this->dataShort, array( $pair1['publicKey'] ) ); - $this->assertNotEquals( $this->dataUrl, $crypted['encrypted'] ); + $this->assertNotEquals( $this->dataShort, $crypted['data'] ); - $decrypt = Encryption\Crypt::multiKeyDecrypt( $crypted['encrypted'], $crypted['keys'][0], $pair1['privateKey'] ); + $decrypt = Encryption\Crypt::multiKeyDecrypt( $crypted['data'], $crypted['keys'][0], $pair1['privateKey'] ); - $this->assertEquals( $this->dataUrl, $decrypt ); + $this->assertEquals( $this->dataShort, $decrypt ); } diff --git a/lib/public/share.php b/lib/public/share.php index 936f85021c0..4170783d71e 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -92,20 +92,73 @@ class Share { return false; } + /** + * @brief Prepare a path to be passed to DB as file_target + * @return string Prepared path + */ + public static function prepFileTarget( $path ) { + + // Paths in DB are stored with leading slashes, so add one if necessary + if ( substr( $path, 0, 1 ) !== '/' ) { + + $path = '/' . $path; + + } + + return $path; + + } + + public static function isSharedFile( $path ) { + + $fPath = self::prepFileTarget( $path ); + + // Fetch all shares of this file path from DB + $query = \OC_DB::prepare( + 'SELECT + id + FROM + `*PREFIX*share` + WHERE + file_target = ?' + ); + + $result = $query->execute( array( $fPath ) ); + + if ( \OC_DB::isError( $result ) ) { + + \OC_Log::write( 'OCP\Share', \OC_DB::getErrorMessage( $result ) . ', path=' . $fPath, \OC_Log::ERROR ); + + } + + if ( $result->fetchRow() !== false ) { + + return true; + + } else { + + return false; + + } + + } + /** * @brief Find which users can access a shared item - * @param string Item type - * @param int Format (optional) Format type must be defined by the backend - * @param int Number of items to return (optional) Returns all by default - * @return Return depends on format + * @return bool / array + * @note $path needs to be relative to user data dir, e.g. 'file.txt' + * not '/admin/data/file.txt' */ - public static function getUsersSharingFile( $path ) { + public static function getUsersSharingFile( $path, $includeOwner = 0 ) { + + $fPath = self::prepFileTarget( $path ); // Fetch all shares of this file path from DB $query = \OC_DB::prepare( 'SELECT share_type , share_with + , uid_owner , permissions FROM `*PREFIX*share` @@ -113,11 +166,11 @@ class Share { file_target = ?' ); - $result = $query->execute( array( $path ) ); + $result = $query->execute( array( $fPath ) ); if ( \OC_DB::isError( $result ) ) { - \OC_Log::write( 'OCP\Share', \OC_DB::getErrorMessage($result) . ', path=' . $path, \OC_Log::ERROR ); + \OC_Log::write( 'OCP\Share', \OC_DB::getErrorMessage($result) . ', path=' . $fPath, \OC_Log::ERROR ); } @@ -128,6 +181,7 @@ class Share { // Set helpful array keys $shares[] = array( 'userId' => $row['share_with'] + , 'owner' => $row['uid_owner'] // we just set this so it can be used once, hugly hack :/ , 'shareType' => $row['share_type'] , 'permissions' => $row['permissions'] ); @@ -136,6 +190,20 @@ class Share { if ( ! empty( $shares ) ) { + // Include owner in list of users, if requested + if ( $includeOwner == 1 ) { + + // NOTE: The values are incorrect for shareType and + // permissions of the owner; we just include them for + // optional convenience + $shares[] = array( + 'userId' => $shares[0]['owner'] + , 'shareType' => 0 + , 'permissions' => 0 + ); + + } + return $shares; } else { -- cgit v1.2.3 From 2787aafae6577dfad1f3db0dc70a8e0b05eaba53 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Mon, 11 Feb 2013 12:12:21 +0100 Subject: added some TODOs --- apps/files_encryption/hooks/hooks.php | 1 + apps/files_encryption/lib/proxy.php | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 9252a341fb7..b0075a3ada7 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -190,6 +190,7 @@ class Hooks { $util = new Util( $view, $share['userId'] ); // Check that the user is encryption capable + // TODO create encryption key when user gets created if ( $util->ready() ) { // Construct array of just UIDs for Keymanager{} diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index b5e59e89b9e..40ac411539b 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -92,12 +92,13 @@ class Proxy extends \OC_FileProxy { } public function preFile_put_contents( $path, &$data ) { - + // TODO check for existing key file and reuse it if possible to avoid problems with versioning etc. if ( self::shouldEncrypt( $path ) ) { // Stream put contents should have been converted to fopen if ( !is_resource( $data ) ) { + // TODO check who is the owner of the file in case of shared folders $userId = \OCP\USER::getUser(); $rootView = new \OC_FilesystemView( '/' ); $util = new Util( $rootView, $userId ); @@ -175,7 +176,7 @@ class Proxy extends \OC_FileProxy { * @param string $data Data that has been read from file */ public function postFile_get_contents( $path, $data ) { - + // TODO check for existing key file and reuse it if possible to avoid problems with versioning etc. // Disable encryption proxy to prevent recursive calls \OC_FileProxy::$enabled = false; @@ -184,8 +185,8 @@ class Proxy extends \OC_FileProxy { Crypt::mode() == 'server' && Crypt::isCatfile( $data ) ) { - $view = new \OC_FilesystemView( '/' ); + // TODO use get owner to find correct location of key files for shared files $userId = \OCP\USER::getUser(); $session = new Session(); $util = new Util( $view, $userId ); -- cgit v1.2.3 From 3e3cee98c87e90ece7a4a908b6cbbc7cbc94aac7 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Mon, 11 Feb 2013 13:28:37 +0100 Subject: - moved the enrcyption of the filekey ifg file gets shared from the post shared hook to Crypt::encKeyfileToMultipleUsers() because this can be reused if files get unshared - switch from preUnshare hook to postUnshare hook because afterward we can simply get the updated list of users with access to the file and call Crypt::encKeyfileToMultipleUsers() --- apps/files_encryption/appinfo/app.php | 4 +-- apps/files_encryption/hooks/hooks.php | 47 ++++++++--------------------------- apps/files_encryption/lib/crypt.php | 42 +++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 39 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index f83109a18ea..6778e1faa3c 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -16,8 +16,8 @@ OCP\Util::connectHook( 'OC_User', 'pre_setPassword','OCA\Encryption\Hooks', 'set // Sharing-related hooks OCP\Util::connectHook( 'OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared' ); -OCP\Util::connectHook( 'OCP\Share', 'pre_unshare', 'OCA\Encryption\Hooks', 'preUnshare' ); -OCP\Util::connectHook( 'OCP\Share', 'pre_unshareAll', 'OCA\Encryption\Hooks', 'preUnshareAll' ); +OCP\Util::connectHook( 'OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare' ); +OCP\Util::connectHook( 'OCP\Share', 'post_unshareAll', 'OCA\Encryption\Hooks', 'postUnshareAll' ); // Webdav-related hooks OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfile' ); diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index b0075a3ada7..c8565964ba9 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -179,7 +179,6 @@ class Hooks { $view = new \OC_FilesystemView( '/' ); $userId = \OCP\User::getUser(); $util = new Util( $view, $userId ); - $session = new Session(); $shares = \OCP\Share::getUsersSharingFile( $params['fileTarget'], 1 ); @@ -207,55 +206,29 @@ class Hooks { } } - - $userPubKeys = Keymanager::getPublicKeys( $view, $userIds ); - - \OC_FileProxy::$enabled = false; - - // get the keyfile - $encKeyfile = Keymanager::getFileKey( $view, $userId, $params['fileTarget'] ); - - $privateKey = $session->getPrivateKey(); - - // decrypt the keyfile - $plainKeyfile = Crypt::keyDecrypt( $encKeyfile, $privateKey ); - - // re-enc keyfile to sharekeys - $shareKeys = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys ); - - // save sharekeys - if ( ! Keymanager::setShareKeys( $view, $params['fileTarget'], $shareKeys['keys'] ) ) { - - trigger_error( "SET Share keys failed" ); - - } - - // Delete existing keyfile - // Do this last to ensure file is recoverable in case of error -// Keymanager::deleteFileKey( $view, $userId, $params['fileTarget'] ); - - \OC_FileProxy::$enabled = true; - - return true; + + return Crypt::encKeyfileToMultipleUsers($shares, $params['fileTarget']); } /** * @brief */ - public static function preUnshare( $params ) { - - // Delete existing catfile + public static function postUnshare( $params ) { + $shares = \OCP\Share::getUsersSharingFile( $params['fileTarget'], 1 ); - // Generate new catfile and env keys + $userIds = array(); + foreach ( $shares as $share ) { + $userIds[] = $share['userId']; + } - // Save env keys to user folders + return Crypt::encKeyfileToMultipleUsers($userIDs, $params['fileTarget']); } /** * @brief */ - public static function preUnshareAll( $params ) { + public static function postUnshareAll( $params ) { trigger_error( "preUnshareAll" ); diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index fdee03eeaf5..6704ea6bf18 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -744,4 +744,46 @@ class Crypt { } + + /** + * @brief encrypt file key to multiple users + * @param $users list of users which should be able to access the file + * @param $fileTarget target of the file + */ + public static function encKeyfileToMultipleUsers($users, $fileTarget) { + $view = new \OC_FilesystemView( '/' ); + $userId = \OCP\User::getUser(); + $util = new Util( $view, $userId ); + $session = new Session(); + + $userPubKeys = Keymanager::getPublicKeys( $view, $users ); + + \OC_FileProxy::$enabled = false; + + // get the keyfile + $encKeyfile = Keymanager::getFileKey( $view, $userId, $fileTarget ); + + $privateKey = $session->getPrivateKey(); + + // decrypt the keyfile + $plainKeyfile = Crypt::keyDecrypt( $encKeyfile, $privateKey ); + + // re-enc keyfile to sharekeys + $shareKeys = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys ); + + // save sharekeys + if ( ! Keymanager::setShareKeys( $view, $fileTarget, $shareKeys['keys'] ) ) { + + trigger_error( "SET Share keys failed" ); + + } + + // Delete existing keyfile + // Do this last to ensure file is recoverable in case of error + // Keymanager::deleteFileKey( $view, $userId, $params['fileTarget'] ); + + \OC_FileProxy::$enabled = true; + + return true; + } } \ No newline at end of file -- cgit v1.2.3 From 8eef919a754ff3404df1065d616e66cb9b1ff437 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Tue, 12 Feb 2013 12:08:34 +0100 Subject: take group shares into account if we retrieve the list a all recipients --- apps/files_encryption/hooks/hooks.php | 35 ++++--------------- apps/files_encryption/lib/crypt.php | 30 ++++++++++++++-- lib/public/share.php | 65 ++++++++++++++++------------------- 3 files changed, 63 insertions(+), 67 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 17bcb9238ac..c14ce3e91db 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -167,44 +167,21 @@ class Hooks { * @brief */ public static function postShared( $params ) { - error_log("post shared triggered!"); + // NOTE: $params is an array with these keys: // itemSource -> int, filecache file ID // shareWith -> string, uid of user being shared to // fileTarget -> path of file being shared // uidOwner -> owner of the original file being shared + //TODO: We don't deal with shared folder yet, need to recursively update every file in the folder + $view = new \OC_FilesystemView( '/' ); $userId = \OCP\User::getUser(); $util = new Util( $view, $userId ); - $shares = \OCP\Share::getUsersSharingFile( $params['fileTarget'], 1 ); - - $userIds = array(); - - foreach ( $shares as $share ) { - - $util = new Util( $view, $share['userId'] ); - - // Check that the user is encryption capable - // TODO create encryption key when user gets created - if ( $util->ready() ) { - - // Construct array of just UIDs for Keymanager{} - $userIds[] = $share['userId']; - - } else { - - // Log warning; we can't do necessary setup here - // because we don't have the user passphrase - // TODO: Provide user feedback indicating that - // sharing failed - \OC_Log::write( 'Encryption library', 'File cannot be shared: user "'.$share['userId'].'" is not setup for encryption', \OC_Log::WARN ); - - } + $shares = \OCP\Share::getUsersSharingFile( $params['itemSource'], 1 ); - } - return Crypt::encKeyfileToMultipleUsers($shares, $params['fileTarget']); } @@ -213,11 +190,11 @@ class Hooks { * @brief */ public static function preUnshare( $params ) { - $items = \OCP\Share::getItemSharedWithBySource($params['itemType'], $params['itemSource']); - $shares = \OCP\Share::getUsersSharingFile( $item[0]['file_target'], 1 ); + $shares = \OCP\Share::getUsersSharingFile( $params['itemSource'], 1 ); $userIds = array(); foreach ( $shares as $share ) { + error_log("keek user id: " . $share['userId']); $userIds[] = $share['userId']; } diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 6704ea6bf18..a8cc2b3726d 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -752,16 +752,40 @@ class Crypt { */ public static function encKeyfileToMultipleUsers($users, $fileTarget) { $view = new \OC_FilesystemView( '/' ); - $userId = \OCP\User::getUser(); + $owner = \OCP\User::getUser(); $util = new Util( $view, $userId ); $session = new Session(); + + $userIds = array(); + + foreach ( $users as $user ) { + + $util = new Util( $view, $user ); + + // Check that the user is encryption capable + if ( $util->ready() ) { + // Construct array of just UIDs for Keymanager{} + $userIds[] = $user; + + } else { + + // Log warning; we can't do necessary setup here + // because we don't have the user passphrase + // TODO: Provide user feedback indicating that + // sharing failed + \OC_Log::write( 'Encryption library', 'File cannot be shared: user "'.$user.'" is not setup for encryption', \OC_Log::WARN ); + + } + + } + - $userPubKeys = Keymanager::getPublicKeys( $view, $users ); + $userPubKeys = Keymanager::getPublicKeys( $view, $userIds ); \OC_FileProxy::$enabled = false; // get the keyfile - $encKeyfile = Keymanager::getFileKey( $view, $userId, $fileTarget ); + $encKeyfile = Keymanager::getFileKey( $view, $owner, $fileTarget ); $privateKey = $session->getPrivateKey(); diff --git a/lib/public/share.php b/lib/public/share.php index 4170783d71e..841240692d8 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -149,62 +149,57 @@ class Share { * @note $path needs to be relative to user data dir, e.g. 'file.txt' * not '/admin/data/file.txt' */ - public static function getUsersSharingFile( $path, $includeOwner = 0 ) { - - $fPath = self::prepFileTarget( $path ); - + public static function getUsersSharingFile( $source, $includeOwner = 0 ) { + //TODO get also the recipients from folders which are shared above the current file // Fetch all shares of this file path from DB $query = \OC_DB::prepare( - 'SELECT - share_type - , share_with - , uid_owner - , permissions + 'SELECT share_with FROM `*PREFIX*share` WHERE - file_target = ?' + item_source = ? AND share_type = ? AND uid_owner = ?' ); - $result = $query->execute( array( $fPath ) ); + $result = $query->execute( array( $source, self::SHARE_TYPE_USER, \OCP\User::getUser() ) ); if ( \OC_DB::isError( $result ) ) { - - \OC_Log::write( 'OCP\Share', \OC_DB::getErrorMessage($result) . ', path=' . $fPath, \OC_Log::ERROR ); - + \OC_Log::write( 'OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR ); } $shares = array(); while( $row = $result->fetchRow() ) { + $shares[] = $row['share_with']; + } - // Set helpful array keys - $shares[] = array( - 'userId' => $row['share_with'] - , 'owner' => $row['uid_owner'] // we just set this so it can be used once, hugly hack :/ - , 'shareType' => $row['share_type'] - , 'permissions' => $row['permissions'] - ); + // We also need to take group shares into account + + $query = \OC_DB::prepare( + 'SELECT share_with + FROM + `*PREFIX*share` + WHERE + item_source = ? AND share_type = ? AND uid_owner = ?' + ); + $result = $query->execute( array( $source, self::SHARE_TYPE_GROUP, \OCP\User::getUser() ) ); + + if ( \OC_DB::isError( $result ) ) { + \OC_Log::write( 'OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR ); } + while( $row = $result->fetchRow() ) { + $usersInGroup = \OC_Group::usersInGroup($row['share_with']); + $shares = array_merge($shares, $usersInGroup); + } + if ( ! empty( $shares ) ) { - // Include owner in list of users, if requested if ( $includeOwner == 1 ) { - - // NOTE: The values are incorrect for shareType and - // permissions of the owner; we just include them for - // optional convenience - $shares[] = array( - 'userId' => $shares[0]['owner'] - , 'shareType' => 0 - , 'permissions' => 0 - ); - + $shares[] = \OCP\User::getUser(); } - - return $shares; + + return array_unique($shares); } else { @@ -235,7 +230,7 @@ class Share { public static function getItemSharedWith($itemType, $itemTarget, $format = self::FORMAT_NONE, $parameters = null, $includeCollections = false) { return self::getItems($itemType, $itemTarget, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, $parameters, 1, $includeCollections); } - + /** * @brief Get the item of item type shared with the current user by source * @param string Item type -- cgit v1.2.3 From 1e5d03da800e5ad36e7b5adbab7eef03a2add80c Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Tue, 12 Feb 2013 12:45:54 +0100 Subject: use right location of the file is the source and not the target it is shared to --- apps/files_encryption/hooks/hooks.php | 32 +++++++++++++++++++------------- apps/files_encryption/lib/crypt.php | 6 +++--- 2 files changed, 22 insertions(+), 16 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index c14ce3e91db..ebc345a47e7 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -163,6 +163,20 @@ class Hooks { } + /** + * @brief get path of a file. + * @param $fileId id of the file + * @return path of the file + */ + private static function getFilePath($fileId) { + $query = \OC_DB::prepare('SELECT `path`' + .' FROM `*PREFIX*filecache`' + .' WHERE `fileid` = ?'); + $result = $query->execute(array($fileId)); + $row = $result->fetchRow(); + return $row['path']; + } + /** * @brief */ @@ -182,7 +196,7 @@ class Hooks { $shares = \OCP\Share::getUsersSharingFile( $params['itemSource'], 1 ); - return Crypt::encKeyfileToMultipleUsers($shares, $params['fileTarget']); + return Crypt::encKeyfileToMultipleUsers($shares, self::getFilePath($params['itemSource'])); } @@ -191,25 +205,17 @@ class Hooks { */ public static function preUnshare( $params ) { $shares = \OCP\Share::getUsersSharingFile( $params['itemSource'], 1 ); - - $userIds = array(); - foreach ( $shares as $share ) { - error_log("keek user id: " . $share['userId']); - $userIds[] = $share['userId']; - } - // remove the user from the list from which the file will be unshared - unset($userIds[$params['shareWith']]); - - return Crypt::encKeyfileToMultipleUsers($userIDs, $item[0]['file_target']); + unset($shares[$params['shareWith']]); + + return Crypt::encKeyfileToMultipleUsers($shares, self::getFilePath($params['itemSource'])); } /** * @brief */ public static function preUnshareAll( $params ) { - $items = \OCP\Share::getItemSharedWithBySource($params['itemType'], $params['itemSource']); - return Crypt::encKeyfileToMultipleUsers(array($items[0]['uid_owner']), $items[0]['file_target']); + return Crypt::encKeyfileToMultipleUsers(array(\OCP\User::getUser()), self::getFilePath($params['itemSource'])); } } diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index a8cc2b3726d..cbdae323e56 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -750,7 +750,7 @@ class Crypt { * @param $users list of users which should be able to access the file * @param $fileTarget target of the file */ - public static function encKeyfileToMultipleUsers($users, $fileTarget) { + public static function encKeyfileToMultipleUsers($users, $filePath) { $view = new \OC_FilesystemView( '/' ); $owner = \OCP\User::getUser(); $util = new Util( $view, $userId ); @@ -785,7 +785,7 @@ class Crypt { \OC_FileProxy::$enabled = false; // get the keyfile - $encKeyfile = Keymanager::getFileKey( $view, $owner, $fileTarget ); + $encKeyfile = Keymanager::getFileKey( $view, $owner, $filePath ); $privateKey = $session->getPrivateKey(); @@ -796,7 +796,7 @@ class Crypt { $shareKeys = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys ); // save sharekeys - if ( ! Keymanager::setShareKeys( $view, $fileTarget, $shareKeys['keys'] ) ) { + if ( ! Keymanager::setShareKeys( $view, $filePath, $shareKeys['keys'] ) ) { trigger_error( "SET Share keys failed" ); -- cgit v1.2.3 From d1bbb30385260d77b01bc5998465ebe68ccd83d7 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Tue, 12 Feb 2013 16:48:04 +0100 Subject: also find users with access to the file if a folder above the actual file was already shared --- apps/files_encryption/hooks/hooks.php | 30 ++++------- apps/files_encryption/lib/crypt.php | 2 - apps/files_encryption/lib/util.php | 14 +++++ lib/public/share.php | 97 ++++++++++++++++++----------------- 4 files changed, 75 insertions(+), 68 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index ebc345a47e7..ffd3e4544f1 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -164,21 +164,7 @@ class Hooks { } /** - * @brief get path of a file. - * @param $fileId id of the file - * @return path of the file - */ - private static function getFilePath($fileId) { - $query = \OC_DB::prepare('SELECT `path`' - .' FROM `*PREFIX*filecache`' - .' WHERE `fileid` = ?'); - $result = $query->execute(array($fileId)); - $row = $result->fetchRow(); - return $row['path']; - } - - /** - * @brief + * @brief get all users with access to the file and encrypt the file key to each of them */ public static function postShared( $params ) { @@ -194,9 +180,11 @@ class Hooks { $userId = \OCP\User::getUser(); $util = new Util( $view, $userId ); - $shares = \OCP\Share::getUsersSharingFile( $params['itemSource'], 1 ); + $path = Util::getFilePath($params['itemSource']); + + $shares = \OCP\Share::getUsersSharingFile( $path, 1 ); - return Crypt::encKeyfileToMultipleUsers($shares, self::getFilePath($params['itemSource'])); + return Crypt::encKeyfileToMultipleUsers($shares, $path); } @@ -204,18 +192,20 @@ class Hooks { * @brief */ public static function preUnshare( $params ) { - $shares = \OCP\Share::getUsersSharingFile( $params['itemSource'], 1 ); + + $path = Util::getFilePath($params['itemSource']); + $shares = \OCP\Share::getUsersSharingFile( $path, 1 ); // remove the user from the list from which the file will be unshared unset($shares[$params['shareWith']]); - return Crypt::encKeyfileToMultipleUsers($shares, self::getFilePath($params['itemSource'])); + return Crypt::encKeyfileToMultipleUsers($shares, $path ); } /** * @brief */ public static function preUnshareAll( $params ) { - return Crypt::encKeyfileToMultipleUsers(array(\OCP\User::getUser()), self::getFilePath($params['itemSource'])); + return Crypt::encKeyfileToMultipleUsers(array(\OCP\User::getUser()), Util::getFilePath($params['itemSource'])); } } diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index cbdae323e56..ba9f0cb9a2a 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -450,9 +450,7 @@ class Crypt { * @returns encrypted file */ public static function keyEncrypt( $plainContent, $publicKey ) { - openssl_public_encrypt( $plainContent, $encryptedContent, $publicKey ); - return $encryptedContent; } diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 52bc74db27a..843727d7ab4 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -472,5 +472,19 @@ class Util { } } + + /** + * @brief get path of a file. + * @param $fileId id of the file + * @return path of the file + */ + public static function getFilePath($fileId) { + $query = \OC_DB::prepare('SELECT `path`' + .' FROM `*PREFIX*filecache`' + .' WHERE `fileid` = ?'); + $result = $query->execute(array($fileId)); + $row = $result->fetchRow(); + return substr($row['path'], 5); + } } diff --git a/lib/public/share.php b/lib/public/share.php index 841240692d8..55ff4d4738f 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -149,64 +149,69 @@ class Share { * @note $path needs to be relative to user data dir, e.g. 'file.txt' * not '/admin/data/file.txt' */ - public static function getUsersSharingFile( $source, $includeOwner = 0 ) { - //TODO get also the recipients from folders which are shared above the current file - // Fetch all shares of this file path from DB - $query = \OC_DB::prepare( - 'SELECT share_with - FROM - `*PREFIX*share` - WHERE - item_source = ? AND share_type = ? AND uid_owner = ?' - ); - - $result = $query->execute( array( $source, self::SHARE_TYPE_USER, \OCP\User::getUser() ) ); - - if ( \OC_DB::isError( $result ) ) { - \OC_Log::write( 'OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR ); - } - + public static function getUsersSharingFile( $path, $includeOwner = 0 ) { + + $user = \OCP\User::getUser(); + $path_parts = explode(DIRECTORY_SEPARATOR, trim($path, DIRECTORY_SEPARATOR)); + $path = ''; $shares = array(); - while( $row = $result->fetchRow() ) { - $shares[] = $row['share_with']; - } - - // We also need to take group shares into account - - $query = \OC_DB::prepare( - 'SELECT share_with - FROM - `*PREFIX*share` - WHERE - item_source = ? AND share_type = ? AND uid_owner = ?' - ); + foreach ($path_parts as $p) { + $path .= '/'.$p; + $meta = \OC\Files\Filesystem::getFileInfo(\OC_Filesystem::normalizePath($path)); + $source = $meta['fileid']; - $result = $query->execute( array( $source, self::SHARE_TYPE_GROUP, \OCP\User::getUser() ) ); - - if ( \OC_DB::isError( $result ) ) { - \OC_Log::write( 'OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR ); - } - - while( $row = $result->fetchRow() ) { - $usersInGroup = \OC_Group::usersInGroup($row['share_with']); - $shares = array_merge($shares, $usersInGroup); + // Fetch all shares of this file path from DB + $query = \OC_DB::prepare( + 'SELECT share_with + FROM + `*PREFIX*share` + WHERE + item_source = ? AND share_type = ? AND uid_owner = ?' + ); + + $result = $query->execute( array( $source, self::SHARE_TYPE_USER, $user ) ); + + if ( \OC_DB::isError( $result ) ) { + \OC_Log::write( 'OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR ); + } + + while( $row = $result->fetchRow() ) { + $shares[] = $row['share_with']; + } + + // We also need to take group shares into account + + $query = \OC_DB::prepare( + 'SELECT share_with + FROM + `*PREFIX*share` + WHERE + item_source = ? AND share_type = ? AND uid_owner = ?' + ); + + $result = $query->execute( array( $source, self::SHARE_TYPE_GROUP, $user ) ); + + if ( \OC_DB::isError( $result ) ) { + \OC_Log::write( 'OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR ); + } + + while( $row = $result->fetchRow() ) { + $usersInGroup = \OC_Group::usersInGroup($row['share_with']); + $shares = array_merge($shares, $usersInGroup); + } } - + if ( ! empty( $shares ) ) { // Include owner in list of users, if requested if ( $includeOwner == 1 ) { - $shares[] = \OCP\User::getUser(); + $shares[] = $user; } - return array_unique($shares); - } else { - return false; - } - + } /** -- cgit v1.2.3 From a692264fa416fec44d774bd955a06a65c7c0d158 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Tue, 12 Feb 2013 17:00:33 +0100 Subject: add option to keep duplicates in the list of users with access to a file, e.g. for the unshare operation we need to know if access was granted more than once, for example as group share and as individual share --- apps/files_encryption/hooks/hooks.php | 6 +++--- apps/files_encryption/lib/proxy.php | 11 ++--------- lib/public/share.php | 17 +++++++++++------ 3 files changed, 16 insertions(+), 18 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index ffd3e4544f1..5e06948aa50 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -182,7 +182,7 @@ class Hooks { $path = Util::getFilePath($params['itemSource']); - $shares = \OCP\Share::getUsersSharingFile( $path, 1 ); + $shares = \OCP\Share::getUsersSharingFile( $path, true ); return Crypt::encKeyfileToMultipleUsers($shares, $path); @@ -194,11 +194,11 @@ class Hooks { public static function preUnshare( $params ) { $path = Util::getFilePath($params['itemSource']); - $shares = \OCP\Share::getUsersSharingFile( $path, 1 ); + $shares = \OCP\Share::getUsersSharingFile( $path, true, false ); // remove the user from the list from which the file will be unshared unset($shares[$params['shareWith']]); - return Crypt::encKeyfileToMultipleUsers($shares, $path ); + return Crypt::encKeyfileToMultipleUsers(array_unique($shares), $path ); } /** diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 40ac411539b..3e4178e8a87 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -118,15 +118,8 @@ class Proxy extends \OC_FileProxy { // $fileOwner = \OC\Files\Filesystem::getOwner( $path ); // List everyone sharing the file - $shares = \OCP\Share::getUsersSharingFile( $filePath, 1 ); - - $userIds = array(); - - foreach ( $shares as $share ) { - - $userIds[] = $share['userId']; - - } + //TODO check, is this path always the path to the source file? + $userIds = \OCP\Share::getUsersSharingFile( $filePath, true ); $publicKeys = Keymanager::getPublicKeys( $rootView, $userIds ); diff --git a/lib/public/share.php b/lib/public/share.php index 55ff4d4738f..68f5e93baa7 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -145,11 +145,14 @@ class Share { /** * @brief Find which users can access a shared item - * @return bool / array + * @param $path to the file + * @param include owner to the list of users with access to the file + * @param remove duplicates in the result + * @return array * @note $path needs to be relative to user data dir, e.g. 'file.txt' * not '/admin/data/file.txt' */ - public static function getUsersSharingFile( $path, $includeOwner = 0 ) { + public static function getUsersSharingFile( $path, $includeOwner = false, $removeDuplicates = true ) { $user = \OCP\User::getUser(); $path_parts = explode(DIRECTORY_SEPARATOR, trim($path, DIRECTORY_SEPARATOR)); @@ -204,14 +207,16 @@ class Share { if ( ! empty( $shares ) ) { // Include owner in list of users, if requested - if ( $includeOwner == 1 ) { + if ( $includeOwner ) { $shares[] = $user; } + } + + if ( $removeDuplicates ) return array_unique($shares); - } else { - return false; + else { + return $shares; } - } /** -- cgit v1.2.3 From 4952dfe95657ba52f1b39f958100659539831ba8 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Wed, 13 Feb 2013 14:56:39 +0100 Subject: add post_unshare hook, also add public link shares to the list of user with access to a file --- apps/files_encryption/appinfo/app.php | 2 +- apps/files_encryption/hooks/hooks.php | 9 ++++----- apps/files_encryption/lib/crypt.php | 4 +++- lib/public/share.php | 35 ++++++++++++++++++++++++++++------- 4 files changed, 36 insertions(+), 14 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index f83109a18ea..932e8855d07 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -16,7 +16,7 @@ OCP\Util::connectHook( 'OC_User', 'pre_setPassword','OCA\Encryption\Hooks', 'set // Sharing-related hooks OCP\Util::connectHook( 'OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared' ); -OCP\Util::connectHook( 'OCP\Share', 'pre_unshare', 'OCA\Encryption\Hooks', 'preUnshare' ); +OCP\Util::connectHook( 'OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare' ); OCP\Util::connectHook( 'OCP\Share', 'pre_unshareAll', 'OCA\Encryption\Hooks', 'preUnshareAll' ); // Webdav-related hooks diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 5e06948aa50..ae05ba78012 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -176,6 +176,8 @@ class Hooks { //TODO: We don't deal with shared folder yet, need to recursively update every file in the folder + if ($params['shareType'] == \OCP\Share::SHARE_TYPE_LINK) + $view = new \OC_FilesystemView( '/' ); $userId = \OCP\User::getUser(); $util = new Util( $view, $userId ); @@ -191,12 +193,9 @@ class Hooks { /** * @brief */ - public static function preUnshare( $params ) { - + public static function postUnshare( $params ) { $path = Util::getFilePath($params['itemSource']); - $shares = \OCP\Share::getUsersSharingFile( $path, true, false ); - // remove the user from the list from which the file will be unshared - unset($shares[$params['shareWith']]); + $shares = \OCP\Share::getUsersSharingFile( $path, true ); return Crypt::encKeyfileToMultipleUsers(array_unique($shares), $path ); } diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index ba9f0cb9a2a..0f465d7d95a 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -450,7 +450,9 @@ class Crypt { * @returns encrypted file */ public static function keyEncrypt( $plainContent, $publicKey ) { - openssl_public_encrypt( $plainContent, $encryptedContent, $publicKey ); + + if (openssl_public_encrypt( $plainContent, $encryptedContent, $publicKey )) error_log("feinifeine"); else error_log("ups"); + return $encryptedContent; } diff --git a/lib/public/share.php b/lib/public/share.php index 68f5e93baa7..f691ae9b39f 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -147,7 +147,6 @@ class Share { * @brief Find which users can access a shared item * @param $path to the file * @param include owner to the list of users with access to the file - * @param remove duplicates in the result * @return array * @note $path needs to be relative to user data dir, e.g. 'file.txt' * not '/admin/data/file.txt' @@ -203,6 +202,25 @@ class Share { $usersInGroup = \OC_Group::usersInGroup($row['share_with']); $shares = array_merge($shares, $usersInGroup); } + + //check for public link shares + $query = \OC_DB::prepare( + 'SELECT share_with + FROM + `*PREFIX*share` + WHERE + item_source = ? AND share_type = ? AND uid_owner = ?' + ); + + $result = $query->execute( array( $source, self::SHARE_TYPE_LINK, $user ) ); + + if ( \OC_DB::isError( $result ) ) { + \OC_Log::write( 'OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR ); + } + + if ($result->fetchRow()) { + $shares[] = self::SHARE_TYPE_LINK; + } } if ( ! empty( $shares ) ) { @@ -212,11 +230,8 @@ class Share { } } - if ( $removeDuplicates ) - return array_unique($shares); - else { - return $shares; - } + return array_unique($shares); + } /** @@ -475,8 +490,14 @@ class Share { 'itemSource' => $itemSource, 'shareType' => $shareType, 'shareWith' => $shareWith, - )); + )); self::delete($item['id']); + \OC_Hook::emit('OCP\Share', 'post_unshare', array( + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'shareType' => $shareType, + 'shareWith' => $shareWith, + )); return true; } return false; -- cgit v1.2.3 From 9356f9a6bf6e9bd048e31e787d5fcb621de8eebc Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Wed, 13 Feb 2013 17:23:27 +0100 Subject: add post_unshareALll hook, update recursively all keyfiles if a folder was shared/unshared --- apps/files_encryption/appinfo/app.php | 2 +- apps/files_encryption/hooks/hooks.php | 15 ++++++--------- apps/files_encryption/lib/crypt.php | 36 ++++++++++++++++++++++++++++++++++- lib/public/share.php | 5 +++++ 4 files changed, 47 insertions(+), 11 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index 932e8855d07..6778e1faa3c 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -17,7 +17,7 @@ OCP\Util::connectHook( 'OC_User', 'pre_setPassword','OCA\Encryption\Hooks', 'set // Sharing-related hooks OCP\Util::connectHook( 'OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared' ); OCP\Util::connectHook( 'OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare' ); -OCP\Util::connectHook( 'OCP\Share', 'pre_unshareAll', 'OCA\Encryption\Hooks', 'preUnshareAll' ); +OCP\Util::connectHook( 'OCP\Share', 'post_unshareAll', 'OCA\Encryption\Hooks', 'postUnshareAll' ); // Webdav-related hooks OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfile' ); diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index ae05ba78012..34ed11c7e24 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -176,17 +176,13 @@ class Hooks { //TODO: We don't deal with shared folder yet, need to recursively update every file in the folder - if ($params['shareType'] == \OCP\Share::SHARE_TYPE_LINK) - $view = new \OC_FilesystemView( '/' ); $userId = \OCP\User::getUser(); $util = new Util( $view, $userId ); $path = Util::getFilePath($params['itemSource']); - $shares = \OCP\Share::getUsersSharingFile( $path, true ); - - return Crypt::encKeyfileToMultipleUsers($shares, $path); + return Crypt::updateKeyfile($path); } @@ -195,16 +191,17 @@ class Hooks { */ public static function postUnshare( $params ) { $path = Util::getFilePath($params['itemSource']); - $shares = \OCP\Share::getUsersSharingFile( $path, true ); - return Crypt::encKeyfileToMultipleUsers(array_unique($shares), $path ); + return Crypt::updateKeyfile($path); } /** * @brief */ - public static function preUnshareAll( $params ) { - return Crypt::encKeyfileToMultipleUsers(array(\OCP\User::getUser()), Util::getFilePath($params['itemSource'])); + public static function postUnshareAll( $params ) { + $path = Util::getFilePath($params['itemSource']); + + return Crypt::updateKeyfile($path); } } diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 0f465d7d95a..18e9535bf35 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -750,7 +750,7 @@ class Crypt { * @param $users list of users which should be able to access the file * @param $fileTarget target of the file */ - public static function encKeyfileToMultipleUsers($users, $filePath) { + private static function encKeyfileToMultipleUsers($users, $filePath) { $view = new \OC_FilesystemView( '/' ); $owner = \OCP\User::getUser(); $util = new Util( $view, $userId ); @@ -810,4 +810,38 @@ class Crypt { return true; } + + /** + * @brief update keyfile encryption for given path and all sub folders/files + * @param path which needs to be updated + * @return bool success + */ + public static function updateKeyfile($path) { + + $filesView = \OCP\Files::getStorage('files'); + + $result = true; + + if ( $filesView->is_dir($path) ) { + $content = $filesView->getDirectoryContent($path); + foreach ( $content as $c) { + $path = substr($c['path'], 5); + if ( $filesView->is_dir($path) ) { + error_log("dive into $path"); + $result &= self::updateKeyfile($path); + } else { + error_log("encKeyFileToMultipleUsers $path"); + $shares = \OCP\Share::getUsersSharingFile( $path, true ); + $result &= self::encKeyfileToMultipleUsers($shares, $path); + } + } + } else { + error_log("encKeyFileToMultipleUsers single file: " . $path); + $shares = \OCP\Share::getUsersSharingFile( $path, true ); + $result = self::encKeyfileToMultipleUsers($shares, $path); + } + + return $result; + + } } \ No newline at end of file diff --git a/lib/public/share.php b/lib/public/share.php index f691ae9b39f..d1297c6e59e 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -520,6 +520,11 @@ class Share { foreach ($shares as $share) { self::delete($share['id']); } + \OC_Hook::emit('OCP\Share', 'post_unshareAll', array( + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'shares' => $shares + )); return true; } return false; -- cgit v1.2.3 From 5005195db005fd0d7c8fdf1a73e12c4a4619acb9 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Wed, 13 Feb 2013 17:57:45 +0100 Subject: create keypair for ownCloud with empty passphrase, will be used for public link shares --- apps/files_encryption/lib/crypt.php | 5 +---- apps/files_encryption/lib/session.php | 28 ++++++++++++++++++++++++++++ lib/public/share.php | 2 +- 3 files changed, 30 insertions(+), 5 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 18e9535bf35..2e5912a8683 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -763,7 +763,7 @@ class Crypt { $util = new Util( $view, $user ); // Check that the user is encryption capable - if ( $util->ready() ) { + if ( $util->ready() && $user == 'ownCloud' ) { // Construct array of just UIDs for Keymanager{} $userIds[] = $user; @@ -827,16 +827,13 @@ class Crypt { foreach ( $content as $c) { $path = substr($c['path'], 5); if ( $filesView->is_dir($path) ) { - error_log("dive into $path"); $result &= self::updateKeyfile($path); } else { - error_log("encKeyFileToMultipleUsers $path"); $shares = \OCP\Share::getUsersSharingFile( $path, true ); $result &= self::encKeyfileToMultipleUsers($shares, $path); } } } else { - error_log("encKeyFileToMultipleUsers single file: " . $path); $shares = \OCP\Share::getUsersSharingFile( $path, true ); $result = self::encKeyfileToMultipleUsers($shares, $path); } diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index 769a40b359f..ebf7edcd715 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -27,6 +27,34 @@ namespace OCA\Encryption; */ class Session { + + /** + * @brief if session is started, check if ownCloud key pair is set up, if not create it + * + * The ownCloud key pair is used to allow public link sharing even if encryption is enabled + */ + public function __construct() { + $view = new \OC\Files\View('/'); + if (!$view->is_dir('owncloud_private_key')) { + $view->mkdir('owncloud_private_key'); + } + + if (!$view->file_exists("/public-keys/owncloud.public.key") || !$view->file_exists("/owncloud_private_key/owncloud.private.key") ) { + + $keypair = Crypt::createKeypair(); + + \OC_FileProxy::$enabled = false; + // Save public key + $view->file_put_contents( '/public-keys/owncloud.public.key', $keypair['publicKey'] ); + // Encrypt private key empthy passphrase + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], '' ); + // Save private key + error_log("encrypted private key: " . $encryptedPrivateKey ); + $view->file_put_contents( '/owncloud_private_key/owncloud.private.key', $encryptedPrivateKey ); + + \OC_FileProxy::$enabled = true; + } + } /** * @brief Sets user private key to session diff --git a/lib/public/share.php b/lib/public/share.php index d1297c6e59e..720337c3c38 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -219,7 +219,7 @@ class Share { } if ($result->fetchRow()) { - $shares[] = self::SHARE_TYPE_LINK; + $shares[] = "ownCloud"; } } -- cgit v1.2.3 From 8c35bbcba75590d5f66ecf08a4dd07db3fd23732 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Thu, 14 Feb 2013 16:33:57 +0100 Subject: remove debug output, fix typo in file names --- apps/files_encryption/lib/session.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index ebf7edcd715..171a6900f0f 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -34,23 +34,23 @@ class Session { * The ownCloud key pair is used to allow public link sharing even if encryption is enabled */ public function __construct() { + $view = new \OC\Files\View('/'); if (!$view->is_dir('owncloud_private_key')) { $view->mkdir('owncloud_private_key'); } if (!$view->file_exists("/public-keys/owncloud.public.key") || !$view->file_exists("/owncloud_private_key/owncloud.private.key") ) { - + $keypair = Crypt::createKeypair(); \OC_FileProxy::$enabled = false; // Save public key - $view->file_put_contents( '/public-keys/owncloud.public.key', $keypair['publicKey'] ); + $view->file_put_contents( '/public-keys/ownCloud.public.key', $keypair['publicKey'] ); // Encrypt private key empthy passphrase $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], '' ); // Save private key - error_log("encrypted private key: " . $encryptedPrivateKey ); - $view->file_put_contents( '/owncloud_private_key/owncloud.private.key', $encryptedPrivateKey ); + $view->file_put_contents( '/owncloud_private_key/ownCloud.private.key', $encryptedPrivateKey ); \OC_FileProxy::$enabled = true; } -- cgit v1.2.3 From fd629983fa61ad7fdc1c6696e6b2fa1739ae6f28 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Tue, 19 Feb 2013 17:10:32 +0100 Subject: remove debug output --- apps/files_encryption/lib/crypt.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 2e5912a8683..a1684fc95f6 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -451,7 +451,7 @@ class Crypt { */ public static function keyEncrypt( $plainContent, $publicKey ) { - if (openssl_public_encrypt( $plainContent, $encryptedContent, $publicKey )) error_log("feinifeine"); else error_log("ups"); + openssl_public_encrypt( $plainContent, $encryptedContent, $publicKey ); return $encryptedContent; -- cgit v1.2.3 From 14ae373dfe86b34b3e027306b5f857a3f38ff418 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Tue, 19 Feb 2013 17:41:38 +0000 Subject: Fixed wrong array key reference --- apps/files_encryption/lib/crypt.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index a1684fc95f6..49b75c17f6a 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -371,7 +371,7 @@ class Crypt { * @brief Create asymmetrically encrypted keyfile content using a generated key * @param string $plainContent content to be encrypted * @param array $publicKeys array keys must be the userId of corresponding user - * @returns array keys: keys (array, key = userId), encrypted + * @returns array keys: keys (array, key = userId), data * @note symmetricDecryptFileContent() can decrypt files created using this method */ public static function multiKeyEncrypt( $plainContent, array $publicKeys ) { -- cgit v1.2.3 From 1b880f2f96df514c68a17e90141cff9620c2ddb5 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Tue, 19 Feb 2013 19:16:50 +0000 Subject: Moved dependencies out of Crypt methods (encKeyfileToMultipleUsers)(DI) Fixed bug preventing sharing with users other than 'ownCloud' Added comments Moved functionality into filterShareReadyUsers() Other changes --- apps/files_encryption/appinfo/app.php | 2 +- apps/files_encryption/hooks/hooks.php | 23 ++++++--- apps/files_encryption/lib/crypt.php | 97 ++++++++++++++++++----------------- apps/files_encryption/lib/util.php | 41 +++++++++++++++ 4 files changed, 109 insertions(+), 54 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index 6778e1faa3c..742e4add8f1 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -20,7 +20,7 @@ OCP\Util::connectHook( 'OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'pos OCP\Util::connectHook( 'OCP\Share', 'post_unshareAll', 'OCA\Encryption\Hooks', 'postUnshareAll' ); // Webdav-related hooks -OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfile' ); +OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfileFromClient' ); stream_wrapper_register( 'crypt', 'OCA\Encryption\Stream' ); diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 50207246576..1ebfdb1ae0a 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -139,7 +139,7 @@ class Hooks { /** * @brief update the encryption key of the file uploaded by the client */ - public static function updateKeyfile( $params ) { + public static function updateKeyfileFromClient( $params ) { if ( Crypt::mode() == 'client' ) { @@ -175,12 +175,13 @@ class Hooks { // uidOwner -> owner of the original file being shared $view = new \OC_FilesystemView( '/' ); + $session = new Session(); $userId = \OCP\User::getUser(); $util = new Util( $view, $userId ); - $path = Util::getFilePath($params['itemSource']); + $path = Util::getFilePath( $params['itemSource'] ); - return Crypt::updateKeyfile($path); + return Crypt::updateKeyfile( $view, $session, $path ); } @@ -188,18 +189,26 @@ class Hooks { * @brief */ public static function postUnshare( $params ) { - $path = Util::getFilePath($params['itemSource']); + + $view = new \OC_FilesystemView( '/' ); + $session = new Session(); + $path = Util::getFilePath( $params['itemSource'] ); + + return Crypt::updateKeyfile( $view, $session, $path ); - return Crypt::updateKeyfile($path); } /** * @brief */ public static function postUnshareAll( $params ) { - $path = Util::getFilePath($params['itemSource']); + + $view = new \OC_FilesystemView( '/' ); + $session = new Session(); + $path = Util::getFilePath( $params['itemSource'] ); + + return Crypt::updateKeyfile( $view, $session, $path ); - return Crypt::updateKeyfile($path); } } diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 49b75c17f6a..1b0167834e1 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -746,52 +746,44 @@ class Crypt { /** - * @brief encrypt file key to multiple users - * @param $users list of users which should be able to access the file - * @param $fileTarget target of the file + * @brief Encrypt keyfile to multiple users + * @param array $users list of users which should be able to access the file + * @param string $filePath path of the file to be shared */ - private static function encKeyfileToMultipleUsers($users, $filePath) { - $view = new \OC_FilesystemView( '/' ); - $owner = \OCP\User::getUser(); - $util = new Util( $view, $userId ); - $session = new Session(); + private static function encKeyfileToMultipleUsers( \OC_FilesystemView $view, Util $util, Session $session, $userId, array $users, $filePath ) { + + // Make sure users are capable of sharing + $filteredUids = $util->filterShareReadyUsers( $users ); - $userIds = array(); + // Get public keys for each user, ready for generating sharekeys + $userPubKeys = Keymanager::getPublicKeys( $view, $filteredUids ); // TODO: check this includes the owner's public key + + \OC_FileProxy::$enabled = false; + + // Get the current users's private key for decrypting existing keyfile + $privateKey = $session->getPrivateKey(); - foreach ( $users as $user ) { + // We need to get a decrypted key for the file + // Determine how to decrypt the keyfile by checking if current user is owner + if ( $userId == \OC\Files\Filesystem::getOwner( $filePath ) ) { - $util = new Util( $view, $user ); - - // Check that the user is encryption capable - if ( $util->ready() && $user == 'ownCloud' ) { - // Construct array of just UIDs for Keymanager{} - $userIds[] = $user; - - } else { - - // Log warning; we can't do necessary setup here - // because we don't have the user passphrase - // TODO: Provide user feedback indicating that - // sharing failed - \OC_Log::write( 'Encryption library', 'File cannot be shared: user "'.$user.'" is not setup for encryption', \OC_Log::WARN ); + // If current user is owner, decrypt without using sharekey - } + } else { + + // Current user is resharing a file they don't own + // Decrypt keyfile using sharekey } - - $userPubKeys = Keymanager::getPublicKeys( $view, $userIds ); - - \OC_FileProxy::$enabled = false; - - // get the keyfile + // get the existing keyfile $encKeyfile = Keymanager::getFileKey( $view, $owner, $filePath ); - $privateKey = $session->getPrivateKey(); - - // decrypt the keyfile + // decrypt the existing keyfile $plainKeyfile = Crypt::keyDecrypt( $encKeyfile, $privateKey ); - + + trigger_error("PUBKEYS = ". var_export($userPubKeys, 1)); + // re-enc keyfile to sharekeys $shareKeys = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys ); @@ -816,29 +808,42 @@ class Crypt { * @param path which needs to be updated * @return bool success */ - public static function updateKeyfile($path) { + public static function updateKeyfile( \OC_FilesystemView $view, Util $util, Session $session, $path ) { - $filesView = \OCP\Files::getStorage('files'); + // Make path include 'files' dir for OC_FSV operations + $fPath = 'files' . $path; $result = true; - if ( $filesView->is_dir($path) ) { - $content = $filesView->getDirectoryContent($path); - foreach ( $content as $c) { + if ( ! $view->is_dir( $fPath ) ) { + + $shares = \OCP\Share::getUsersSharingFile( $path, true ); + $result = self::encKeyfileToMultipleUsers( $view, $util, $session, $shares, $path ); + + } else { + + $content = $view->getDirectoryContent( $fPath ); + + foreach ( $content as $c ) { + $path = substr($c['path'], 5); - if ( $filesView->is_dir($path) ) { - $result &= self::updateKeyfile($path); + + if ( $view->is_dir( $fPath ) ) { + + $result &= self::updateKeyfile( $path ); + } else { + $shares = \OCP\Share::getUsersSharingFile( $path, true ); - $result &= self::encKeyfileToMultipleUsers($shares, $path); + $result &= self::encKeyfileToMultipleUsers( $view, $util, $session, $shares, $path ); + } } - } else { - $shares = \OCP\Share::getUsersSharingFile( $path, true ); - $result = self::encKeyfileToMultipleUsers($shares, $path); + } return $result; } + } \ No newline at end of file diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 843727d7ab4..8ca51c95d77 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -486,5 +486,46 @@ class Util { $row = $result->fetchRow(); return substr($row['path'], 5); } + + /** + * @brief Filter an array of UIDs to return only ones ready for sharing + * @param array $unfilteredUsers users to be checked for sharing readiness + * @return array $userIds filtered users + */ + public function filterShareReadyUsers( $unfilteredUsers ) { + + // This array will collect the filtered IDs + $userIds = array(); + + // Loop through users and create array of UIDs that need new keyfiles + foreach ( $unfilteredUsers as $user ) { + + $util = new Util( $this->view, $user ); + + // Check that the user is encryption capable, or is the + // public system user 'ownCloud' (for public shares) + if ( + $util->ready() + or $user == 'ownCloud' + ) { + + // Construct array of just UIDs for Keymanager{} + $userIds[] = $user; + + } else { + + // Log warning; we can't do necessary setup here + // because we don't have the user passphrase + // TODO: Provide user feedback indicating that + // sharing failed + \OC_Log::write( 'Encryption library', '"'.$user.'" is not setup for encryption', \OC_Log::WARN ); + + } + + } + + return $userIds; + + } } -- cgit v1.2.3 From 2d267501a10642e5c601ca87748b692ca58e4094 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Wed, 20 Feb 2013 19:18:00 +0000 Subject: Development snapshot Added comments Added methods --- apps/files_encryption/hooks/hooks.php | 54 +++++++--- apps/files_encryption/lib/crypt.php | 102 ------------------- apps/files_encryption/lib/keymanager.php | 4 +- apps/files_encryption/lib/proxy.php | 43 ++++++-- apps/files_encryption/lib/util.php | 169 +++++++++++++++++++++++++++++-- apps/files_encryption/test/util.php | 4 +- 6 files changed, 240 insertions(+), 136 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 1ebfdb1ae0a..6d982b2c3b0 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -178,10 +178,34 @@ class Hooks { $session = new Session(); $userId = \OCP\User::getUser(); $util = new Util( $view, $userId ); + $path = $util->fileIdToPath( $params['itemSource'] ); - $path = Util::getFilePath( $params['itemSource'] ); - - return Crypt::updateKeyfile( $view, $session, $path ); + $usersSharing = \OCP\Share::getUsersSharingFile( $path, true ); + + $allPaths = $util->getPaths( $path ); + + $failed = array(); + + foreach ( $allPaths as $path ) { + + if ( ! $util->setSharedFileKeyfiles( $session, $usersSharing, $path ) ) { + + $failed[] = $path; + + } + + } + + // If no attempts to set keyfiles failed + if ( empty( $failed ) ) { + + return true; + + } else { + + return false; + + } } @@ -190,11 +214,13 @@ class Hooks { */ public static function postUnshare( $params ) { - $view = new \OC_FilesystemView( '/' ); - $session = new Session(); - $path = Util::getFilePath( $params['itemSource'] ); - - return Crypt::updateKeyfile( $view, $session, $path ); +// $view = new \OC_FilesystemView( '/' ); +// $session = new Session(); +// $userId = \OCP\User::getUser(); +// $util = new Util( $view, $userId ); +// $path = $util->fileIdToPath( $params['itemSource'] ); +// +// return Crypt::updateKeyfile( $view, $util, $session, $userId, $path ); } @@ -203,11 +229,13 @@ class Hooks { */ public static function postUnshareAll( $params ) { - $view = new \OC_FilesystemView( '/' ); - $session = new Session(); - $path = Util::getFilePath( $params['itemSource'] ); - - return Crypt::updateKeyfile( $view, $session, $path ); +// $view = new \OC_FilesystemView( '/' ); +// $session = new Session(); +// $userId = \OCP\User::getUser(); +// $util = new Util( $view, $userId ); +// $path = $util->fileIdToPath( $params['itemSource'] ); +// +// return Crypt::updateKeyfile( $view, $util, $session, $userId, $path ); } diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 1b0167834e1..a677de950ae 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -744,106 +744,4 @@ class Crypt { } - - /** - * @brief Encrypt keyfile to multiple users - * @param array $users list of users which should be able to access the file - * @param string $filePath path of the file to be shared - */ - private static function encKeyfileToMultipleUsers( \OC_FilesystemView $view, Util $util, Session $session, $userId, array $users, $filePath ) { - - // Make sure users are capable of sharing - $filteredUids = $util->filterShareReadyUsers( $users ); - - // Get public keys for each user, ready for generating sharekeys - $userPubKeys = Keymanager::getPublicKeys( $view, $filteredUids ); // TODO: check this includes the owner's public key - - \OC_FileProxy::$enabled = false; - - // Get the current users's private key for decrypting existing keyfile - $privateKey = $session->getPrivateKey(); - - // We need to get a decrypted key for the file - // Determine how to decrypt the keyfile by checking if current user is owner - if ( $userId == \OC\Files\Filesystem::getOwner( $filePath ) ) { - - // If current user is owner, decrypt without using sharekey - - } else { - - // Current user is resharing a file they don't own - // Decrypt keyfile using sharekey - - } - - // get the existing keyfile - $encKeyfile = Keymanager::getFileKey( $view, $owner, $filePath ); - - // decrypt the existing keyfile - $plainKeyfile = Crypt::keyDecrypt( $encKeyfile, $privateKey ); - - trigger_error("PUBKEYS = ". var_export($userPubKeys, 1)); - - // re-enc keyfile to sharekeys - $shareKeys = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys ); - - // save sharekeys - if ( ! Keymanager::setShareKeys( $view, $filePath, $shareKeys['keys'] ) ) { - - trigger_error( "SET Share keys failed" ); - - } - - // Delete existing keyfile - // Do this last to ensure file is recoverable in case of error - // Keymanager::deleteFileKey( $view, $userId, $params['fileTarget'] ); - - \OC_FileProxy::$enabled = true; - - return true; - } - - /** - * @brief update keyfile encryption for given path and all sub folders/files - * @param path which needs to be updated - * @return bool success - */ - public static function updateKeyfile( \OC_FilesystemView $view, Util $util, Session $session, $path ) { - - // Make path include 'files' dir for OC_FSV operations - $fPath = 'files' . $path; - - $result = true; - - if ( ! $view->is_dir( $fPath ) ) { - - $shares = \OCP\Share::getUsersSharingFile( $path, true ); - $result = self::encKeyfileToMultipleUsers( $view, $util, $session, $shares, $path ); - - } else { - - $content = $view->getDirectoryContent( $fPath ); - - foreach ( $content as $c ) { - - $path = substr($c['path'], 5); - - if ( $view->is_dir( $fPath ) ) { - - $result &= self::updateKeyfile( $path ); - - } else { - - $shares = \OCP\Share::getUsersSharingFile( $path, true ); - $result &= self::encKeyfileToMultipleUsers( $view, $util, $session, $shares, $path ); - - } - } - - } - - return $result; - - } - } \ No newline at end of file diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 5f9eea1a0bc..ec1fdd1fd55 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -305,8 +305,8 @@ class Keymanager { /** * @brief retrieve shareKey for an encrypted file * @param \OC_FilesystemView $view - * @param $userId - * @param $filePath + * @param string $userId + * @param string $filePath * @internal param \OCA\Encryption\file $string name * @return string file key or false * @note The sharekey returned is encrypted. Decryption diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 3e4178e8a87..9e6a11d9d48 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -169,6 +169,24 @@ class Proxy extends \OC_FileProxy { * @param string $data Data that has been read from file */ public function postFile_get_contents( $path, $data ) { + + // FIXME: $path for shared files is just /uid/files/Shared/filepath + + $userId = \OCP\USER::getUser(); + $view = new \OC_FilesystemView( '/' ); + $util = new Util( $view, $userId ); + + if ( $util->isSharedPath( $path ) ) { + + $relPath = $util->stripSharedFilePath( $path ); + + } else { + + $relPath = $util->stripUserFilesPath( $path ); + + } + + // TODO check for existing key file and reuse it if possible to avoid problems with versioning etc. // Disable encryption proxy to prevent recursive calls \OC_FileProxy::$enabled = false; @@ -178,27 +196,34 @@ class Proxy extends \OC_FileProxy { Crypt::mode() == 'server' && Crypt::isCatfile( $data ) ) { - $view = new \OC_FilesystemView( '/' ); + // TODO use get owner to find correct location of key files for shared files - $userId = \OCP\USER::getUser(); $session = new Session(); - $util = new Util( $view, $userId ); - $filePath = $util->stripUserFilesPath( $path ); $privateKey = $session->getPrivateKey( $userId ); + // Get the file owner so we can retrieve its keyfile + $fileOwner = \OC\Files\Filesystem::getOwner( $relPath ); //NOTE: This might be false! make sure the path passed to it is right + $fileOwner = 'admin'; // FIXME: Manually set the correct UID for now + // Get the encrypted keyfile - $encKeyfile = Keymanager::getFileKey( $view, $userId, $filePath ); + $encKeyfile = Keymanager::getFileKey( $view, $fileOwner, $relPath ); - // Check if key is shared or not - if ( \OCP\Share::isSharedFile( $filePath ) ) { + trigger_error("\$encKeyfile = ". var_export($encKeyfile, 1)); + + // Attempt to fetch the user's shareKey + $shareKey = Keymanager::getShareKey( $view, $userId, $relPath ); + + trigger_error("\$shareKey = ".var_export($shareKey, 1)); - // If key is shared, fetch the user's shareKey - $shareKey = Keymanager::getShareKey( $view, $userId, $filePath ); + // Check if key is shared or not + if ( $shareKey ) { \OC_FileProxy::$enabled = false; // Decrypt keyfile with shareKey $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); + + trigger_error("PROXY plainkeyfile = ". var_export($plainKeyfile, 1)); } else { diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 8ca51c95d77..ac098cd877d 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -224,7 +224,7 @@ class Util { * @note $directory needs to be a path relative to OC data dir. e.g. * /admin/files NOT /backup OR /home/www/oc/data/admin/files */ - public function findFiles( $directory ) { + public function findEncFiles( $directory ) { // Disable proxy - we don't want files to be decrypted before // we handle them @@ -251,7 +251,7 @@ class Util { // its contents if ( $this->view->is_dir( $filePath ) ) { - $this->findFiles( $filePath ); + $this->findEncFiles( $filePath ); // If the path is a file, determine // its encryption status @@ -348,6 +348,38 @@ class Util { } + /** + * @brief Format a shared path to be relative to the /user/files/ directory + * @note Expects a path like /uid/files/Shared/filepath + */ + public function stripSharedFilePath( $path ) { + + $trimmed = ltrim( $path, '/' ); + $split = explode( '/', $trimmed ); + $sliced = array_slice( $split, 3 ); + $relPath = implode( '/', $sliced ); + + return $relPath; + + } + + public function isSharedPath( $path ) { + + $trimmed = ltrim( $path, '/' ); + $split = explode( '/', $trimmed ); + + if ( $split[2] == "Shared" ) { + + return true; + + } else { + + return false; + + } + + } + /** * @brief Encrypt all files in a directory * @param string $publicKey the public key to encrypt files with @@ -356,7 +388,7 @@ class Util { */ public function encryptAll( $publicKey, $dirPath, $legacyPassphrase = null, $newPassphrase = null ) { - if ( $found = $this->findFiles( $dirPath ) ) { + if ( $found = $this->findEncFiles( $dirPath ) ) { // Disable proxy to prevent file being encrypted twice \OC_FileProxy::$enabled = false; @@ -478,13 +510,18 @@ class Util { * @param $fileId id of the file * @return path of the file */ - public static function getFilePath($fileId) { - $query = \OC_DB::prepare('SELECT `path`' + public static function fileIdToPath( $fileId ) { + + $query = \OC_DB::prepare( 'SELECT `path`' .' FROM `*PREFIX*filecache`' - .' WHERE `fileid` = ?'); - $result = $query->execute(array($fileId)); + .' WHERE `fileid` = ?' ); + + $result = $query->execute( array( $fileId ) ); + $row = $result->fetchRow(); - return substr($row['path'], 5); + + return substr( $row['path'], 5 ); + } /** @@ -527,5 +564,121 @@ class Util { return $userIds; } + + /** + * @brief Expand given path to all sub files & folders + * @param Session $session + * @param string $path path which needs to be updated + * @return bool outcome of attempt to set keyfiles + */ + public function getPaths( $path ) { + + // Default return value is success + $result = true; + + // Make path include 'files' dir for OC_FSV operations + $fPath = 'files' . $path; + + // If we're handling a single file + if ( ! $this->view->is_dir( $fPath ) ) { + + $pathsArray[] = $path; + + // If we're handling a folder (recursively) + } else { + + $subFiles = $this->view->getDirectoryContent( $fPath ); + + foreach ( $subFiles as $file ) { + + $filePath = substr( $file['path'], 5 ); + + // If this is a nested file + if ( ! $this->view->is_dir( $fPath ) ) { + + // Add the file path to array + $pathsArray[] = $path; + + } else { + + // If this is a nested folder + $dirPaths = $this->getPaths( $filePath ); + + // Add all subfiles & folders to the array + $pathsArray = array_merge( $dirPaths, $pathsArray ); + + } + } + + } + + return $pathsArray; + + } + + /** + * @brief Encrypt keyfile to multiple users + * @param array $users list of users which should be able to access the file + * @param string $filePath path of the file to be shared + */ + public function setSharedFileKeyfiles( Session $session, array $users, $filePath ) { + + // Make sure users are capable of sharing + $filteredUids = $this->filterShareReadyUsers( $users ); + + // Get public keys for each user, ready for generating sharekeys + $userPubKeys = Keymanager::getPublicKeys( $this->view, $filteredUids ); // TODO: check this includes the owner's public key + + \OC_FileProxy::$enabled = false; + + // Get the current users's private key for decrypting existing keyfile + $privateKey = $session->getPrivateKey(); + + $fileOwner = \OC\Files\Filesystem::getOwner( $filePath ); + + // Get the encrypted keyfile + // NOTE: the keyfile format depends on how it was encrypted! At + // this stage we don't know how it was encrypted + $encKeyfile = Keymanager::getFileKey( $this->view, $this->userId, $filePath ); + + // We need to decrypt the keyfile + // Has the file been shared yet? + if ( + $this->userId == $fileOwner + && ! Keymanager::getShareKey( $this->view, $this->userId, $filePath ) // NOTE: we can't use isShared() here because it's a post share hook so it always returns true + ) { + + // The file has no shareKey, and its keyfile must be + // decrypted conventionally + $plainKeyfile = Crypt::keyDecrypt( $encKeyfile, $privateKey ); + + + } else { + + // The file has a shareKey and must use it for decryption + $shareKey = Keymanager::getShareKey( $this->view, $this->userId, $filePath ); + + $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); + + } + + // Re-enc keyfile to (additional) sharekeys + $newShareKeys = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys ); + + // Save new sharekeys to all necessary user folders + if ( ! Keymanager::setShareKeys( $this->view, $filePath, $newShareKeys['keys'] ) ) { + + trigger_error( "SET Share keys failed" ); + + } + + // Delete existing keyfile + // Do this last to ensure file is recoverable in case of error + // Keymanager::deleteFileKey( $this->view, $this->userId, $params['fileTarget'] ); + + \OC_FileProxy::$enabled = true; + + return true; + } } diff --git a/apps/files_encryption/test/util.php b/apps/files_encryption/test/util.php index 1cdeff8008d..275e60f4bd6 100755 --- a/apps/files_encryption/test/util.php +++ b/apps/files_encryption/test/util.php @@ -150,13 +150,13 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase { } - function testFindFiles() { + function testFindEncFiles() { // $this->view->chroot( "/data/{$this->userId}/files" ); $util = new Encryption\Util( $this->view, $this->userId ); - $files = $util->findFiles( '/', 'encrypted' ); + $files = $util->findEncFiles( '/', 'encrypted' ); var_dump( $files ); -- cgit v1.2.3 From 40efeb91878e72eb5c2eb1ab50574cda9435e0fa Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Fri, 22 Feb 2013 16:02:27 +0100 Subject: isSharedFile() doesn't detect all shares, just use getUsersSharingFile() directly either you get a list of users or not --- apps/files_encryption/lib/proxy.php | 6 +----- lib/public/share.php | 34 ---------------------------------- 2 files changed, 1 insertion(+), 39 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 9e6a11d9d48..ebe09dc075a 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -113,14 +113,10 @@ class Proxy extends \OC_FileProxy { $encData = Crypt::symmetricEncryptFileContentKeyfile( $data ); // Check if the keyfile needs to be shared - if ( \OCP\Share::isSharedFile( $filePath ) ) { + if ( ($userIds = \OCP\Share::getUsersSharingFile( $filePath, true )) ) { // $fileOwner = \OC\Files\Filesystem::getOwner( $path ); - // List everyone sharing the file - //TODO check, is this path always the path to the source file? - $userIds = \OCP\Share::getUsersSharingFile( $filePath, true ); - $publicKeys = Keymanager::getPublicKeys( $rootView, $userIds ); \OC_FileProxy::$enabled = false; diff --git a/lib/public/share.php b/lib/public/share.php index 720337c3c38..7630c8ae6cb 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -108,41 +108,7 @@ class Share { return $path; } - - public static function isSharedFile( $path ) { - - $fPath = self::prepFileTarget( $path ); - - // Fetch all shares of this file path from DB - $query = \OC_DB::prepare( - 'SELECT - id - FROM - `*PREFIX*share` - WHERE - file_target = ?' - ); - - $result = $query->execute( array( $fPath ) ); - - if ( \OC_DB::isError( $result ) ) { - - \OC_Log::write( 'OCP\Share', \OC_DB::getErrorMessage( $result ) . ', path=' . $fPath, \OC_Log::ERROR ); - - } - - if ( $result->fetchRow() !== false ) { - return true; - - } else { - - return false; - - } - - } - /** * @brief Find which users can access a shared item * @param $path to the file -- cgit v1.2.3 From 31c434b79560c3c45e6202cecc635ad6cb887390 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Fri, 22 Feb 2013 16:08:08 +0100 Subject: the default should be to encrypt all files if the user/admin doesn't specify a blacklist explicitely --- apps/files_encryption/lib/proxy.php | 2 +- apps/files_encryption/settings-personal.php | 2 +- apps/files_encryption/settings.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index ebe09dc075a..56c9000bfb0 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -70,7 +70,7 @@ class Proxy extends \OC_FileProxy { if ( is_null(self::$blackList ) ) { - self::$blackList = explode(',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', 'jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg' ) ); + self::$blackList = explode(',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) ); } diff --git a/apps/files_encryption/settings-personal.php b/apps/files_encryption/settings-personal.php index 6fe4ea6d564..94e37ebe96b 100644 --- a/apps/files_encryption/settings-personal.php +++ b/apps/files_encryption/settings-personal.php @@ -8,7 +8,7 @@ $tmpl = new OCP\Template( 'files_encryption', 'settings-personal'); -$blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', 'jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg' ) ); +$blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) ); $tmpl->assign( 'blacklist', $blackList ); diff --git a/apps/files_encryption/settings.php b/apps/files_encryption/settings.php index d1260f44e9f..85c616bca79 100644 --- a/apps/files_encryption/settings.php +++ b/apps/files_encryption/settings.php @@ -10,7 +10,7 @@ $tmpl = new OCP\Template( 'files_encryption', 'settings' ); -$blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', 'jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg' ) ); +$blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) ); $tmpl->assign( 'blacklist', $blackList ); $tmpl->assign( 'encryption_mode', \OC_Appconfig::getValue( 'files_encryption', 'mode', 'none' ) ); -- cgit v1.2.3 From ca1b94d890c281507c31082f1116f15d246341dd Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Mon, 25 Feb 2013 12:29:07 +0100 Subject: make sure that home folders are mounted correctly before write/read keyfile --- apps/files_encryption/lib/keymanager.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index ec1fdd1fd55..d35ad8f4d5e 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -105,6 +105,7 @@ class Keymanager { */ public static function setFileKey( \OC_FilesystemView $view, $path, $userId, $catfile ) { + \OC\Files\Filesystem::initMountPoints($userId); $basePath = '/' . $userId . '/files_encryption/keyfiles'; $targetPath = self::keySetPreparation( $view, $path, $basePath, $userId ); @@ -134,6 +135,7 @@ class Keymanager { */ public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) { + \OC\Files\Filesystem::initMountPoints($userId); $filePath_f = ltrim( $filePath, '/' ); $keyfilePath = '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key'; -- cgit v1.2.3 From 4550ae6a69c00aeab2f54d0210ae5dee90f7ee82 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Tue, 26 Feb 2013 18:11:29 +0000 Subject: Shared encrypted files now readable by both sharer and sharee --- apps/files_encryption/lib/crypt.php | 2 ++ apps/files_encryption/lib/keymanager.php | 20 +++++++++++++---- apps/files_encryption/lib/proxy.php | 15 +++++++------ apps/files_encryption/lib/util.php | 37 ++++++++++++++++++++++---------- 4 files changed, 53 insertions(+), 21 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index a677de950ae..5a2d99df546 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -391,6 +391,8 @@ class Crypt { if( openssl_seal( $plainContent, $sealed, $shareKeys, $publicKeys ) ) { +// trigger_error("SEALED = $sealed"); + $i = 0; // Ensure each shareKey is labelled with its diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index d35ad8f4d5e..ec4057d0983 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -105,6 +105,8 @@ class Keymanager { */ public static function setFileKey( \OC_FilesystemView $view, $path, $userId, $catfile ) { + \OC_FileProxy::$enabled = false; + \OC\Files\Filesystem::initMountPoints($userId); $basePath = '/' . $userId . '/files_encryption/keyfiles'; @@ -112,15 +114,19 @@ class Keymanager { if ( $view->is_dir( $basePath . '/' . $targetPath ) ) { - + // FIXME: write me } else { // Save the keyfile in parallel directory - return $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); + $result = $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); } + \OC_FileProxy::$enabled = true; + + return $result; + } /** @@ -140,16 +146,22 @@ class Keymanager { $keyfilePath = '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key'; + \OC_FileProxy::$enabled = false; + if ( $view->file_exists( $keyfilePath ) ) { - return $view->file_get_contents( $keyfilePath ); + $result = $view->file_get_contents( $keyfilePath ); } else { - return false; + $result = false; } + \OC_FileProxy::$enabled = true; + + return $result; + } /** diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 56c9000bfb0..29207dce07d 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -91,7 +91,8 @@ class Proxy extends \OC_FileProxy { return false; } - public function preFile_put_contents( $path, &$data ) { + public function preFile_put_contents( $path, &$data ) { + // TODO check for existing key file and reuse it if possible to avoid problems with versioning etc. if ( self::shouldEncrypt( $path ) ) { @@ -204,22 +205,22 @@ class Proxy extends \OC_FileProxy { // Get the encrypted keyfile $encKeyfile = Keymanager::getFileKey( $view, $fileOwner, $relPath ); - trigger_error("\$encKeyfile = ". var_export($encKeyfile, 1)); - // Attempt to fetch the user's shareKey $shareKey = Keymanager::getShareKey( $view, $userId, $relPath ); - trigger_error("\$shareKey = ".var_export($shareKey, 1)); - // Check if key is shared or not if ( $shareKey ) { \OC_FileProxy::$enabled = false; +// trigger_error("\$encKeyfile = $encKeyfile, \$shareKey = $shareKey, \$privateKey = $privateKey"); + // Decrypt keyfile with shareKey $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); - trigger_error("PROXY plainkeyfile = ". var_export($plainKeyfile, 1)); +// $plainKeyfile = $encKeyfile; + +// trigger_error("PROXY plainkeyfile = ". var_export($plainKeyfile, 1)); } else { @@ -229,6 +230,8 @@ class Proxy extends \OC_FileProxy { } $plainData = Crypt::symmetricDecryptFileContent( $data, $plainKeyfile ); + +// trigger_error("PLAINDATA = ". var_export($plainData, 1)); } elseif ( Crypt::mode() == 'server' diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index ac098cd877d..920ff3eb159 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -21,17 +21,28 @@ * */ -// Todo: +# Bugs +# ---- +# Sharing a file to a user without encryption set up will not provide them with access but won't notify the sharer +# Deleting files if keyfile is missing fails +# When encryption app is disabled files become unreadable +# Timeouts on first login due to encryption of very large files +# MultiKeyEncrypt() may be failing + + +# Missing features +# ---------------- +# Unshare a file +# Re-use existing keyfiles so they don't need version control +# Make sure user knows if large files weren't encrypted +# Trashbin support + + +// Old Todo: // - Crypt/decrypt button in the userinterface // - Setting if crypto should be on by default // - Add a setting "Don´t encrypt files larger than xx because of performance // reasons" -// - Transparent decrypt/encrypt in filesystem.php. Autodetect if a file is -// encrypted (.encrypted extension) -// - Don't use a password directly as encryption key. but a key which is -// stored on the server and encrypted with the user password. -> password -// change faster -// - IMPORTANT! Check if the block lenght of the encrypted data stays the same namespace OCA\Encryption; @@ -663,10 +674,14 @@ class Util { } // Re-enc keyfile to (additional) sharekeys - $newShareKeys = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys ); - - // Save new sharekeys to all necessary user folders - if ( ! Keymanager::setShareKeys( $this->view, $filePath, $newShareKeys['keys'] ) ) { + $multiEncKey = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys ); + + // Save the recrypted key to it's owner's keyfiles directory + // Save new sharekeys to all necessary user directory + if ( + ! Keymanager::setFileKey( $this->view, $filePath, $fileOwner, $multiEncKey['data'] ) + || ! Keymanager::setShareKeys( $this->view, $filePath, $multiEncKey['keys'] ) + ) { trigger_error( "SET Share keys failed" ); -- cgit v1.2.3 From aae9b0b1bfc95d60bcc7c4a4b85a387a94ac9caa Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Tue, 26 Feb 2013 18:33:31 +0000 Subject: Started work on post unshare hook Development snapshot --- apps/files_encryption/hooks/hooks.php | 114 ++++++++++++++++++++++--------- apps/files_encryption/lib/keymanager.php | 24 +++++++ apps/files_encryption/lib/util.php | 3 +- 3 files changed, 107 insertions(+), 34 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 6d982b2c3b0..bf16a492e33 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -167,44 +167,60 @@ class Hooks { * @brief get all users with access to the file and encrypt the file key to each of them */ public static function postShared( $params ) { - - // NOTE: $params is an array with these keys: + + // NOTE: $params has keys: + // [itemType] => file // itemSource -> int, filecache file ID + // [parent] => + // [itemTarget] => /13 // shareWith -> string, uid of user being shared to // fileTarget -> path of file being shared // uidOwner -> owner of the original file being shared + // [shareType] => 0 + // [shareWith] => test1 + // [uidOwner] => admin + // [permissions] => 17 + // [fileSource] => 13 + // [fileTarget] => /test8 + // [id] => 10 + // [token] => - $view = new \OC_FilesystemView( '/' ); - $session = new Session(); - $userId = \OCP\User::getUser(); - $util = new Util( $view, $userId ); - $path = $util->fileIdToPath( $params['itemSource'] ); - - $usersSharing = \OCP\Share::getUsersSharingFile( $path, true ); - - $allPaths = $util->getPaths( $path ); + // TODO: Should other kinds of item be encrypted too? + if ( $params['itemType'] === 'file' ) { - $failed = array(); - - foreach ( $allPaths as $path ) { - - if ( ! $util->setSharedFileKeyfiles( $session, $usersSharing, $path ) ) { + $view = new \OC_FilesystemView( '/' ); + $session = new Session(); + $userId = \OCP\User::getUser(); + $util = new Util( $view, $userId ); + $path = $util->fileIdToPath( $params['itemSource'] ); + + $usersSharing = \OCP\Share::getUsersSharingFile( $path, true ); + + $allPaths = $util->getPaths( $path ); + + $failed = array(); - $failed[] = $path; + foreach ( $allPaths as $path ) { + + if ( ! $util->setSharedFileKeyfiles( $session, $usersSharing, $path ) ) { + + $failed[] = $path; + + } } - } - - // If no attempts to set keyfiles failed - if ( empty( $failed ) ) { - - return true; + // If no attempts to set keyfiles failed + if ( empty( $failed ) ) { - } else { - - return false; + return true; + + } else { + return false; + + } + } } @@ -213,15 +229,47 @@ class Hooks { * @brief */ public static function postUnshare( $params ) { + + // NOTE: $params has keys: + // [itemType] => file + // [itemSource] => 13 + // [shareType] => 0 + // [shareWith] => test1 -// $view = new \OC_FilesystemView( '/' ); -// $session = new Session(); -// $userId = \OCP\User::getUser(); -// $util = new Util( $view, $userId ); -// $path = $util->fileIdToPath( $params['itemSource'] ); -// -// return Crypt::updateKeyfile( $view, $util, $session, $userId, $path ); + // TODO: Should other kinds of item be encrypted too? + if ( $params['itemType'] === 'file' ) { + + $view = new \OC_FilesystemView( '/' ); + $session = new Session(); + $userId = \OCP\User::getUser(); + $util = new Util( $view, $userId ); + $path = $util->fileIdToPath( $params['itemSource'] ); + $allPaths = $util->getPaths( $path ); + + foreach ( $allPaths as $path ) { + + if ( ! Keymanager::delShareKey( $view, $userId, $path ) ) { + + $failed[] = $path; + + } + + } + + // If no attempts to set keyfiles failed + if ( empty( $failed ) ) { + + return true; + + } else { + + return false; + + } + + } + } /** diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index ec4057d0983..22e2ffa500e 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -350,6 +350,30 @@ class Keymanager { } + /** + * @brief Delete a single user's shareKey for a single file + */ + public static function delShareKey( \OC_FilesystemView $view, $userId, $filePath ) { + + $trimmed = ltrim( $filePath, '/' ); + $shareKeyPath = '/' . $userId . '/files_encryption/share-keys/' . $trimmed . '.shareKey'; + + // Unlink doesn't tell us if file was deleted (not found returns + // true), so we perform our own test + if ( $view->file_exists( $shareKeyPath ) ) { + + return $view->unlink( $shareKeyPath ); + + } else { + + \OC_Log::write( 'Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath, \OC_Log::ERROR ); + + return false; + + } + + } + /** * @brief Make preparations to vars and filesystem for saving a keyfile */ diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 920ff3eb159..02c62e160c8 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -580,7 +580,8 @@ class Util { * @brief Expand given path to all sub files & folders * @param Session $session * @param string $path path which needs to be updated - * @return bool outcome of attempt to set keyfiles + * @return array $pathsArray all found file paths + * @note Paths of directories excluded, only *file* paths are returned */ public function getPaths( $path ) { -- cgit v1.2.3 From 14eae441eb77ee53304d8a164deb146bda4020f4 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Wed, 27 Feb 2013 15:31:23 +0000 Subject: Unsharing a single file now works --- apps/files_encryption/hooks/hooks.php | 4 +++- apps/files_encryption/lib/keymanager.php | 12 ++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index bf16a492e33..fb3545208d2 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -245,11 +245,13 @@ class Hooks { $util = new Util( $view, $userId ); $path = $util->fileIdToPath( $params['itemSource'] ); + // If path is a folder, get all children $allPaths = $util->getPaths( $path ); foreach ( $allPaths as $path ) { - if ( ! Keymanager::delShareKey( $view, $userId, $path ) ) { + // Unshare each child path + if ( ! Keymanager::delShareKey( $view, $params['shareWith'], $path ) ) { $failed[] = $path; diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 22e2ffa500e..62bb12bf90d 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -355,6 +355,8 @@ class Keymanager { */ public static function delShareKey( \OC_FilesystemView $view, $userId, $filePath ) { + \OC_FileProxy::$enabled = false; + $trimmed = ltrim( $filePath, '/' ); $shareKeyPath = '/' . $userId . '/files_encryption/share-keys/' . $trimmed . '.shareKey'; @@ -362,16 +364,22 @@ class Keymanager { // true), so we perform our own test if ( $view->file_exists( $shareKeyPath ) ) { - return $view->unlink( $shareKeyPath ); + $result = $view->unlink( $shareKeyPath ); } else { + trigger_error("Could not delete shareKey; does not exist: $shareKeyPath"); + \OC_Log::write( 'Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath, \OC_Log::ERROR ); - return false; + $result = false; } + \OC_FileProxy::$enabled = false; + + return $result; + } /** -- cgit v1.2.3 From 69bc42f920324ef02ade5dff6bd52f2ddde113a2 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Wed, 27 Feb 2013 16:15:03 +0000 Subject: Deleting encrypted files with missing keyfiles/shareKeys now succeeds --- apps/files_encryption/hooks/hooks.php | 9 ++------- apps/files_encryption/lib/crypt.php | 2 -- apps/files_encryption/lib/proxy.php | 27 +++++++++++++++++++++------ apps/files_encryption/lib/util.php | 3 --- 4 files changed, 23 insertions(+), 18 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index fb3545208d2..590ba7b1b97 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -279,13 +279,8 @@ class Hooks { */ public static function postUnshareAll( $params ) { -// $view = new \OC_FilesystemView( '/' ); -// $session = new Session(); -// $userId = \OCP\User::getUser(); -// $util = new Util( $view, $userId ); -// $path = $util->fileIdToPath( $params['itemSource'] ); -// -// return Crypt::updateKeyfile( $view, $util, $session, $userId, $path ); + // NOTE: It appears that this is never called for files, so + // we may not need to implement it } diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 5a2d99df546..a138f5f3cb0 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -390,8 +390,6 @@ class Crypt { $shareKeys = array(); if( openssl_seal( $plainContent, $sealed, $shareKeys, $publicKeys ) ) { - -// trigger_error("SEALED = $sealed"); $i = 0; diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 29207dce07d..92a70499367 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -272,23 +272,38 @@ class Proxy extends \OC_FileProxy { $split = explode( '/', $trimmed ); $sliced = array_slice( $split, 2 ); $relPath = implode( '/', $sliced ); + $filePath = $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/'. $relPath; if ( $view->is_dir( $path ) ) { // Dirs must be handled separately as deleteFileKey // doesn't handle them - $view->unlink( $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/'. $relPath ); + $view->unlink( $filePath ); } else { - // Delete keyfile so it isn't orphaned - $result = Keymanager::deleteFileKey( $view, $userId, $relPath ); - - \OC_FileProxy::$enabled = true; + // Delete keyfile & shareKey so it isn't orphaned + if ( + ! ( + Keymanager::deleteFileKey( $view, $userId, $relPath ) + && Keymanager::delShareKey( $view, $userId, $relPath ) + ) + ) { + + \OC_Log::write( 'Encryption library', 'Keyfile or shareKey could not be deleted for file "'.$filePath.'"', \OC_Log::ERROR ); + + + } + - return $result; } + + \OC_FileProxy::$enabled = true; + + // If we don't return true then file delete will fail; better + // to leave orphaned keyfiles than to disallow file deletion + return true; } diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 02c62e160c8..31ce3a413cc 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -24,15 +24,12 @@ # Bugs # ---- # Sharing a file to a user without encryption set up will not provide them with access but won't notify the sharer -# Deleting files if keyfile is missing fails # When encryption app is disabled files become unreadable # Timeouts on first login due to encryption of very large files -# MultiKeyEncrypt() may be failing # Missing features # ---------------- -# Unshare a file # Re-use existing keyfiles so they don't need version control # Make sure user knows if large files weren't encrypted # Trashbin support -- cgit v1.2.3 From 953319a2c3d85bf0d5eb86511c7466188b5ca45f Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Wed, 27 Feb 2013 18:46:44 +0000 Subject: Made proxy class reuse existing keyfiles not gen new ones; Added notes about reusing shareKeys --- apps/files_encryption/lib/keymanager.php | 2 -- apps/files_encryption/lib/proxy.php | 46 ++++++++++++++++++++--------- apps/files_encryption/lib/util.php | 50 +++++++++++++++++++++----------- 3 files changed, 65 insertions(+), 33 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 62bb12bf90d..0c2db2be329 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -368,8 +368,6 @@ class Keymanager { } else { - trigger_error("Could not delete shareKey; does not exist: $shareKeyPath"); - \OC_Log::write( 'Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath, \OC_Log::ERROR ); $result = false; diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 92a70499367..c5b1c8154c4 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -93,16 +93,17 @@ class Proxy extends \OC_FileProxy { public function preFile_put_contents( $path, &$data ) { - // TODO check for existing key file and reuse it if possible to avoid problems with versioning etc. if ( self::shouldEncrypt( $path ) ) { // Stream put contents should have been converted to fopen if ( !is_resource( $data ) ) { - // TODO check who is the owner of the file in case of shared folders $userId = \OCP\USER::getUser(); $rootView = new \OC_FilesystemView( '/' ); $util = new Util( $rootView, $userId ); + $session = new Session(); + $fileOwner = \OC\Files\Filesystem::getOwner( $path ); + $privateKey = $session->getPrivateKey(); $filePath = $util->stripUserFilesPath( $path ); // Set the filesize for userland, before encrypting $size = strlen( $data ); @@ -110,45 +111,62 @@ class Proxy extends \OC_FileProxy { // Disable encryption proxy to prevent recursive calls \OC_FileProxy::$enabled = false; + // Check if there is an existing key we can reuse + if ( $encKeyfile = Keymanager::getFileKey( $rootView, $fileOwner, $filePath ) ) { + + $keyPreExists = true; + + // Decrypt the keyfile + $plainKey = $util->decryptUnknownKeyfile( $filePath, $fileOwner, $privateKey ); + + } else { + + $keyPreExists = false; + + // Make a new key + $plainKey = Crypt::generateKey(); + + } + // Encrypt data - $encData = Crypt::symmetricEncryptFileContentKeyfile( $data ); + $encData = Crypt::symmetricEncryptFileContent( $data, $plainKey ); // Check if the keyfile needs to be shared - if ( ($userIds = \OCP\Share::getUsersSharingFile( $filePath, true )) ) { - -// $fileOwner = \OC\Files\Filesystem::getOwner( $path ); + if ( $userIds = \OCP\Share::getUsersSharingFile( $filePath, true ) ) { $publicKeys = Keymanager::getPublicKeys( $rootView, $userIds ); \OC_FileProxy::$enabled = false; // Encrypt plain keyfile to multiple sharefiles - $multiEncrypted = Crypt::multiKeyEncrypt( $encData['key'], $publicKeys ); + $multiEncrypted = Crypt::multiKeyEncrypt( $plainKey, $publicKeys ); // Save sharekeys to user folders + // TODO: openssl_seal generates new shareKeys (envelope keys) each time data is encrypted, but will data still be decryptable using old shareKeys? If so we don't need to replace the old shareKeys here, we only need to set the new ones Keymanager::setShareKeys( $rootView, $filePath, $multiEncrypted['keys'] ); // Set encrypted keyfile as common varname $encKey = $multiEncrypted['encrypted']; - - } else { $publicKey = Keymanager::getPublicKey( $rootView, $userId ); // Encrypt plain data to a single user - $encKey = Crypt::keyEncrypt( $encData['key'], $publicKey ); + $encKey = Crypt::keyEncrypt( $plainKey, $publicKey ); } - // TODO: Replace userID with ownerId so keyfile is saved centrally + // Save the key if its new + if ( ! $keyPreExists ) { - // Save keyfile for newly encrypted file in parallel directory tree - Keymanager::setFileKey( $rootView, $filePath, $userId, $encKey ); + // Save keyfile for newly encrypted file in parallel directory tree + Keymanager::setFileKey( $rootView, $filePath, $fileOwner, $encKey ); + + } // Replace plain content with encrypted content by reference - $data = $encData['encrypted']; + $data = $encData; // Update the file cache with file info \OC\Files\Filesystem::putFileInfo( $path, array( 'encrypted'=>true, 'size' => $size ), '' ); diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 31ce3a413cc..cd223bd7029 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -626,25 +626,15 @@ class Util { } /** - * @brief Encrypt keyfile to multiple users - * @param array $users list of users which should be able to access the file - * @param string $filePath path of the file to be shared + * @brief Decrypt a keyfile without knowing how it was encrypted + * @param string $filePath + * @param string $fileOwner + * @param string $privateKey + * @note Checks whether file was encrypted with openssl_seal or + * openssl_encrypt, and decrypts accrdingly */ - public function setSharedFileKeyfiles( Session $session, array $users, $filePath ) { - - // Make sure users are capable of sharing - $filteredUids = $this->filterShareReadyUsers( $users ); - - // Get public keys for each user, ready for generating sharekeys - $userPubKeys = Keymanager::getPublicKeys( $this->view, $filteredUids ); // TODO: check this includes the owner's public key + public function decryptUnknownKeyfile( $filePath, $fileOwner, $privateKey ) { - \OC_FileProxy::$enabled = false; - - // Get the current users's private key for decrypting existing keyfile - $privateKey = $session->getPrivateKey(); - - $fileOwner = \OC\Files\Filesystem::getOwner( $filePath ); - // Get the encrypted keyfile // NOTE: the keyfile format depends on how it was encrypted! At // this stage we don't know how it was encrypted @@ -671,6 +661,32 @@ class Util { } + return $plainKeyfile; + + } + + /** + * @brief Encrypt keyfile to multiple users + * @param array $users list of users which should be able to access the file + * @param string $filePath path of the file to be shared + */ + public function setSharedFileKeyfiles( Session $session, array $users, $filePath ) { + + // Make sure users are capable of sharing + $filteredUids = $this->filterShareReadyUsers( $users ); + + // Get public keys for each user, ready for generating sharekeys + $userPubKeys = Keymanager::getPublicKeys( $this->view, $filteredUids ); // TODO: check this includes the owner's public key + + \OC_FileProxy::$enabled = false; + + // Get the current users's private key for decrypting existing keyfile + $privateKey = $session->getPrivateKey(); + + $fileOwner = \OC\Files\Filesystem::getOwner( $filePath ); + + $plainKeyfile = $this->decryptUnknownKeyfile( $filePath, $fileOwner, $privateKey ); + // Re-enc keyfile to (additional) sharekeys $multiEncKey = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys ); -- cgit v1.2.3 From 0bc7d3bcf833e257fa4b2ae3b74d60bef63218b8 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Wed, 27 Feb 2013 18:50:57 +0000 Subject: Added notes where to reuse old keys instead of generating new ones --- apps/files_encryption/lib/stream.php | 1 + apps/files_encryption/lib/util.php | 1 + 2 files changed, 2 insertions(+) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index d4b993b4c06..f4bd6f1b6b0 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -318,6 +318,7 @@ class Stream { // one), save the newly generated keyfile if ( ! $this->getKey() ) { + // TODO: Reuse the keyfile, it it exists, instead of making a new one $this->keyfile = Crypt::generateKey(); $this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId ); diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index cd223bd7029..6a18feea7df 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -692,6 +692,7 @@ class Util { // Save the recrypted key to it's owner's keyfiles directory // Save new sharekeys to all necessary user directory + // TODO: Reuse the keyfile, it it exists, instead of making a new one if ( ! Keymanager::setFileKey( $this->view, $filePath, $fileOwner, $multiEncKey['data'] ) || ! Keymanager::setShareKeys( $this->view, $filePath, $multiEncKey['keys'] ) -- cgit v1.2.3 From e65e6a12f1270faec377363f02f27ddd7d68b8e9 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Mon, 4 Mar 2013 15:33:38 +0100 Subject: define key size in constructor, otherwise the key size will depend on the servers openssl conf --- apps/files_encryption/lib/crypt.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index a138f5f3cb0..2be6e3ae5d9 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -56,7 +56,7 @@ class Crypt { */ public static function createKeypair() { - $res = openssl_pkey_new(); + $res = openssl_pkey_new(array('private_key_bits' => 4096)); // Get private key openssl_pkey_export( $res, $privateKey ); @@ -450,7 +450,7 @@ class Crypt { * @returns encrypted file */ public static function keyEncrypt( $plainContent, $publicKey ) { - + openssl_public_encrypt( $plainContent, $encryptedContent, $publicKey ); return $encryptedContent; -- cgit v1.2.3 From f2b86d0227d080dd4395efaf5fb086b024af0c95 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Mon, 4 Mar 2013 17:58:56 +0100 Subject: make sure that $this->userId is initialized before using it as a parameter --- apps/files_encryption/lib/stream.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index f4bd6f1b6b0..6074638ab39 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -68,6 +68,8 @@ class Stream { private $rootView; // a fsview object set to '/' public function stream_open( $path, $mode, $options, &$opened_path ) { + + $this->userId = \OCP\User::getUser(); // Get access to filesystem via filesystemview object if ( !self::$view ) { @@ -82,9 +84,7 @@ class Stream { $this->rootView = new \OC_FilesystemView( $this->userId . '/' ); } - - $this->userId = \OCP\User::getUser(); - + // Get the bare file path $path = str_replace( 'crypt://', '', $path ); -- cgit v1.2.3 From c1f1fbda08b464b286e309283ed81d16f30a5ca6 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Sat, 9 Mar 2013 19:18:34 +0100 Subject: Fixed stream wrapper bugs Switched encryptAll() to use stream-based instead of file-at-a-time encryption Development snapshot --- apps/files_encryption/lib/crypt.php | 4 +- apps/files_encryption/lib/proxy.php | 10 ++--- apps/files_encryption/lib/stream.php | 60 +++++++++++---------------- apps/files_encryption/lib/util.php | 78 ++++++++++++++++++++++++++++++------ apps/files_encryption/test/crypt.php | 6 +-- 5 files changed, 99 insertions(+), 59 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 2be6e3ae5d9..f92930c2cbd 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -114,7 +114,7 @@ class Crypt { * @return true / false * @note see also OCA\Encryption\Util->isEncryptedPath() */ - public static function isCatfile( $content ) { + public static function isCatfileContent( $content ) { if ( !$content ) { @@ -179,7 +179,7 @@ class Crypt { if ( isset( $metadata['encrypted'] ) and $metadata['encrypted'] === true - and ! self::isCatfile( $data ) + and ! self::isCatfileContent( $data ) ) { return true; diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index c5b1c8154c4..2a738c80e38 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -74,7 +74,7 @@ class Proxy extends \OC_FileProxy { } - if ( Crypt::isCatfile( $path ) ) { + if ( Crypt::isCatfileContent( $path ) ) { return true; @@ -209,7 +209,7 @@ class Proxy extends \OC_FileProxy { // If data is a catfile if ( Crypt::mode() == 'server' - && Crypt::isCatfile( $data ) + && Crypt::isCatfileContent( $data ) ) { // TODO use get owner to find correct location of key files for shared files @@ -439,7 +439,7 @@ class Proxy extends \OC_FileProxy { public function postGetMimeType( $path, $mime ) { - if ( Crypt::isCatfile( $path ) ) { + if ( Crypt::isCatfileContent( $path ) ) { $mime = \OCP\Files::getMimeType( 'crypt://' . $path, 'w' ); @@ -451,7 +451,7 @@ class Proxy extends \OC_FileProxy { public function postStat( $path, $data ) { - if ( Crypt::isCatfile( $path ) ) { + if ( Crypt::isCatfileContent( $path ) ) { $cached = \OC\Files\Filesystem::getFileInfo( $path, '' ); @@ -464,7 +464,7 @@ class Proxy extends \OC_FileProxy { public function postFileSize( $path, $size ) { - if ( Crypt::isCatfile( $path ) ) { + if ( Crypt::isCatfileContent( $path ) ) { $cached = \OC\Files\Filesystem::getFileInfo( $path, '' ); diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 6074638ab39..0b2e6ab3e64 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -68,42 +68,33 @@ class Stream { private $rootView; // a fsview object set to '/' public function stream_open( $path, $mode, $options, &$opened_path ) { - - $this->userId = \OCP\User::getUser(); - // Get access to filesystem via filesystemview object - if ( !self::$view ) { - - self::$view = new \OC_FilesystemView( $this->userId . '/' ); - - } + $this->userId = \OCP\User::getUser(); - // Set rootview object if necessary - if ( ! $this->rootView ) { + if ( ! isset( $this->rootView ) ) { - $this->rootView = new \OC_FilesystemView( $this->userId . '/' ); + $this->rootView = new \OC_FilesystemView( '/' ); } - // Get the bare file path - $path = str_replace( 'crypt://', '', $path ); + // Strip identifier text from path + $this->rawPath = str_replace( 'crypt://', '', $path ); - $this->rawPath = $path; - - $this->path_f = $this->userId . '/files/' . $path; + // Set file path relative to user files dir + $this->relPath = $this->userId . '/files/' . $this->rawPath; if ( - dirname( $path ) == 'streams' - and isset( self::$sourceStreams[basename( $path )] ) + dirname( $this->rawPath ) == 'streams' + and isset( self::$sourceStreams[basename( $this->rawPath )] ) ) { // Is this just for unit testing purposes? - $this->handle = self::$sourceStreams[basename( $path )]['stream']; + $this->handle = self::$sourceStreams[basename( $this->rawPath )]['stream']; - $this->path = self::$sourceStreams[basename( $path )]['path']; + $this->path = self::$sourceStreams[basename( $this->rawPath )]['path']; - $this->size = self::$sourceStreams[basename( $path )]['size']; + $this->size = self::$sourceStreams[basename( $this->rawPath )]['size']; } else { @@ -114,41 +105,38 @@ class Stream { or $mode == 'wb+' ) { + // We're writing a new file so start write counter with 0 bytes $this->size = 0; } else { + $this->size = $this->rootView->filesize( $this->relPath, $mode ); - - $this->size = self::$view->filesize( $this->path_f, $mode ); - - //$this->size = filesize( $path ); + //$this->size = filesize( $this->rawPath ); } // Disable fileproxies so we can open the source file without recursive encryption \OC_FileProxy::$enabled = false; - //$this->handle = fopen( $path, $mode ); + //$this->handle = fopen( $this->rawPath, $mode ); - $this->handle = self::$view->fopen( $this->path_f, $mode ); + $this->handle = $this->rootView->fopen( $this->relPath, $mode ); \OC_FileProxy::$enabled = true; - if ( !is_resource( $this->handle ) ) { + if ( ! is_resource( $this->handle ) ) { - \OCP\Util::writeLog( 'files_encryption', 'failed to open '.$path, \OCP\Util::ERROR ); + \OCP\Util::writeLog( 'files_encryption', 'failed to open file "'.$this->rootView . '"', \OCP\Util::ERROR ); + } else { + + $this->meta = stream_get_meta_data( $this->handle ); + } } - if ( is_resource( $this->handle ) ) { - - $this->meta = stream_get_meta_data( $this->handle ); - - } - return is_resource( $this->handle ); } @@ -238,7 +226,7 @@ class Stream { // If a keyfile already exists for a file named identically to // file to be written - if ( self::$view->file_exists( $this->userId . '/'. 'files_encryption' . '/' . 'keyfiles' . '/' . $this->rawPath . '.key' ) ) { + if ( $this->rootView->file_exists( $this->userId . '/'. 'files_encryption' . '/' . 'keyfiles' . '/' . $this->rawPath . '.key' ) ) { // TODO: add error handling for when file exists but no // keyfile diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 6a18feea7df..e8b5be2de15 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -24,13 +24,12 @@ # Bugs # ---- # Sharing a file to a user without encryption set up will not provide them with access but won't notify the sharer -# When encryption app is disabled files become unreadable # Timeouts on first login due to encryption of very large files # Missing features # ---------------- -# Re-use existing keyfiles so they don't need version control +# Re-use existing keyfiles so they don't need version control (part implemented, stream{} and util{} remain) # Make sure user knows if large files weren't encrypted # Trashbin support @@ -280,14 +279,14 @@ class Util { // will eat server resources :( if ( Keymanager::getFileKey( $this->view, $this->userId, $file ) - && Crypt::isCatfile( $data ) + && Crypt::isCatfileContent( $data ) ) { $found['encrypted'][] = array( 'name' => $file, 'path' => $filePath ); // If the file uses old // encryption system - } elseif ( Crypt::isLegacyEncryptedContent( $this->view->file_get_contents( $filePath ), $relPath ) ) { + } elseif ( Crypt::isLegacyEncryptedContent( $this->tail( $filePath, 3 ), $relPath ) ) { $found['legacy'][] = array( 'name' => $file, 'path' => $filePath ); @@ -324,6 +323,49 @@ class Util { } + /** + * @brief Fetch the last lines of a file efficiently + * @note Safe to use on large files; does not read entire file to memory + * @note Derivative of http://tekkie.flashbit.net/php/tail-functionality-in-php + */ + public function tail( $filename, $numLines ) { + + \OC_FileProxy::$enabled = false; + + $text = ''; + $pos = -1; + $handle = $this->view->fopen( $filename, 'r' ); + + while ( $numLines > 0 ) { + + --$pos; + + if( fseek( $handle, $pos, SEEK_END ) !== 0 ) { + + rewind( $handle ); + $numLines = 0; + + } elseif ( fgetc( $handle ) === "\n" ) { + + --$numLines; + + } + + $block_size = ( -$pos ) % 8192; + if ( $block_size === 0 || $numLines === 0 ) { + + $text = fread( $handle, ( $block_size === 0 ? 8192 : $block_size ) ) . $text; + + } + } + + fclose( $handle ); + + \OC_FileProxy::$enabled = true; + + return $text; + } + /** * @brief Check if a given path identifies an encrypted file * @return true / false @@ -338,7 +380,7 @@ class Util { \OC_FileProxy::$enabled = true; - return Crypt::isCatfile( $data ); + return Crypt::isCatfileContent( $data ); } @@ -403,22 +445,32 @@ class Util { // Encrypt unencrypted files foreach ( $found['plain'] as $plainFile ) { + + // Open plain file handle + + + // Open enc file handle + - // Fetch data from file - $plainData = $this->view->file_get_contents( $plainFile['path'] ); + // Read plain file in chunks - // Encrypt data, generate catfile - $encrypted = Crypt::keyEncryptKeyfile( $plainData, $publicKey ); $relPath = $this->stripUserFilesPath( $plainFile['path'] ); - // Save keyfile - Keymanager::setFileKey( $this->view, $relPath, $this->userId, $encrypted['key'] ); + // Open handle with for binary reading + $plainHandle = $this->view->fopen( $plainFile['path'], 'rb' ); + // Open handle with for binary writing + $encHandle = fopen( 'crypt://' . 'var/www/oc6/data/' . $plainFile['path'] . '.tmp', 'ab' ); // Overwrite the existing file with the encrypted one - $this->view->file_put_contents( $plainFile['path'], $encrypted['data'] ); + //$this->view->file_put_contents( $plainFile['path'], $encrypted['data'] ); + $size = stream_copy_to_stream( $plainHandle, $encHandle ); + + // Fetch the key that has just been set/updated by the stream + $encKey = Keymanager::getFileKey( $relPath ); - $size = strlen( $encrypted['data'] ); + // Save keyfile + Keymanager::setFileKey( $this->view, $relPath, $this->userId, $encKey ); // Add the file to the cache \OC\Files\Filesystem::putFileInfo( $plainFile['path'], array( 'encrypted'=>true, 'size' => $size ), '' ); diff --git a/apps/files_encryption/test/crypt.php b/apps/files_encryption/test/crypt.php index 48ad2ee0075..b02e63b2ffc 100755 --- a/apps/files_encryption/test/crypt.php +++ b/apps/files_encryption/test/crypt.php @@ -416,13 +416,13 @@ class Test_Crypt extends \PHPUnit_Framework_TestCase { function testIsEncryptedContent() { - $this->assertFalse( Encryption\Crypt::isCatfile( $this->dataUrl ) ); + $this->assertFalse( Encryption\Crypt::isCatfileContent( $this->dataUrl ) ); - $this->assertFalse( Encryption\Crypt::isCatfile( $this->legacyEncryptedData ) ); + $this->assertFalse( Encryption\Crypt::isCatfileContent( $this->legacyEncryptedData ) ); $keyfileContent = Encryption\Crypt::symmetricEncryptFileContent( $this->dataUrl, 'hat' ); - $this->assertTrue( Encryption\Crypt::isCatfile( $keyfileContent ) ); + $this->assertTrue( Encryption\Crypt::isCatfileContent( $keyfileContent ) ); } -- cgit v1.2.3 From c89fd49870e3bdd66b73ab6d8d64895e870de260 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Tue, 19 Mar 2013 19:53:15 +0100 Subject: Improved folder creation code Created stub method for checking user pwd recovery preference from db Added pwd recovery column to db Added comments --- apps/files_encryption/appinfo/database.xml | 8 ++++ apps/files_encryption/hooks/hooks.php | 6 +-- apps/files_encryption/lib/util.php | 68 ++++++++++++++---------------- 3 files changed, 42 insertions(+), 40 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/appinfo/database.xml b/apps/files_encryption/appinfo/database.xml index d294c35d63d..b144b6cb2a4 100644 --- a/apps/files_encryption/appinfo/database.xml +++ b/apps/files_encryption/appinfo/database.xml @@ -18,6 +18,14 @@ text true 64 + What client-side / server-side configuration is used + + + recovery + boolean + true + 0 + Whether encryption key recovery is enabled diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 590ba7b1b97..8db75397063 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -29,9 +29,6 @@ namespace OCA\Encryption; class Hooks { - // TODO: use passphrase for encrypting private key that is separate to - // the login password - /** * @brief Startup encryption backend upon user login * @note This method should never be called for users using client side encryption @@ -196,12 +193,15 @@ class Hooks { $usersSharing = \OCP\Share::getUsersSharingFile( $path, true ); + // Recursively expand path to include subfiles $allPaths = $util->getPaths( $path ); $failed = array(); + // Loop through all subfiles foreach ( $allPaths as $path ) { + // Attempt to set shareKey if ( ! $util->setSharedFileKeyfiles( $session, $usersSharing, $path ) ) { $failed[] = $path; diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index e8b5be2de15..a80da73a4b0 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -153,45 +153,24 @@ class Util { */ public function setupServerSide( $passphrase = null ) { - // Create user dir - if( !$this->view->file_exists( $this->userDir ) ) { + // Set directories to check / create + $setUpDirs = array( + $this->userDir + , $this->userFilesDir + , $this->publicKeyDir + , $this->encryptionDir + , $this->keyfilesPath + , $this->shareKeysPath + ); - $this->view->mkdir( $this->userDir ); + // Check / create all necessary dirs + foreach ( $setUpDirs as $dirPath ) { - } - - // Create user files dir - if( !$this->view->file_exists( $this->userFilesDir ) ) { - - $this->view->mkdir( $this->userFilesDir ); - - } - - // Create shared public key directory - if( !$this->view->file_exists( $this->publicKeyDir ) ) { - - $this->view->mkdir( $this->publicKeyDir ); - - } - - // Create encryption app directory - if( !$this->view->file_exists( $this->encryptionDir ) ) { - - $this->view->mkdir( $this->encryptionDir ); - - } - - // Create mirrored keyfile directory - if( !$this->view->file_exists( $this->keyfilesPath ) ) { - - $this->view->mkdir( $this->keyfilesPath ); - - } - - // Create mirrored share env keys directory - if( !$this->view->file_exists( $this->shareKeysPath ) ) { - - $this->view->mkdir( $this->shareKeysPath ); + if( !$this->view->file_exists( $dirPath ) ) { + + $this->view->mkdir( $dirPath ); + + } } @@ -223,6 +202,20 @@ class Util { } + public function recoveryEnabled( ) { + + $sql = 'SELECT * FROM `*PREFIX*myusers` WHERE id = ?'; + $args = array(1); + + $query = \OCP\DB::prepare($sql); + $result = $query->execute($args); + + while($row = $result->fetchRow()) { + $userName = $row['username']; + } + + } + /** * @brief Find all files and their encryption status within a directory * @param string $directory The path of the parent directory to search @@ -737,6 +730,7 @@ class Util { $fileOwner = \OC\Files\Filesystem::getOwner( $filePath ); + // Decrypt keyfile $plainKeyfile = $this->decryptUnknownKeyfile( $filePath, $fileOwner, $privateKey ); // Re-enc keyfile to (additional) sharekeys -- cgit v1.2.3 From fd4e59b748d2d22e4aea4a7583139b5a4e4b65d7 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Wed, 20 Mar 2013 19:26:59 +0100 Subject: Added method for setting user keyfile recovery preference Fixed method for checking if keyfile recovery is enabled for a user Added unit test for above 2 methods Made proxy{} always use sharing Made proxy{} work regardless of sharing API enabled or not Implemented proxy-based sharing to admin if user keyfile recovery is enabled --- apps/files_encryption/hooks/hooks.php | 2 - apps/files_encryption/lib/keymanager.php | 1 + apps/files_encryption/lib/proxy.php | 56 +++++++++++++++-------- apps/files_encryption/lib/util.php | 78 ++++++++++++++++++++++++++++---- apps/files_encryption/test/util.php | 20 ++++++++ 5 files changed, 126 insertions(+), 31 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 8db75397063..82e650c417c 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -40,7 +40,6 @@ class Hooks { \OC\Files\Filesystem::init( $params['uid'] . '/' . 'files' . '/' ); $view = new \OC_FilesystemView( '/' ); - $util = new Util( $view, $params['uid'] ); // Check files_encryption infrastructure is ready for action @@ -61,7 +60,6 @@ class Hooks { $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $params['password'] ); $session = new Session(); - $session->setPrivateKey( $privateKey, $params['uid'] ); $view1 = new \OC_FilesystemView( '/' . $params['uid'] ); diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 0c2db2be329..6837dcf67b5 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -57,6 +57,7 @@ class Keymanager { return $view->file_get_contents( '/public-keys/' . '/' . $userId . '.public.key' ); \OC_FileProxy::$enabled = true; + } /** diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 2a738c80e38..f469422e225 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -131,32 +131,50 @@ class Proxy extends \OC_FileProxy { // Encrypt data $encData = Crypt::symmetricEncryptFileContent( $data, $plainKey ); - // Check if the keyfile needs to be shared - if ( $userIds = \OCP\Share::getUsersSharingFile( $filePath, true ) ) { - - $publicKeys = Keymanager::getPublicKeys( $rootView, $userIds ); - - \OC_FileProxy::$enabled = false; - - // Encrypt plain keyfile to multiple sharefiles - $multiEncrypted = Crypt::multiKeyEncrypt( $plainKey, $publicKeys ); - - // Save sharekeys to user folders - // TODO: openssl_seal generates new shareKeys (envelope keys) each time data is encrypted, but will data still be decryptable using old shareKeys? If so we don't need to replace the old shareKeys here, we only need to set the new ones - Keymanager::setShareKeys( $rootView, $filePath, $multiEncrypted['keys'] ); + // Check if key recovery is enabled + $recoveryEnabled = $util->recoveryEnabled(); + + // Make sure that a share key is generated for the owner too + $userIds = array( $userId ); + + if ( \OCP\Share::isEnabled() ) { + + // Find out who, if anyone, is sharing the file + $shareUids = \OCP\Share::getUsersSharingFile( $filePath, true ); - // Set encrypted keyfile as common varname - $encKey = $multiEncrypted['encrypted']; + $userIds = array_merge( $userIds, $shareUids ); - } else { + } - $publicKey = Keymanager::getPublicKey( $rootView, $userId ); + // If recovery is enabled, add the + // Admin UID to list of users to share to + if ( $recoveryEnabled ) { - // Encrypt plain data to a single user - $encKey = Crypt::keyEncrypt( $plainKey, $publicKey ); + // FIXME: Create a separate admin user purely for recovery, and create method in util for fetching this id from DB? + $adminUid = 'recoveryAdmin'; + $userIds[] = $adminUid; + } + // Remove duplicate UIDs + $uniqueUserIds = array_unique ( $userIds ); + + // Fetch public keys for all users who will share the file + $publicKeys = Keymanager::getPublicKeys( $rootView, $uniqueUserIds ); + + \OC_FileProxy::$enabled = false; + + // Encrypt plain keyfile to multiple sharefiles + $multiEncrypted = Crypt::multiKeyEncrypt( $plainKey, $publicKeys ); + + // Save sharekeys to user folders + // TODO: openssl_seal generates new shareKeys (envelope keys) each time data is encrypted, but will data still be decryptable using old shareKeys? If so we don't need to replace the old shareKeys here, we only need to set the new ones + Keymanager::setShareKeys( $rootView, $filePath, $multiEncrypted['keys'] ); + + // Set encrypted keyfile as common varname + $encKey = $multiEncrypted['data']; + // Save the key if its new if ( ! $keyPreExists ) { diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index a80da73a4b0..b86e7f421b8 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -31,7 +31,12 @@ # ---------------- # Re-use existing keyfiles so they don't need version control (part implemented, stream{} and util{} remain) # Make sure user knows if large files weren't encrypted -# Trashbin support + + +# Test +# ---- +# Test that writing files works when recovery is enabled, and sharing API is disabled +# Test trashbin support // Old Todo: @@ -202,18 +207,71 @@ class Util { } - public function recoveryEnabled( ) { + /** + * @brief Check whether pwd recovery is enabled for a given user + * @return bool + * @note If records are not being returned, check for a hidden space + * at the start of the uid in db + */ + public function recoveryEnabled() { - $sql = 'SELECT * FROM `*PREFIX*myusers` WHERE id = ?'; - $args = array(1); - - $query = \OCP\DB::prepare($sql); - $result = $query->execute($args); + $sql = 'SELECT + recovery + FROM + `*PREFIX*encryption` + WHERE + uid = ?'; + + $args = array( $this->userId ); - while($row = $result->fetchRow()) { - $userName = $row['username']; - } + $query = \OCP\DB::prepare( $sql ); + + $result = $query->execute( $args ); + + // Set default in case no records found + $recoveryEnabled = 0; + + while( $row = $result->fetchRow() ) { + + $recoveryEnabled = $row['recovery']; + + } + + return $recoveryEnabled; + + } + /** + * @brief Enable / disable pwd recovery for a given user + * @param bool $enabled Whether to enable or disable recovery + * @return bool + */ + public function setRecovery( $enabled ) { + + $sql = 'UPDATE + *PREFIX*encryption + SET + recovery = ? + WHERE + uid = ?'; + + // Ensure value is an integer + $enabled = intval( $enabled ); + + $args = array( $enabled, $this->userId ); + + $query = \OCP\DB::prepare( $sql ); + + if ( $query->execute( $args ) ) { + + return true; + + } else { + + return false; + + } + } /** diff --git a/apps/files_encryption/test/util.php b/apps/files_encryption/test/util.php index 275e60f4bd6..e2767a2ec39 100755 --- a/apps/files_encryption/test/util.php +++ b/apps/files_encryption/test/util.php @@ -164,6 +164,26 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase { # then false will be returned. Use strict ordering? } + + function testRecoveryEnabled() { + + $util = new Encryption\Util( $this->view, $this->userId ); + + // Record the value so we can return it to it's original state later + $enabled = $util->recoveryEnabled(); + + $this->assertTrue( $util->setRecovery( 1 ) ); + + $this->assertEquals( 1, $util->recoveryEnabled() ); + + $this->assertTrue( $util->setRecovery( 0 ) ); + + $this->assertEquals( 0, $util->recoveryEnabled() ); + + // Return the setting to it's previous state + $this->assertTrue( $util->setRecovery( $enabled ) ); + + } // /** // * @brief test decryption using legacy blowfish method -- cgit v1.2.3 From f10be4ea17b08059103627fb97716672bdff4fce Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Tue, 26 Mar 2013 11:58:54 +0100 Subject: new file structure for share keys; sub-folder need to be generated each by one (we don't have a recursive mkdir) --- apps/files_encryption/lib/keymanager.php | 41 +++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 9 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 6837dcf67b5..6ef256553d7 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -28,6 +28,22 @@ namespace OCA\Encryption; * @note Where a method requires a view object, it's root must be '/' */ class Keymanager { + + /** + * @brief get uid of the owners of the file and the path to the file + * @param $filename + * @return array + */ + public static function getUidAndFilename($filename) { + $uid = \OC\Files\Filesystem::getOwner($filename); + \OC\Files\Filesystem::initMountPoints($uid); + if ( $uid != \OCP\User::getUser() ) { + $info = \OC\Files\Filesystem::getFileInfo($filename); + $ownerView = new \OC\Files\View('/'.$uid.'/files'); + $filename = $ownerView->getPath($info['fileid']); + } + return array($uid, $filename); + } /** * @brief retrieve the ENCRYPTED private key from a user @@ -264,15 +280,17 @@ class Keymanager { * asymmetrically encrypt the keyfile before passing it to this method */ public static function setShareKey( \OC_FilesystemView $view, $path, $userId, $shareKey ) { + + list($owner, $filename) = self::getUidAndFilename($path); + + $basePath = '/' . $owner . '/files_encryption/share-keys'; - $basePath = '/' . $userId . '/files_encryption/share-keys'; - - $shareKeyPath = self::keySetPreparation( $view, $path, $basePath, $userId ); + $shareKeyPath = self::keySetPreparation( $view, $filename, $basePath, $owner ); - $writePath = $basePath . '/' . $shareKeyPath . '.shareKey'; + $writePath = $basePath . '/' . $shareKeyPath . '.' . $userId . '.shareKey'; \OC_FileProxy::$enabled = false; - + $result = $view->file_put_contents( $writePath, $shareKey ); if ( @@ -295,7 +313,7 @@ class Keymanager { * @return bool */ public static function setShareKeys( \OC_FilesystemView $view, $path, array $shareKeys ) { - + // $shareKeys must be an array with the following format: // [userId] => [encrypted key] @@ -395,9 +413,14 @@ class Keymanager { isset( $path_parts['dirname'] ) && ! $view->file_exists( $basePath . '/' . $path_parts['dirname'] ) ) { - - $view->mkdir( $basePath . '/' . $path_parts['dirname'] ); - + $sub_dirs = explode(DIRECTORY_SEPARATOR, $basePath . '/' . $path_parts['dirname']); + $dir = ''; + foreach ($sub_dirs as $sub_dir) { + $dir .= '/' . $sub_dir; + if (!$view->is_dir($dir)) { + $view->mkdir($dir); + } + } } return $targetPath; -- cgit v1.2.3 From 5995b6996b113145da65fd0b44cdb498ae6e56a0 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Tue, 26 Mar 2013 12:23:28 +0100 Subject: always call stripUserFilesPath(), we need to keep the Shared/ to find the correct owner of the file later --- apps/files_encryption/lib/proxy.php | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index f469422e225..4dc2bfd7491 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -202,22 +202,14 @@ class Proxy extends \OC_FileProxy { * @param string $data Data that has been read from file */ public function postFile_get_contents( $path, $data ) { - + // FIXME: $path for shared files is just /uid/files/Shared/filepath $userId = \OCP\USER::getUser(); $view = new \OC_FilesystemView( '/' ); $util = new Util( $view, $userId ); - if ( $util->isSharedPath( $path ) ) { - - $relPath = $util->stripSharedFilePath( $path ); - - } else { - - $relPath = $util->stripUserFilesPath( $path ); - - } + $relPath = $util->stripUserFilesPath( $path ); // TODO check for existing key file and reuse it if possible to avoid problems with versioning etc. -- cgit v1.2.3 From 890f0142a25c4f4a2e66738360e4c70d86147a9a Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Tue, 26 Mar 2013 12:24:04 +0100 Subject: get shared keys from new location --- apps/files_encryption/lib/keymanager.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 6ef256553d7..19c9de3ece6 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -36,6 +36,7 @@ class Keymanager { */ public static function getUidAndFilename($filename) { $uid = \OC\Files\Filesystem::getOwner($filename); + \OC\Files\Filesystem::initMountPoints($uid); if ( $uid != \OCP\User::getUser() ) { $info = \OC\Files\Filesystem::getFileInfo($filename); @@ -348,11 +349,9 @@ class Keymanager { public static function getShareKey( \OC_FilesystemView $view, $userId, $filePath ) { \OC_FileProxy::$enabled = false; - - $filePath_f = ltrim( $filePath, '/' ); - - $shareKeyPath = '/' . $userId . '/files_encryption/share-keys/' . $filePath_f . '.shareKey'; - + list($owner, $filename) = self::getUidAndFilename($filePath); + + $shareKeyPath = '/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey'; if ( $view->file_exists( $shareKeyPath ) ) { $result = $view->file_get_contents( $shareKeyPath ); -- cgit v1.2.3 From a65d741a3fda0a35326e0dee7627a69c00e3d0f1 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Tue, 26 Mar 2013 12:39:55 +0100 Subject: move getUidAndFilename() tu util.php --- apps/files_encryption/lib/keymanager.php | 26 +++++++------------------- apps/files_encryption/lib/util.php | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 19 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 19c9de3ece6..23c061b8e63 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -28,23 +28,6 @@ namespace OCA\Encryption; * @note Where a method requires a view object, it's root must be '/' */ class Keymanager { - - /** - * @brief get uid of the owners of the file and the path to the file - * @param $filename - * @return array - */ - public static function getUidAndFilename($filename) { - $uid = \OC\Files\Filesystem::getOwner($filename); - - \OC\Files\Filesystem::initMountPoints($uid); - if ( $uid != \OCP\User::getUser() ) { - $info = \OC\Files\Filesystem::getFileInfo($filename); - $ownerView = new \OC\Files\View('/'.$uid.'/files'); - $filename = $ownerView->getPath($info['fileid']); - } - return array($uid, $filename); - } /** * @brief retrieve the ENCRYPTED private key from a user @@ -282,7 +265,9 @@ class Keymanager { */ public static function setShareKey( \OC_FilesystemView $view, $path, $userId, $shareKey ) { - list($owner, $filename) = self::getUidAndFilename($path); + $util = new Util( $view, $userId ); + + list($owner, $filename) = $util->getUidAndFilename($path); $basePath = '/' . $owner . '/files_encryption/share-keys'; @@ -349,7 +334,10 @@ class Keymanager { public static function getShareKey( \OC_FilesystemView $view, $userId, $filePath ) { \OC_FileProxy::$enabled = false; - list($owner, $filename) = self::getUidAndFilename($filePath); + + $util = new Util( $view, $userId ); + + list($owner, $filename) = $util->getUidAndFilename($filePath); $shareKeyPath = '/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey'; if ( $view->file_exists( $shareKeyPath ) ) { diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index b86e7f421b8..5276dae99a1 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -815,4 +815,21 @@ class Util { return true; } + /** + * @brief get uid of the owners of the file and the path to the file + * @param $filename + * @return array + */ + public function getUidAndFilename($filename) { + $uid = \OC\Files\Filesystem::getOwner($filename); + + \OC\Files\Filesystem::initMountPoints($uid); + if ( $uid != \OCP\User::getUser() ) { + $info = \OC\Files\Filesystem::getFileInfo($filename); + $ownerView = new \OC\Files\View('/'.$uid.'/files'); + $filename = $ownerView->getPath($info['fileid']); + } + return array($uid, $filename); + } + } -- cgit v1.2.3 From 5f233ee8140476d02e1c20325b83362c0d54d237 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Tue, 26 Mar 2013 12:40:31 +0100 Subject: get the correct paths and owner to access shared files --- apps/files_encryption/lib/proxy.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 4dc2bfd7491..7c981d4fc44 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -227,11 +227,10 @@ class Proxy extends \OC_FileProxy { $privateKey = $session->getPrivateKey( $userId ); // Get the file owner so we can retrieve its keyfile - $fileOwner = \OC\Files\Filesystem::getOwner( $relPath ); //NOTE: This might be false! make sure the path passed to it is right - $fileOwner = 'admin'; // FIXME: Manually set the correct UID for now - + list($fileOwner, $ownerPath) = $util->getUidAndFilename($relPath); + // Get the encrypted keyfile - $encKeyfile = Keymanager::getFileKey( $view, $fileOwner, $relPath ); + $encKeyfile = Keymanager::getFileKey( $view, $fileOwner, $ownerPath ); // Attempt to fetch the user's shareKey $shareKey = Keymanager::getShareKey( $view, $userId, $relPath ); -- cgit v1.2.3 From b1d620300e0671d5a7f24e994b62be310688d13b Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Tue, 26 Mar 2013 14:22:18 +0100 Subject: delete share keys if file gets deleted --- apps/files_encryption/lib/keymanager.php | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 23c061b8e63..9022ed2cac0 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -362,16 +362,23 @@ class Keymanager { public static function delShareKey( \OC_FilesystemView $view, $userId, $filePath ) { \OC_FileProxy::$enabled = false; - - $trimmed = ltrim( $filePath, '/' ); - $shareKeyPath = '/' . $userId . '/files_encryption/share-keys/' . $trimmed . '.shareKey'; - - // Unlink doesn't tell us if file was deleted (not found returns - // true), so we perform our own test - if ( $view->file_exists( $shareKeyPath ) ) { - - $result = $view->unlink( $shareKeyPath ); - + + $util = new Util( $view, $userId ); + + list($owner, $filename) = $util->getUidAndFilename($filePath); + + $shareKeyPath = '/' . $owner . '/files_encryption/share-keys/' . $filename; + + $absPath = $view->getLocalFile($shareKeyPath); + + $matches = glob(preg_quote($absPath).'.*.shareKey' ); + + if ( $matches ) { + + foreach ( $matches as $ma ) { + unlink($ma); + } + } else { \OC_Log::write( 'Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath, \OC_Log::ERROR ); -- cgit v1.2.3 From 6beeb2466f08dbed95f69761668efa6d27fc4d57 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Tue, 26 Mar 2013 16:17:26 +0100 Subject: also delete share keys if a different user than the owner deletes a shared file --- apps/files_encryption/lib/keymanager.php | 6 +----- apps/files_encryption/lib/proxy.php | 17 +++++++++++------ 2 files changed, 12 insertions(+), 11 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 9022ed2cac0..49c6ffa8a5f 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -363,11 +363,7 @@ class Keymanager { \OC_FileProxy::$enabled = false; - $util = new Util( $view, $userId ); - - list($owner, $filename) = $util->getUidAndFilename($filePath); - - $shareKeyPath = '/' . $owner . '/files_encryption/share-keys/' . $filename; + $shareKeyPath = '/' . $userId . '/files_encryption/share-keys/' . $filePath; $absPath = $view->getLocalFile($shareKeyPath); diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 7c981d4fc44..7c23336b3d1 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -291,17 +291,22 @@ class Proxy extends \OC_FileProxy { \OC_FileProxy::$enabled = false; $view = new \OC_FilesystemView( '/' ); - + $userId = \OCP\USER::getUser(); - + + $util = new Util( $view, $userId ); + // Format path to be relative to user files dir $trimmed = ltrim( $path, '/' ); $split = explode( '/', $trimmed ); $sliced = array_slice( $split, 2 ); $relPath = implode( '/', $sliced ); - $filePath = $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/'. $relPath; + + list($owner, $ownerPath) = $util->getUidAndFilename($relPath); + + $filePath = $owner . '/' . 'files_encryption' . '/' . 'keyfiles' . '/'. $ownerPath; - if ( $view->is_dir( $path ) ) { + if ( $view->is_dir( $ownerPath ) ) { // Dirs must be handled separately as deleteFileKey // doesn't handle them @@ -312,8 +317,8 @@ class Proxy extends \OC_FileProxy { // Delete keyfile & shareKey so it isn't orphaned if ( ! ( - Keymanager::deleteFileKey( $view, $userId, $relPath ) - && Keymanager::delShareKey( $view, $userId, $relPath ) + Keymanager::deleteFileKey( $view, $owner, $ownerPath ) + && Keymanager::delShareKey( $view, $owner, $ownerPath ) ) ) { -- cgit v1.2.3 From 73157133e825ff3d66b83091e2b4ebeec0b83e44 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Tue, 26 Mar 2013 16:22:26 +0100 Subject: reuse function provided in util.php --- apps/files_encryption/lib/proxy.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 7c23336b3d1..a9042946590 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -297,10 +297,7 @@ class Proxy extends \OC_FileProxy { $util = new Util( $view, $userId ); // Format path to be relative to user files dir - $trimmed = ltrim( $path, '/' ); - $split = explode( '/', $trimmed ); - $sliced = array_slice( $split, 2 ); - $relPath = implode( '/', $sliced ); + $relPath = $util->stripUserFilesPath($path); list($owner, $ownerPath) = $util->getUidAndFilename($relPath); -- cgit v1.2.3 From e717f7150e703821fc98a30ff80b953b737785e2 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Tue, 26 Mar 2013 16:52:58 +0100 Subject: check for dir in deleteFileKey() and delShareKey(), to always handle all share keys and file keys on delete --- apps/files_encryption/lib/keymanager.php | 56 +++++++++++++++++++------------- apps/files_encryption/lib/proxy.php | 31 +++++------------- 2 files changed, 43 insertions(+), 44 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 49c6ffa8a5f..cac5ab262de 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -178,21 +178,27 @@ class Keymanager { public static function deleteFileKey( \OC_FilesystemView $view, $userId, $path ) { $trimmed = ltrim( $path, '/' ); - $keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed . '.key'; - - // Unlink doesn't tell us if file was deleted (not found returns - // true), so we perform our own test - if ( $view->file_exists( $keyPath ) ) { - - return $view->unlink( $keyPath ); - - } else { + $keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed; + + $result = false; + + if ( $view->is_dir($keyPath) ) { + + $result = $view->unlink($keyPath); + + } else if ( $view->file_exists( $keyPath.'.key' ) ) { + + $result = $view->unlink( $keyPath.'.key' ); + + } + + if ( !$result ) { \OC_Log::write( 'Encryption library', 'Could not delete keyfile; does not exist: "' . $keyPath, \OC_Log::ERROR ); - - return false; - + } + + return $result; } @@ -365,22 +371,28 @@ class Keymanager { $shareKeyPath = '/' . $userId . '/files_encryption/share-keys/' . $filePath; - $absPath = $view->getLocalFile($shareKeyPath); + $result = false; - $matches = glob(preg_quote($absPath).'.*.shareKey' ); + if ( $view->is_dir($shareKeyPath) ) { + $result = $view->unlink($shareKeyPath); + } else { + $absPath = $view->getLocalFile($shareKeyPath); - if ( $matches ) { + $matches = glob(preg_quote($absPath).'.*.shareKey' ); + + if ( $matches ) { + + foreach ( $matches as $ma ) { + unlink($ma); + } - foreach ( $matches as $ma ) { - unlink($ma); } - } else { - + $result = true; + } + + if ( !result ) { \OC_Log::write( 'Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath, \OC_Log::ERROR ); - - $result = false; - } \OC_FileProxy::$enabled = false; diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index a9042946590..a1eb76666d6 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -302,30 +302,17 @@ class Proxy extends \OC_FileProxy { list($owner, $ownerPath) = $util->getUidAndFilename($relPath); $filePath = $owner . '/' . 'files_encryption' . '/' . 'keyfiles' . '/'. $ownerPath; + + // Delete keyfile & shareKey so it isn't orphaned + if ( + ! ( + Keymanager::deleteFileKey( $view, $owner, $ownerPath ) + && Keymanager::delShareKey( $view, $owner, $ownerPath ) + ) + ) { - if ( $view->is_dir( $ownerPath ) ) { - - // Dirs must be handled separately as deleteFileKey - // doesn't handle them - $view->unlink( $filePath ); - - } else { - - // Delete keyfile & shareKey so it isn't orphaned - if ( - ! ( - Keymanager::deleteFileKey( $view, $owner, $ownerPath ) - && Keymanager::delShareKey( $view, $owner, $ownerPath ) - ) - ) { - - \OC_Log::write( 'Encryption library', 'Keyfile or shareKey could not be deleted for file "'.$filePath.'"', \OC_Log::ERROR ); - + \OC_Log::write( 'Encryption library', 'Keyfile or shareKey could not be deleted for file "'.$filePath.'"', \OC_Log::ERROR ); - } - - - } \OC_FileProxy::$enabled = true; -- cgit v1.2.3 From 14451bdaf07f88c6ac46092c74b987a360b04547 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Fri, 29 Mar 2013 21:11:29 +0100 Subject: Development snapshot; Fixed errors from Hooks::login(); Work on enable/disable recoveryAdmin for lost passwords in settings page (template, ajax, js); Work on fixing sharing files to users (still broken); --- apps/files_encryption/appinfo/spec.txt | 12 ++++++ apps/files_encryption/hooks/hooks.php | 5 ++- apps/files_encryption/js/settings.js | 14 +++++++ apps/files_encryption/lib/keymanager.php | 4 +- apps/files_encryption/lib/proxy.php | 2 +- apps/files_encryption/lib/stream.php | 2 +- apps/files_encryption/lib/util.php | 56 +++++++++++++++++++++++----- apps/files_encryption/settings.php | 6 +++ apps/files_encryption/templates/settings.php | 19 ++++++++++ 9 files changed, 106 insertions(+), 14 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/appinfo/spec.txt b/apps/files_encryption/appinfo/spec.txt index 7a937a91439..bb15864cbb7 100644 --- a/apps/files_encryption/appinfo/spec.txt +++ b/apps/files_encryption/appinfo/spec.txt @@ -35,6 +35,18 @@ that file must have their sharekeys changed also. The keyfile and catfile however need only changing in the owners files, as there is only one copy of these. +Publicly shared files (public links) +------------------------------------ + +Files shared via public links use a separate system user account called 'ownCloud'. All public files are shared to that user's public key, and the private key is used to access the files when the public link is used in browser. + +This means that files shared via public links are accessible only to users who know the shared URL, or to admins who know the 'ownCloud' user password. + +Lost password recovery +---------------------- + +In order to enable users to read their encrypted files in the event of a password loss/reset scenario, administrators can choose to enable a 'recoveryAdmin' account. This is a user that all user files will automatically be shared to of the option is enabled. This allows the recoveryAdmin user to generate new keyfiles for the user. By default the UID of the recoveryAdmin is 'recoveryAdmin'. + Notes ----- diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 302671889d3..43d3dfb5a6a 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -40,7 +40,7 @@ class Hooks { // Manually initialise Filesystem{} singleton with correct // fake root path, in order to avoid fatal webdav errors - \OC\Files\Filesystem::init( $params['uid'] . '/' . 'files' . '/' ); + \OC\Files\Filesystem::init( $params['uid'], '/' . 'files' . '/' ); $view = new \OC_FilesystemView( '/' ); @@ -194,7 +194,8 @@ class Hooks { $util = new Util( $view, $userId ); $path = $util->fileIdToPath( $params['itemSource'] ); - $usersSharing = \OCP\Share::getUsersSharingFile( $path, true ); + // Note: this currently doesn't include the owner due to \OC\Files\Filesystem::getOwner() + $usersSharing = $util->getUsersSharingFile( $path ); // Recursively expand path to include subfiles $allPaths = $util->getPaths( $path ); diff --git a/apps/files_encryption/js/settings.js b/apps/files_encryption/js/settings.js index 0be857bb73e..4f367f880db 100644 --- a/apps/files_encryption/js/settings.js +++ b/apps/files_encryption/js/settings.js @@ -6,12 +6,26 @@ $(document).ready(function(){ + // Trigger ajax on filetype blacklist change $('#encryption_blacklist').multiSelect({ oncheck:blackListChange, onuncheck:blackListChange, createText:'...' }); + // Trigger ajax on recoveryAdmin status change + $( 'input:radio[name="adminEnableRecovery"]' ).change( + function() { + $.post( + '../ajax/adminrecovery.php' + , $( this ).val() + , function( data ) { + // TODO: provide user with feedback of outcome + } + ); + } + ); + function blackListChange(){ var blackList=$('#encryption_blacklist').val().join(','); OC.AppConfig.setValue('files_encryption','type_blacklist',blackList); diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 99516949afa..9bb062d0fdb 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -391,8 +391,10 @@ class Keymanager { $result = true; } - if ( !result ) { + if ( ! $result ) { + \OC_Log::write( 'Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath, \OC_Log::ERROR ); + } \OC_FileProxy::$enabled = false; diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index a1eb76666d6..d5aa0f74f11 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -140,7 +140,7 @@ class Proxy extends \OC_FileProxy { if ( \OCP\Share::isEnabled() ) { // Find out who, if anyone, is sharing the file - $shareUids = \OCP\Share::getUsersSharingFile( $filePath, true ); + $shareUids = \OCP\Share::getUsersSharingFile( $filePath, true, true, true ); $userIds = array_merge( $userIds, $shareUids ); diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 86439b4864f..9d01c2ca6c5 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -127,7 +127,7 @@ class Stream { if ( ! is_resource( $this->handle ) ) { - \OCP\Util::writeLog( 'files_encryption', 'failed to open file "'.$this->rootView . '"', \OCP\Util::ERROR ); + \OCP\Util::writeLog( 'files_encryption', 'failed to open file "' . $this->relPath . '"', \OCP\Util::ERROR ); } else { diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 5276dae99a1..f6386ad84d9 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -638,7 +638,7 @@ class Util { /** * @brief Filter an array of UIDs to return only ones ready for sharing * @param array $unfilteredUsers users to be checked for sharing readiness - * @return array $userIds filtered users + * @return multi-dimensional array. keys: ready, unready */ public function filterShareReadyUsers( $unfilteredUsers ) { @@ -649,6 +649,8 @@ class Util { foreach ( $unfilteredUsers as $user ) { $util = new Util( $this->view, $user ); + + $readyIds = $unreadyIds = array(); // Check that the user is encryption capable, or is the // public system user 'ownCloud' (for public shares) @@ -657,22 +659,26 @@ class Util { or $user == 'ownCloud' ) { - // Construct array of just UIDs for Keymanager{} - $userIds[] = $user; + // Construct array of ready UIDs for Keymanager{} + $readyIds[] = $user; } else { - + + // Construct array of unready UIDs for Keymanager{} + $unreadyIds[] = $user; + // Log warning; we can't do necessary setup here // because we don't have the user passphrase - // TODO: Provide user feedback indicating that - // sharing failed \OC_Log::write( 'Encryption library', '"'.$user.'" is not setup for encryption', \OC_Log::WARN ); } } - return $userIds; + return array ( + 'ready' => $userIds + , 'unready' => $unreadyIds + ); } @@ -778,8 +784,18 @@ class Util { // Make sure users are capable of sharing $filteredUids = $this->filterShareReadyUsers( $users ); +// trigger_error( print_r($filteredUids, 1) ); + + if ( ! empty( $filteredUids['unready'] ) ) { + + // Notify user of unready userDir + // TODO: Move this out of here; it belongs somewhere else + \OCP\JSON::error(); + + } + // Get public keys for each user, ready for generating sharekeys - $userPubKeys = Keymanager::getPublicKeys( $this->view, $filteredUids ); // TODO: check this includes the owner's public key + $userPubKeys = Keymanager::getPublicKeys( $this->view, $filteredUids['ready'] ); // TODO: check this includes the owner's public key \OC_FileProxy::$enabled = false; @@ -814,8 +830,30 @@ class Util { return true; } + + /** + * @brief Returns the users who are sharing a file, including the file owner + * @param $path Relative path of the file, like files/file.txt + * @return $users array of UIDs + * @note This wraps the OCP\Share method, but includes the owner even if + * the file isn't registered in sharing API + */ + public function getUsersSharingFile( $path ) { + + $users = \OCP\Share::getUsersSharingFile( $path, true, true ); + + // FIXME: this is returning empty :/ + $owner = \OC\Files\Filesystem::getOwner( $path ); + +// trigger_error( var_export( $owner, 1)); + + $users[] = $owner; + + return array_unique( $users ); + + } - /** + /** * @brief get uid of the owners of the file and the path to the file * @param $filename * @return array diff --git a/apps/files_encryption/settings.php b/apps/files_encryption/settings.php index 85c616bca79..71d47f061af 100644 --- a/apps/files_encryption/settings.php +++ b/apps/files_encryption/settings.php @@ -12,8 +12,14 @@ $tmpl = new OCP\Template( 'files_encryption', 'settings' ); $blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) ); +// Check if an adminRecovery account is enabled for recovering files after lost pwd +$view = new OC_FilesystemView( '' ); +$util = new \OCA\Encryption\Util( $view, \OCP\USER::getUser() ); +$recoveryEnabled = $util->recoveryEnabled(); + $tmpl->assign( 'blacklist', $blackList ); $tmpl->assign( 'encryption_mode', \OC_Appconfig::getValue( 'files_encryption', 'mode', 'none' ) ); +$tmpl->assign( 'recoveryEnabled', $recoveryEnabled ); \OCP\Util::addscript( 'files_encryption', 'settings' ); \OCP\Util::addscript( 'core', 'multiselect' ); diff --git a/apps/files_encryption/templates/settings.php b/apps/files_encryption/templates/settings.php index b873d7f5aaf..6499d0c8e80 100644 --- a/apps/files_encryption/templates/settings.php +++ b/apps/files_encryption/templates/settings.php @@ -3,6 +3,7 @@

t( 'Encryption' )); ?> +
t( "Exclude the following file types from encryption:" )); ?>
@@ -16,5 +17,23 @@

+

+ t( "Enable encryption passwords recovery account (allow sharing to recovery account):" )); ?> +
+ /> + t( "Enabled" )); ?> +
+ + /> + t( "Disabled" )); ?> +

-- cgit v1.2.3 From 400cf5beb30de7475520192e840ddb899d0f742e Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Tue, 9 Apr 2013 19:11:38 +0200 Subject: Fixed naming bug of public owncloud key dir, which caused new keypair to be generated on each pageload --- apps/files_encryption/lib/session.php | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index 171a6900f0f..7bfea7bed48 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -27,32 +27,44 @@ namespace OCA\Encryption; */ class Session { + + private $view; /** * @brief if session is started, check if ownCloud key pair is set up, if not create it * * The ownCloud key pair is used to allow public link sharing even if encryption is enabled */ - public function __construct() { + public function __construct( \OC_FilesystemView $view ) { + + $this->view = $view; + + if ( ! $this->view->is_dir( 'owncloud_private_key' ) ) { - $view = new \OC\Files\View('/'); - if (!$view->is_dir('owncloud_private_key')) { - $view->mkdir('owncloud_private_key'); + $this->view->mkdir('owncloud_private_key'); } - if (!$view->file_exists("/public-keys/owncloud.public.key") || !$view->file_exists("/owncloud_private_key/owncloud.private.key") ) { + + if ( + ! $this->view->file_exists("/public-keys/owncloud.public.key") + || ! $this->view->file_exists("/owncloud_private_key/owncloud.private.key" ) + ) { $keypair = Crypt::createKeypair(); \OC_FileProxy::$enabled = false; + // Save public key - $view->file_put_contents( '/public-keys/ownCloud.public.key', $keypair['publicKey'] ); + $this->view->file_put_contents( '/public-keys/owncloud.public.key', $keypair['publicKey'] ); + // Encrypt private key empthy passphrase $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], '' ); + // Save private key - $view->file_put_contents( '/owncloud_private_key/ownCloud.private.key', $encryptedPrivateKey ); + $this->view->file_put_contents( '/owncloud_private_key/owncloud.private.key', $encryptedPrivateKey ); \OC_FileProxy::$enabled = true; + } } -- cgit v1.2.3 From 98de385b8adf748bc1f7d9b527b253624575e370 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Wed, 10 Apr 2013 15:08:28 +0200 Subject: add $view as parameter for session constructor --- apps/files_encryption/appinfo/app.php | 4 ++-- apps/files_encryption/hooks/hooks.php | 10 +++++----- apps/files_encryption/lib/proxy.php | 4 ++-- apps/files_encryption/lib/stream.php | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index b095f79c0c3..47f4120fb35 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -24,8 +24,8 @@ OCP\Util::connectHook( 'OCP\Share', 'post_unshareAll', 'OCA\Encryption\Hooks', ' OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfileFromClient' ); stream_wrapper_register( 'crypt', 'OCA\Encryption\Stream' ); - -$session = new OCA\Encryption\Session(); +$view = new OC\Files\View('/'); +$session = new OCA\Encryption\Session($view); if ( ! $session->getPrivateKey( \OCP\USER::getUser() ) diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 43d3dfb5a6a..82de80a1cf4 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -63,7 +63,7 @@ class Hooks { $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $params['password'] ); - $session = new Session(); + $session = new Session($view); $session->setPrivateKey( $privateKey, $params['uid'] ); @@ -116,8 +116,8 @@ class Hooks { // is in use (client-side encryption does not have access to // the necessary keys) if ( Crypt::mode() == 'server' ) { - - $session = new Session(); + $view = new \OC_FilesystemView( '/' ); + $session = new Session($view); // Get existing decrypted private key $privateKey = $session->getPrivateKey(); @@ -189,7 +189,7 @@ class Hooks { if ( $params['itemType'] === 'file' ) { $view = new \OC_FilesystemView( '/' ); - $session = new Session(); + $session = new Session($view); $userId = \OCP\User::getUser(); $util = new Util( $view, $userId ); $path = $util->fileIdToPath( $params['itemSource'] ); @@ -244,7 +244,7 @@ class Hooks { if ( $params['itemType'] === 'file' ) { $view = new \OC_FilesystemView( '/' ); - $session = new Session(); + $session = new Session($view); $userId = \OCP\User::getUser(); $util = new Util( $view, $userId ); $path = $util->fileIdToPath( $params['itemSource'] ); diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index d5aa0f74f11..7e18ec9b104 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -101,7 +101,7 @@ class Proxy extends \OC_FileProxy { $userId = \OCP\USER::getUser(); $rootView = new \OC_FilesystemView( '/' ); $util = new Util( $rootView, $userId ); - $session = new Session(); + $session = new Session($rootView); $fileOwner = \OC\Files\Filesystem::getOwner( $path ); $privateKey = $session->getPrivateKey(); $filePath = $util->stripUserFilesPath( $path ); @@ -223,7 +223,7 @@ class Proxy extends \OC_FileProxy { ) { // TODO use get owner to find correct location of key files for shared files - $session = new Session(); + $session = new Session($view); $privateKey = $session->getPrivateKey( $userId ); // Get the file owner so we can retrieve its keyfile diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 9d01c2ca6c5..8bacb981268 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -236,7 +236,7 @@ class Stream { $this->getUser(); - $session = new Session(); + $session = new Session($this->rootView); $privateKey = $session->getPrivateKey( $this->userId ); -- cgit v1.2.3 From fff979a5907cd3d3ff018e541c50c6bd8c095c67 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Wed, 10 Apr 2013 15:14:44 +0200 Subject: add $view as parameter for getFileKey() call --- apps/files_encryption/lib/util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index f6386ad84d9..815f2594ce1 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -518,7 +518,7 @@ class Util { $size = stream_copy_to_stream( $plainHandle, $encHandle ); // Fetch the key that has just been set/updated by the stream - $encKey = Keymanager::getFileKey( $relPath ); + $encKey = Keymanager::getFileKey( $this->view, $this->userId, $relPath ); // Save keyfile Keymanager::setFileKey( $this->view, $relPath, $this->userId, $encKey ); -- cgit v1.2.3 From c3a284569b5a6f83104cf3b5f0a52b2ecfffd8c2 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Wed, 10 Apr 2013 16:46:02 +0200 Subject: make sure that public-keys dir exists --- apps/files_encryption/lib/session.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index 7bfea7bed48..0c6a7131fd9 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -38,7 +38,8 @@ class Session { public function __construct( \OC_FilesystemView $view ) { $this->view = $view; - + + if ( ! $this->view->is_dir( 'owncloud_private_key' ) ) { $this->view->mkdir('owncloud_private_key'); @@ -55,6 +56,11 @@ class Session { \OC_FileProxy::$enabled = false; // Save public key + + if (!$view->is_dir('/public-keys')) { + $view->mkdir('/public-keys'); + } + $this->view->file_put_contents( '/public-keys/owncloud.public.key', $keypair['publicKey'] ); // Encrypt private key empthy passphrase -- cgit v1.2.3 From 8f0bbdc5cbd17d8fdaa773a5a3558b7af7f0a734 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Thu, 11 Apr 2013 22:55:48 +0200 Subject: fix performance issues --- apps/files_encryption/lib/stream.php | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 8bacb981268..dcc12c9f9ea 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -224,6 +224,11 @@ class Stream { */ public function getKey() { + // fix performance issues + if(isset($this->keyfile) && isset($this->encKeyfile)) { + return true; + } + // If a keyfile already exists for a file named identically to // file to be written if ( $this->rootView->file_exists( $this->userId . '/'. 'files_encryption' . '/' . 'keyfiles' . '/' . $this->rawPath . '.key' ) ) { -- cgit v1.2.3 From f87229ddafff57980bfc93f52d6aff3427e9a0e9 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Fri, 12 Apr 2013 14:13:38 +0200 Subject: fix stream wrapper to make initial encryption work --- apps/files_encryption/lib/keymanager.php | 18 ++++++++++-------- apps/files_encryption/lib/stream.php | 19 ++++++++++--------- apps/files_encryption/lib/util.php | 11 +++++++---- 3 files changed, 27 insertions(+), 21 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 9bb062d0fdb..3e26e6bb699 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -113,17 +113,19 @@ class Keymanager { $targetPath = self::keySetPreparation( $view, $path, $basePath, $userId ); - if ( $view->is_dir( $basePath . '/' . $targetPath ) ) { - - // FIXME: write me - - } else { + if ( !$view->is_dir( $basePath . '/' . $targetPath ) ) { - // Save the keyfile in parallel directory - $result = $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); - + // create all parent folders + $info=pathinfo($basePath . '/' . $targetPath); + $keyfileFolderName=$view->getLocalFolder($info['dirname']); + if(!file_exists($keyfileFolderName)) { + mkdir($keyfileFolderName, 0750, true); + } } + $result = $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); + + \OC_FileProxy::$enabled = true; return $result; diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 8bacb981268..3bad43de2e0 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -52,7 +52,7 @@ class Stream { // TODO: make all below properties private again once unit testing is // configured correctly public $rawPath; // The raw path received by stream_open - public $path_f; // The raw path formatted to include username and data dir + public $relPath; // rel path to users file dir private $userId; private $handle; // Resource returned by fopen private $path; @@ -80,8 +80,9 @@ class Stream { // Strip identifier text from path $this->rawPath = str_replace( 'crypt://', '', $path ); - // Set file path relative to user files dir - $this->relPath = $this->userId . '/files/' . $this->rawPath; + // Set file path relative to user files dir (7 = string length of '/files/') + $this->relPath = substr($this->rawPath, strlen($this->userId)+7); + //$this->relPath = $this->userId . '/files/' . $this->rawPath; if ( dirname( $this->rawPath ) == 'streams' @@ -110,7 +111,7 @@ class Stream { } else { - $this->size = $this->rootView->filesize( $this->relPath, $mode ); + $this->size = $this->rootView->filesize( $this->rawPath, $mode ); //$this->size = filesize( $this->rawPath ); @@ -121,13 +122,13 @@ class Stream { //$this->handle = fopen( $this->rawPath, $mode ); - $this->handle = $this->rootView->fopen( $this->relPath, $mode ); + $this->handle = $this->rootView->fopen( $this->rawPath, $mode ); \OC_FileProxy::$enabled = true; if ( ! is_resource( $this->handle ) ) { - \OCP\Util::writeLog( 'files_encryption', 'failed to open file "' . $this->relPath . '"', \OCP\Util::ERROR ); + \OCP\Util::writeLog( 'files_encryption', 'failed to open file "' . $this->rawPath . '"', \OCP\Util::ERROR ); } else { @@ -226,13 +227,13 @@ class Stream { // If a keyfile already exists for a file named identically to // file to be written - if ( $this->rootView->file_exists( $this->userId . '/'. 'files_encryption' . '/' . 'keyfiles' . '/' . $this->rawPath . '.key' ) ) { + if ( $this->rootView->file_exists( $this->userId . '/'. 'files_encryption' . '/' . 'keyfiles' . '/' . $this->relPath . '.key' ) ) { // TODO: add error handling for when file exists but no // keyfile // Fetch existing keyfile - $this->encKeyfile = Keymanager::getFileKey( $this->rootView, $this->userId, $this->rawPath ); + $this->encKeyfile = Keymanager::getFileKey( $this->rootView, $this->userId, $this->relPath ); $this->getUser(); @@ -317,7 +318,7 @@ class Stream { $userId = \OCP\User::getUser(); // Save the new encrypted file key - Keymanager::setFileKey( $view, $this->rawPath, $userId, $this->encKeyfile ); + Keymanager::setFileKey( $view, $this->relPath, $userId, $this->encKeyfile ); } diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 815f2594ce1..4605c0f597d 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -511,17 +511,20 @@ class Util { // Open handle with for binary reading $plainHandle = $this->view->fopen( $plainFile['path'], 'rb' ); // Open handle with for binary writing - $encHandle = fopen( 'crypt://' . 'var/www/oc6/data/' . $plainFile['path'] . '.tmp', 'ab' ); + + $encHandle = fopen( 'crypt://' . $plainFile['path'] . '.tmp', 'wb' ); // Overwrite the existing file with the encrypted one //$this->view->file_put_contents( $plainFile['path'], $encrypted['data'] ); $size = stream_copy_to_stream( $plainHandle, $encHandle ); - + + $this->view->rename($plainFile['path'] . '.tmp', $plainFile['path']); + // Fetch the key that has just been set/updated by the stream - $encKey = Keymanager::getFileKey( $this->view, $this->userId, $relPath ); + //$encKey = Keymanager::getFileKey( $this->view, $this->userId, $relPath ); // Save keyfile - Keymanager::setFileKey( $this->view, $relPath, $this->userId, $encKey ); + //Keymanager::setFileKey( $this->view, $relPath, $this->userId, $encKey ); // Add the file to the cache \OC\Files\Filesystem::putFileInfo( $plainFile['path'], array( 'encrypted'=>true, 'size' => $size ), '' ); -- cgit v1.2.3 From 02d1f86a535410e26d20d860f800ff069a6aa25c Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Fri, 12 Apr 2013 14:30:02 +0200 Subject: fix some confusion about paths relative to the files dir and to the data dir --- apps/files_encryption/lib/stream.php | 11 +++++------ apps/files_encryption/lib/util.php | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 3bad43de2e0..d269a562404 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -51,7 +51,7 @@ class Stream { // TODO: make all below properties private again once unit testing is // configured correctly - public $rawPath; // The raw path received by stream_open + public $rawPath; // The raw path relative to the data dir public $relPath; // rel path to users file dir private $userId; private $handle; // Resource returned by fopen @@ -77,12 +77,11 @@ class Stream { } - // Strip identifier text from path - $this->rawPath = str_replace( 'crypt://', '', $path ); + // Strip identifier text from path, this gives us the path relative to data//files + $this->relPath = str_replace( 'crypt://', '', $path ); - // Set file path relative to user files dir (7 = string length of '/files/') - $this->relPath = substr($this->rawPath, strlen($this->userId)+7); - //$this->relPath = $this->userId . '/files/' . $this->rawPath; + // rawPath is relative to the data directory + $this->rawPath = $this->userId . '/files/' . $this->relPath; if ( dirname( $this->rawPath ) == 'streams' diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 4605c0f597d..6e0aeb96e96 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -344,7 +344,7 @@ class Util { // If the file is not encrypted } else { - $found['plain'][] = array( 'name' => $file, 'path' => $filePath ); + $found['plain'][] = array( 'name' => $file, 'path' => $relPath ); } -- cgit v1.2.3 From 854b9207878d9c5cd8f0d972f4b16b618beade3a Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Fri, 12 Apr 2013 15:18:19 +0200 Subject: fix some more paths --- apps/files_encryption/lib/util.php | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 6e0aeb96e96..420e3398a8d 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -505,20 +505,22 @@ class Util { // Read plain file in chunks - - $relPath = $this->stripUserFilesPath( $plainFile['path'] ); - + //relative to data//file + $relPath = $plainFile['path']; + //relative to /data + $rawPath = $this->userId . '/files/' . $plainFile['path']; + // Open handle with for binary reading - $plainHandle = $this->view->fopen( $plainFile['path'], 'rb' ); + $plainHandle = $this->view->fopen( $rawPath, 'rb' ); // Open handle with for binary writing - $encHandle = fopen( 'crypt://' . $plainFile['path'] . '.tmp', 'wb' ); + $encHandle = fopen( 'crypt://' . $relPath . '.tmp', 'wb' ); // Overwrite the existing file with the encrypted one //$this->view->file_put_contents( $plainFile['path'], $encrypted['data'] ); $size = stream_copy_to_stream( $plainHandle, $encHandle ); - $this->view->rename($plainFile['path'] . '.tmp', $plainFile['path']); + $this->view->rename($rawPath . '.tmp', $rawPath); // Fetch the key that has just been set/updated by the stream //$encKey = Keymanager::getFileKey( $this->view, $this->userId, $relPath ); @@ -545,18 +547,19 @@ class Util { // Recrypt data, generate catfile $recrypted = Crypt::legacyKeyRecryptKeyfile( $legacyData, $legacyPassphrase, $publicKey, $newPassphrase ); - $relPath = $this->stripUserFilesPath( $legacyFile['path'] ); + $relPath = $legacyFile['path']; + $rawPath = $this->userId . '/files/' . $plainFile['path']; // Save keyfile Keymanager::setFileKey( $this->view, $relPath, $this->userId, $recrypted['key'] ); // Overwrite the existing file with the encrypted one - $this->view->file_put_contents( $legacyFile['path'], $recrypted['data'] ); + $this->view->file_put_contents( $rawPath, $recrypted['data'] ); $size = strlen( $recrypted['data'] ); // Add the file to the cache - \OC\Files\Filesystem::putFileInfo( $legacyFile['path'], array( 'encrypted'=>true, 'size' => $size ), '' ); + \OC\Files\Filesystem::putFileInfo( $rawPath, array( 'encrypted'=>true, 'size' => $size ), '' ); } -- cgit v1.2.3 From f378a7f572e1da4b24280c1fcbf830e026186c83 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Wed, 10 Apr 2013 17:37:03 +0200 Subject: Fixed proxy class handing of read / write files Various work on other classes --- apps/files_encryption/ajax/adminrecovery.php | 12 +++-- apps/files_encryption/appinfo/app.php | 6 ++- apps/files_encryption/hooks/hooks.php | 10 ++-- apps/files_encryption/js/settings.js | 9 ++-- apps/files_encryption/lib/proxy.php | 49 +++++++++---------- apps/files_encryption/lib/stream.php | 2 +- apps/files_encryption/lib/util.php | 70 ++++++++++++++++++++++------ apps/files_encryption/test/proxy.php | 2 +- apps/files_encryption/test/util.php | 12 +++++ 9 files changed, 114 insertions(+), 58 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/ajax/adminrecovery.php b/apps/files_encryption/ajax/adminrecovery.php index f22114f8514..cec0cd4ddda 100644 --- a/apps/files_encryption/ajax/adminrecovery.php +++ b/apps/files_encryption/ajax/adminrecovery.php @@ -15,6 +15,8 @@ use OCA\Encryption; \OCP\JSON::checkAppEnabled( 'files_encryption' ); \OCP\JSON::callCheck(); +$return = $doSetup = false; + if ( isset( $_POST['adminEnableRecovery'] ) && $_POST['adminEnableRecovery'] == 1 @@ -47,7 +49,7 @@ if ( // If the recoveryAdmin UID exists but doesn't have admin rights } else { - \OCP\JSON::error(); + $return = false; } @@ -63,10 +65,12 @@ if ( $util->setupServerSide( $_POST['recoveryPassword'] ); // Store the UID in the DB - OC_Appconfig::setValue( 'encryption', 'recoveryAdminUid', $recoveryAdminUid ); + OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminUid', $recoveryAdminUid ); - \OCP\JSON::success(); + $return = true; } -} \ No newline at end of file +} + +($return) ? OC_JSON::success() : OC_JSON::error(); \ No newline at end of file diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index 9747fb20ad6..c2de9d0b441 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -24,8 +24,10 @@ OCP\Util::connectHook( 'OCP\Share', 'post_unshareAll', 'OCA\Encryption\Hooks', ' OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfileFromClient' ); stream_wrapper_register( 'crypt', 'OCA\Encryption\Stream' ); -$view = new OC_FilesystemView('/'); -$session = new OCA\Encryption\Session($view); + +$view = new OC_FilesystemView( '/' ); + +$session = new OCA\Encryption\Session( $view ); if ( ! $session->getPrivateKey( \OCP\USER::getUser() ) diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 82de80a1cf4..e65f0945f41 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -63,7 +63,7 @@ class Hooks { $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $params['password'] ); - $session = new Session($view); + $session = new Session( $view ); $session->setPrivateKey( $privateKey, $params['uid'] ); @@ -116,8 +116,8 @@ class Hooks { // is in use (client-side encryption does not have access to // the necessary keys) if ( Crypt::mode() == 'server' ) { - $view = new \OC_FilesystemView( '/' ); - $session = new Session($view); + + $session = new Session(); // Get existing decrypted private key $privateKey = $session->getPrivateKey(); @@ -189,7 +189,7 @@ class Hooks { if ( $params['itemType'] === 'file' ) { $view = new \OC_FilesystemView( '/' ); - $session = new Session($view); + $session = new Session(); $userId = \OCP\User::getUser(); $util = new Util( $view, $userId ); $path = $util->fileIdToPath( $params['itemSource'] ); @@ -244,7 +244,7 @@ class Hooks { if ( $params['itemType'] === 'file' ) { $view = new \OC_FilesystemView( '/' ); - $session = new Session($view); + $session = new Session(); $userId = \OCP\User::getUser(); $util = new Util( $view, $userId ); $path = $util->fileIdToPath( $params['itemSource'] ); diff --git a/apps/files_encryption/js/settings.js b/apps/files_encryption/js/settings.js index 4f367f880db..9a0bebf2478 100644 --- a/apps/files_encryption/js/settings.js +++ b/apps/files_encryption/js/settings.js @@ -16,11 +16,14 @@ $(document).ready(function(){ // Trigger ajax on recoveryAdmin status change $( 'input:radio[name="adminEnableRecovery"]' ).change( function() { + + var foo = $( this ).val(); + $.post( - '../ajax/adminrecovery.php' - , $( this ).val() + OC.filePath('files_encryption', 'ajax', 'adminrecovery.php') + , { adminEnableRecovery: foo, recoveryPassword: 'password' } , function( data ) { - // TODO: provide user with feedback of outcome + alert( data ); } ); } diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 7e18ec9b104..44a2e1aae55 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -101,7 +101,7 @@ class Proxy extends \OC_FileProxy { $userId = \OCP\USER::getUser(); $rootView = new \OC_FilesystemView( '/' ); $util = new Util( $rootView, $userId ); - $session = new Session($rootView); + $session = new Session( $rootView ); $fileOwner = \OC\Files\Filesystem::getOwner( $path ); $privateKey = $session->getPrivateKey(); $filePath = $util->stripUserFilesPath( $path ); @@ -115,9 +115,16 @@ class Proxy extends \OC_FileProxy { if ( $encKeyfile = Keymanager::getFileKey( $rootView, $fileOwner, $filePath ) ) { $keyPreExists = true; - + + // Fetch shareKey + $shareKey = Keymanager::getShareKey( $rootView, $userId, $filePath ); + // Decrypt the keyfile - $plainKey = $util->decryptUnknownKeyfile( $filePath, $fileOwner, $privateKey ); + $plainKey = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); + + trigger_error("\$shareKey = $shareKey"); + + trigger_error("\$plainKey = $plainKey"); } else { @@ -170,6 +177,7 @@ class Proxy extends \OC_FileProxy { // Save sharekeys to user folders // TODO: openssl_seal generates new shareKeys (envelope keys) each time data is encrypted, but will data still be decryptable using old shareKeys? If so we don't need to replace the old shareKeys here, we only need to set the new ones + Keymanager::setShareKeys( $rootView, $filePath, $multiEncrypted['keys'] ); // Set encrypted keyfile as common varname @@ -219,15 +227,18 @@ class Proxy extends \OC_FileProxy { // If data is a catfile if ( Crypt::mode() == 'server' - && Crypt::isCatfileContent( $data ) + && Crypt::isCatfileContent( $data ) // TODO: Do we really need this check? Can't we assume it is properly encrypted? ) { - // TODO use get owner to find correct location of key files for shared files - $session = new Session($view); + // TODO: use get owner to find correct location of key files for shared files + $session = new Session( $view ); $privateKey = $session->getPrivateKey( $userId ); // Get the file owner so we can retrieve its keyfile - list($fileOwner, $ownerPath) = $util->getUidAndFilename($relPath); +// list( $fileOwner, $ownerPath ) = $util->getUidAndFilename( $relPath ); + + $fileOwner = \OC\Files\Filesystem::getOwner( $path ); + $ownerPath = $util->stripUserFilesPath( $path ); // TODO: Don't trust $path, fetch owner path // Get the encrypted keyfile $encKeyfile = Keymanager::getFileKey( $view, $fileOwner, $ownerPath ); @@ -235,27 +246,9 @@ class Proxy extends \OC_FileProxy { // Attempt to fetch the user's shareKey $shareKey = Keymanager::getShareKey( $view, $userId, $relPath ); - // Check if key is shared or not - if ( $shareKey ) { - - \OC_FileProxy::$enabled = false; - -// trigger_error("\$encKeyfile = $encKeyfile, \$shareKey = $shareKey, \$privateKey = $privateKey"); - - // Decrypt keyfile with shareKey - $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); - -// $plainKeyfile = $encKeyfile; - -// trigger_error("PROXY plainkeyfile = ". var_export($plainKeyfile, 1)); - - } else { - - // If key is unshared, decrypt with user private key - $plainKeyfile = Crypt::keyDecrypt( $encKeyfile, $privateKey ); - - } - + // Decrypt keyfile with shareKey + $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); + $plainData = Crypt::symmetricDecryptFileContent( $data, $plainKeyfile ); // trigger_error("PLAINDATA = ". var_export($plainData, 1)); diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index d269a562404..7315245fcce 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -236,7 +236,7 @@ class Stream { $this->getUser(); - $session = new Session($this->rootView); + $session = new Session( $this->rootView ); $privateKey = $session->getPrivateKey( $this->userId ); diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 420e3398a8d..dc4e37150c5 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -24,13 +24,17 @@ # Bugs # ---- # Sharing a file to a user without encryption set up will not provide them with access but won't notify the sharer -# Timeouts on first login due to encryption of very large files +# Sharing files to other users currently broken (due to merge + ongoing implementation of support for lost password recovery) +# Timeouts on first login due to encryption of very large files (fix in progress, as a result streaming is currently broken) +# Sharing all files to admin for recovery purposes still in progress +# Possibly public links are broken (not tested since last merge of master) +# getOwner() currently returns false in all circumstances, unsure what code is returning this... # Missing features # ---------------- -# Re-use existing keyfiles so they don't need version control (part implemented, stream{} and util{} remain) # Make sure user knows if large files weren't encrypted +# Support for resharing encrypted files # Test @@ -122,7 +126,8 @@ class Util { $this->userId = $userId; $this->client = $client; $this->userDir = '/' . $this->userId; - $this->userFilesDir = '/' . $this->userId . '/' . 'files'; + $this->fileFolderName = 'files'; + $this->userFilesDir = '/' . $this->userId . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable? $this->publicKeyDir = '/' . 'public-keys'; $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption'; $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; @@ -690,7 +695,6 @@ class Util { /** * @brief Expand given path to all sub files & folders - * @param Session $session * @param string $path path which needs to be updated * @return array $pathsArray all found file paths * @note Paths of directories excluded, only *file* paths are returned @@ -747,6 +751,8 @@ class Util { * @param string $privateKey * @note Checks whether file was encrypted with openssl_seal or * openssl_encrypt, and decrypts accrdingly + * @note This was used when 2 types of encryption for keyfiles was used, + * but now we've switched to exclusively using openssl_seal() */ public function decryptUnknownKeyfile( $filePath, $fileOwner, $privateKey ) { @@ -861,19 +867,55 @@ class Util { /** * @brief get uid of the owners of the file and the path to the file - * @param $filename + * @param $shareFilePath Path of the file to check + * @note $shareFilePath must be relative to data/UID/files. Files + * relative to /Shared are also acceptable * @return array */ - public function getUidAndFilename($filename) { - $uid = \OC\Files\Filesystem::getOwner($filename); - - \OC\Files\Filesystem::initMountPoints($uid); - if ( $uid != \OCP\User::getUser() ) { - $info = \OC\Files\Filesystem::getFileInfo($filename); - $ownerView = new \OC\Files\View('/'.$uid.'/files'); - $filename = $ownerView->getPath($info['fileid']); + public function getUidAndFilename( $shareFilePath ) { + + $fileOwnerUid = \OC\Files\Filesystem::getOwner( $shareFilePath ); + + // Check that UID is valid + if ( ! \OCP\User::userExists( $fileOwnerUid ) ) { + + throw new \Exception( 'Could not find owner (UID = "' . var_export( $fileOwnerUid, 1 ) . '") of file "' . $shareFilePath . '"' ); + + } + + // NOTE: Bah, this dependency should be elsewhere + \OC\Files\Filesystem::initMountPoints( $fileOwnerUid ); + + // If the file owner is the currently logged in user + if ( $fileOwnerUid == $this->userId ) { + + // Assume the path supplied is correct + $filename = $shareFilePath; + + } else { + + $info = \OC\Files\Filesystem::getFileInfo( $shareFilePath ); + $ownerView = new \OC\Files\View( '/' . $fileOwnerUid . '/files' ); + + // Fetch real file path from DB + $filename = $ownerView->getPath( $info['fileid'] ); // TODO: Check that this returns a path without including the user data dir + } - return array($uid, $filename); + + // Make path relative for use by $view + $relpath = $fileOwnerUid . '/' . $this->fileFolderName . '/' . $filename; + + // Check that the filename we're using is working + if ( $this->view->file_exists( $relpath ) ) { + + return array ( $fileOwnerUid, $relpath ); + + } else { + + throw new \Exception( 'Supplied path could not be resolved "' . $shareFilePath . '"' ); + + } + } } diff --git a/apps/files_encryption/test/proxy.php b/apps/files_encryption/test/proxy.php index 709730f7609..5a2d851ff7c 100644 --- a/apps/files_encryption/test/proxy.php +++ b/apps/files_encryption/test/proxy.php @@ -52,7 +52,7 @@ // $this->userId = 'admin'; // $this->pass = 'admin'; // -// $this->session = new Encryption\Session(); +// $this->session = new Encryption\Session( $view ); // FIXME: Provide a $view object for use here // // $this->session->setPrivateKey( // '-----BEGIN PRIVATE KEY----- diff --git a/apps/files_encryption/test/util.php b/apps/files_encryption/test/util.php index e2767a2ec39..3ebc484809b 100755 --- a/apps/files_encryption/test/util.php +++ b/apps/files_encryption/test/util.php @@ -24,6 +24,8 @@ $loader->register(); use \Mockery as m; use OCA\Encryption; +\OC_User::login( 'admin', 'admin' ); + class Test_Enc_Util extends \PHPUnit_Framework_TestCase { function setUp() { @@ -184,6 +186,16 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase { $this->assertTrue( $util->setRecovery( $enabled ) ); } + + function testGetUidAndFilename() { + + \OC_User::setUserId( 'admin' ); + + $this->util->getUidAndFilename( 'test1.txt' ); + + + + } // /** // * @brief test decryption using legacy blowfish method -- cgit v1.2.3 From 770dcbf663c31c912b88b280121b21ec7ea4be8e Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Tue, 16 Apr 2013 14:50:20 +0200 Subject: Fixed stream{} reading of encrypted files (stream_read()) --- apps/files_encryption/lib/stream.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index ebfd05041ba..f765d62201c 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -239,13 +239,15 @@ class Stream { // Fetch existing keyfile $this->encKeyfile = Keymanager::getFileKey( $this->rootView, $this->userId, $this->relPath ); - $this->getUser(); + $this->setUserProperty(); $session = new Session( $this->rootView ); $privateKey = $session->getPrivateKey( $this->userId ); - $this->keyfile = Crypt::keyDecrypt( $this->encKeyfile, $privateKey ); + $shareKey = Keymanager::getShareKey( $this->rootView, $this->userId, $this->relPath ); + + $this->keyfile = Crypt::multiKeyDecrypt( $this->encKeyfile, $shareKey, $privateKey ); return true; @@ -257,7 +259,7 @@ class Stream { } - public function getuser() { + public function setUserProperty() { // Only get the user again if it isn't already set if ( empty( $this->userId ) ) { -- cgit v1.2.3 From f89a3604aabbd36f05789db46b6108f0f41f52b1 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Tue, 16 Apr 2013 18:29:22 +0200 Subject: Working on stream{} writing Development snapshot --- apps/files_encryption/appinfo/spec.txt | 6 ++- apps/files_encryption/lib/keymanager.php | 22 +++++++++ apps/files_encryption/lib/proxy.php | 44 +++++------------ apps/files_encryption/lib/stream.php | 83 +++++++++++++++++++++----------- apps/files_encryption/lib/util.php | 39 +++++++++++++++ 5 files changed, 133 insertions(+), 61 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/appinfo/spec.txt b/apps/files_encryption/appinfo/spec.txt index a1846ca47ff..4a7b3fc6ade 100644 --- a/apps/files_encryption/appinfo/spec.txt +++ b/apps/files_encryption/appinfo/spec.txt @@ -70,4 +70,8 @@ Notes is handled in the login hook listener. Therefore each time the user logs in their files are scanned to detect unencrypted and legacy encrypted files, and they are (re)encrypted as necessary. This may present a performance issue; we - need to monitor this. \ No newline at end of file + need to monitor this. +- When files are saved to ownCloud via WebDAV, a .part file extension is used so + that the file isn't cached before the upload has been completed. .part files + are not compatible with files_encrytion's key management system however, so + we have to always sanitise such paths manually before using them. \ No newline at end of file diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 3e26e6bb699..c37680fcbea 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -132,6 +132,28 @@ class Keymanager { } + /** + * @brief Remove .path extension from a file path + * @param string $path Path that may identify a .part file + * @return string File path without .part extension + */ + public static function fixPartialFilePath( $path ) { + + if ( preg_match( '/\.part$/', $path ) ) { + + $newLength = strlen( $path ) - 5; + $fPath = substr( $path, 0, $newLength ); + + return $fPath; + + } else { + + return $path; + + } + + } + /** * @brief retrieve keyfile for an encrypted file * @param \OC_FilesystemView $view diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 44a2e1aae55..4efb3d2e49c 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -138,34 +138,9 @@ class Proxy extends \OC_FileProxy { // Encrypt data $encData = Crypt::symmetricEncryptFileContent( $data, $plainKey ); - // Check if key recovery is enabled - $recoveryEnabled = $util->recoveryEnabled(); + $sharingEnabled = \OCP\Share::isEnabled(); - // Make sure that a share key is generated for the owner too - $userIds = array( $userId ); - - if ( \OCP\Share::isEnabled() ) { - - // Find out who, if anyone, is sharing the file - $shareUids = \OCP\Share::getUsersSharingFile( $filePath, true, true, true ); - - $userIds = array_merge( $userIds, $shareUids ); - - } - - // If recovery is enabled, add the - // Admin UID to list of users to share to - if ( $recoveryEnabled ) { - - // FIXME: Create a separate admin user purely for recovery, and create method in util for fetching this id from DB? - $adminUid = 'recoveryAdmin'; - - $userIds[] = $adminUid; - - } - - // Remove duplicate UIDs - $uniqueUserIds = array_unique ( $userIds ); + $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $filePath ); // Fetch public keys for all users who will share the file $publicKeys = Keymanager::getPublicKeys( $rootView, $uniqueUserIds ); @@ -280,6 +255,8 @@ class Proxy extends \OC_FileProxy { */ public function preUnlink( $path ) { + $path = Keymanager::fixPartialFilePath( $path ); + // Disable encryption proxy to prevent recursive calls \OC_FileProxy::$enabled = false; @@ -290,17 +267,20 @@ class Proxy extends \OC_FileProxy { $util = new Util( $view, $userId ); // Format path to be relative to user files dir - $relPath = $util->stripUserFilesPath($path); + $relPath = $util->stripUserFilesPath( $path ); + +// list( $owner, $ownerPath ) = $util->getUidAndFilename( $relPath ); - list($owner, $ownerPath) = $util->getUidAndFilename($relPath); + $fileOwner = \OC\Files\Filesystem::getOwner( $path ); + $ownerPath = $util->stripUserFilesPath( $path ); // TODO: Don't trust $path, fetch owner path - $filePath = $owner . '/' . 'files_encryption' . '/' . 'keyfiles' . '/'. $ownerPath; + $filePath = $fileOwner . '/' . 'files_encryption' . '/' . 'keyfiles' . '/'. $ownerPath; // Delete keyfile & shareKey so it isn't orphaned if ( ! ( - Keymanager::deleteFileKey( $view, $owner, $ownerPath ) - && Keymanager::delShareKey( $view, $owner, $ownerPath ) + Keymanager::deleteFileKey( $view, $fileOwner, $ownerPath ) + && Keymanager::delShareKey( $view, $fileOwner, $ownerPath ) ) ) { diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index f765d62201c..3e854c8df87 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -44,6 +44,9 @@ namespace OCA\Encryption; * buffer size used internally by PHP. The encryption process makes the input * data longer, and input is chunked into smaller pieces in order to result in * a 8192 encrypted block size. + * @note When files are deleted via webdav, or when they are updated and the + * previous version deleted, this is handled by OC\Files\View, and thus the + * encryption proxies are used and keyfiles deleted. */ class Stream { @@ -171,17 +174,21 @@ class Stream { // // Get the data from the file handle $data = fread( $this->handle, 8192 ); + + $result = ''; if ( strlen( $data ) ) { - $this->getKey(); + if ( ! $this->getKey() ) { + + // Error! We don't have a key to decrypt the file with + throw new \Exception( 'Encryption key not found for "' . $this->rawPath . '" during attempted read via stream' ); - $result = Crypt::symmetricDecryptFileContent( $data, $this->keyfile ); + } + + // Decrypt data + $result = Crypt::symmetricDecryptFileContent( $data, $this->plainKey ); - } else { - - $result = ''; - } // $length = $this->size - $pos; @@ -224,18 +231,20 @@ class Stream { */ public function getKey() { - // fix performance issues - if(isset($this->keyfile) && isset($this->encKeyfile)) { - return true; - } - - // If a keyfile already exists for a file named identically to - // file to be written - if ( $this->rootView->file_exists( $this->userId . '/'. 'files_encryption' . '/' . 'keyfiles' . '/' . $this->relPath . '.key' ) ) { + // Check if key is already set + if ( isset( $this->plainKey ) && isset( $this->encKeyfile ) ) { + + return true; + + } - // TODO: add error handling for when file exists but no - // keyfile + // Avoid problems with .part file extensions + $this->relPath = Keymanager::fixPartialFilePath( $this->relPath ); + + // If a keyfile already exists + if ( $this->rootView->file_exists( $this->userId . '/'. 'files_encryption' . '/' . 'keyfiles' . '/' . $this->relPath . '.key' ) ) { + // Fetch and decrypt keyfile // Fetch existing keyfile $this->encKeyfile = Keymanager::getFileKey( $this->rootView, $this->userId, $this->relPath ); @@ -247,12 +256,17 @@ class Stream { $shareKey = Keymanager::getShareKey( $this->rootView, $this->userId, $this->relPath ); - $this->keyfile = Crypt::multiKeyDecrypt( $this->encKeyfile, $shareKey, $privateKey ); + $this->plainKey = Crypt::multiKeyDecrypt( $this->encKeyfile, $shareKey, $privateKey ); + + trigger_error( '$this->relPath = '.$this->relPath ); + trigger_error( '$this->userId = '.$this->userId); + trigger_error( '$this->encKeyfile = '.$this->encKeyfile ); + trigger_error( '$this->plainKey1 = '.var_export($this->plainKey, 1)); return true; } else { - + return false; } @@ -303,7 +317,7 @@ class Stream { $pointer = ftell( $this->handle ); // Make sure the userId is set - $this->getuser(); + $this->setUserProperty(); // TODO: Check if file is shared, if so, use multiKeyEncrypt and // save shareKeys in necessary user directories @@ -313,21 +327,34 @@ class Stream { // one), save the newly generated keyfile if ( ! $this->getKey() ) { - // TODO: Reuse the keyfile, it it exists, instead of making a new one - $this->keyfile = Crypt::generateKey(); + $util = new Util( $this->rootView, $this->userId ); + + $this->plainKey = Crypt::generateKey(); $this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId ); - $this->encKeyfile = Crypt::keyEncrypt( $this->keyfile, $this->publicKey ); + $sharingEnabled = \OCP\Share::isEnabled(); + + $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $this->relPath ); + + // Fetch public keys for all users who will share the file + $publicKeys = Keymanager::getPublicKeys( $this->rootView, $uniqueUserIds ); + + $this->encKeyfiles = Crypt::multiKeyEncrypt( $this->plainKey, $publicKeys ); $view = new \OC_FilesystemView( '/' ); - $userId = \OCP\User::getUser(); // Save the new encrypted file key - Keymanager::setFileKey( $view, $this->relPath, $userId, $this->encKeyfile ); + Keymanager::setShareKeys( $view, $this->relPath, $this->encKeyfiles['keys'] ); + +// trigger_error( '$this->relPath = '.$this->relPath ); +// trigger_error( '$this->userId = '.$this->userId); +// trigger_error( '$this->encKeyfile = '.var_export($this->encKeyfiles, 1) ); } - + +// trigger_error( '$this->plainKey2 = '.var_export($this->plainKey, 1)); + // If extra data is left over from the last round, make sure it // is integrated into the next 6126 / 8192 block if ( $this->writeCache ) { @@ -355,7 +382,7 @@ class Stream { // // fseek( $this->handle, - ( $currentPos % 8192 ), SEEK_CUR ); // -// $block = Crypt::symmetricDecryptFileContent( $unencryptedNewBlock, $this->keyfile ); +// $block = Crypt::symmetricDecryptFileContent( $unencryptedNewBlock, $this->plainKey ); // // $x = substr( $block, 0, $currentPos % 8192 ); // @@ -396,7 +423,7 @@ class Stream { // Read the chunk from the start of $data $chunk = substr( $data, 0, 6126 ); - $encrypted = $this->preWriteEncrypt( $chunk, $this->keyfile ); + $encrypted = $this->preWriteEncrypt( $chunk, $this->plainKey ); // Write the data chunk to disk. This will be // attended to the last data chunk if the file @@ -461,7 +488,7 @@ class Stream { // Set keyfile property for file in question $this->getKey(); - $encrypted = $this->preWriteEncrypt( $this->writeCache, $this->keyfile ); + $encrypted = $this->preWriteEncrypt( $this->writeCache, $this->plainKey ); fwrite( $this->handle, $encrypted ); diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index dc4e37150c5..c964bd94dfa 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -864,7 +864,46 @@ class Util { return array_unique( $users ); } + + /** + * @brief Find, sanitise and format users sharing a file + * @note This wraps other methods into a portable bundle + */ + public function getSharingUsersArray( $sharingEnabled, $filePath ) { + // Check if key recovery is enabled + $recoveryEnabled = $this->recoveryEnabled(); + + // Make sure that a share key is generated for the owner too + $userIds = array( $this->userId ); + + if ( $sharingEnabled ) { + + // Find out who, if anyone, is sharing the file + $shareUids = \OCP\Share::getUsersSharingFile( $filePath, true, true, true ); + + $userIds = array_merge( $userIds, $shareUids ); + + } + + // If recovery is enabled, add the + // Admin UID to list of users to share to + if ( $recoveryEnabled ) { + + // FIXME: Create a separate admin user purely for recovery, and create method in util for fetching this id from DB? + $adminUid = 'recoveryAdmin'; + + $userIds[] = $adminUid; + + } + + // Remove duplicate UIDs + $uniqueUserIds = array_unique ( $userIds ); + + return $uniqueUserIds; + + } + /** * @brief get uid of the owners of the file and the path to the file * @param $shareFilePath Path of the file to check -- cgit v1.2.3 From 6dd8c79461bc5edd723ffb1d561f8ab9251ba02c Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Wed, 17 Apr 2013 17:20:37 +0200 Subject: Development snapshot Working on stream{} write --- apps/files_encryption/lib/proxy.php | 5 +-- apps/files_encryption/lib/stream.php | 80 +++++++++++++++++++----------------- apps/files_encryption/lib/util.php | 3 ++ 3 files changed, 48 insertions(+), 40 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 4efb3d2e49c..1e7ac609a4b 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -122,9 +122,8 @@ class Proxy extends \OC_FileProxy { // Decrypt the keyfile $plainKey = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); - trigger_error("\$shareKey = $shareKey"); - - trigger_error("\$plainKey = $plainKey"); +// trigger_error("\$shareKey = $shareKey"); +// trigger_error("\$plainKey = $plainKey"); } else { diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 3e854c8df87..01eee177cd9 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -225,7 +225,7 @@ class Stream { } /** - * @brief Get the keyfile for the current file, generate one if necessary + * @brief Fetch the plain encryption key for the file and set it as plainKey property * @param bool $generate if true, a new key will be generated if none can be found * @return bool true on key found and set, false on key not found and new key generated and set */ @@ -258,10 +258,10 @@ class Stream { $this->plainKey = Crypt::multiKeyDecrypt( $this->encKeyfile, $shareKey, $privateKey ); - trigger_error( '$this->relPath = '.$this->relPath ); - trigger_error( '$this->userId = '.$this->userId); - trigger_error( '$this->encKeyfile = '.$this->encKeyfile ); - trigger_error( '$this->plainKey1 = '.var_export($this->plainKey, 1)); +// trigger_error( '$this->relPath = '.$this->relPath ); +// trigger_error( '$this->userId = '.$this->userId); +// trigger_error( '$this->encKeyfile = '.$this->encKeyfile ); +// trigger_error( '$this->plainKey1 = '.var_export($this->plainKey, 1)); return true; @@ -319,40 +319,44 @@ class Stream { // Make sure the userId is set $this->setUserProperty(); - // TODO: Check if file is shared, if so, use multiKeyEncrypt and - // save shareKeys in necessary user directories - // Get / generate the keyfile for the file we're handling // If we're writing a new file (not overwriting an existing // one), save the newly generated keyfile if ( ! $this->getKey() ) { - $util = new Util( $this->rootView, $this->userId ); - $this->plainKey = Crypt::generateKey(); - $this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId ); - - $sharingEnabled = \OCP\Share::isEnabled(); - - $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $this->relPath ); - - // Fetch public keys for all users who will share the file - $publicKeys = Keymanager::getPublicKeys( $this->rootView, $uniqueUserIds ); - - $this->encKeyfiles = Crypt::multiKeyEncrypt( $this->plainKey, $publicKeys ); - - $view = new \OC_FilesystemView( '/' ); - - // Save the new encrypted file key - Keymanager::setShareKeys( $view, $this->relPath, $this->encKeyfiles['keys'] ); - -// trigger_error( '$this->relPath = '.$this->relPath ); -// trigger_error( '$this->userId = '.$this->userId); -// trigger_error( '$this->encKeyfile = '.var_export($this->encKeyfiles, 1) ); - } + // Fetch user's public key + $this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId ); + + // Check if OC sharing api is enabled + $sharingEnabled = \OCP\Share::isEnabled(); + + $util = new Util( $this->rootView, $this->userId ); + + // Get all users sharing the file + $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $this->relPath ); + + // Fetch public keys for all sharing users + $publicKeys = Keymanager::getPublicKeys( $this->rootView, $uniqueUserIds ); + + // Encrypt enc key for all sharing users + $this->encKeyfiles = Crypt::multiKeyEncrypt( $this->plainKey, $publicKeys ); + + $view = new \OC_FilesystemView( '/' ); + + // Save the new encrypted file key + Keymanager::setFileKey( $this->rootView, $this->relPath, $this->userId, $this->encKeyfiles['data'] ); + + // Save the sharekeys + Keymanager::setShareKeys( $view, $this->relPath, $this->encKeyfiles['keys'] ); + +// trigger_error( "\$this->encKeyfiles['data'] = ".$this->encKeyfiles['data'] ); +// trigger_error( '$this->relPath = '.$this->relPath ); +// trigger_error( '$this->userId = '.$this->userId); +// trigger_error( '$this->encKeyfile = '.var_export($this->encKeyfiles, 1) ); // trigger_error( '$this->plainKey2 = '.var_export($this->plainKey, 1)); // If extra data is left over from the last round, make sure it @@ -396,7 +400,7 @@ class Stream { // // While there still remains somed data to be processed & written while( strlen( $data ) > 0 ) { -// + // // Remaining length for this iteration, not of the // // entire file (may be greater than 8192 bytes) // $remainingLength = strlen( $data ); @@ -404,7 +408,7 @@ class Stream { // // If data remaining to be written is less than the // // size of 1 6126 byte block if ( strlen( $data ) < 6126 ) { - + // Set writeCache to contents of $data // The writeCache will be carried over to the // next write round, and added to the start of @@ -425,6 +429,8 @@ class Stream { $encrypted = $this->preWriteEncrypt( $chunk, $this->plainKey ); + trigger_error("\$encrypted = $encrypted"); + // Write the data chunk to disk. This will be // attended to the last data chunk if the file // being handled totals more than 6126 bytes @@ -441,7 +447,7 @@ class Stream { } } - + $this->size = max( $this->size, $pointer + $length ); return $length; @@ -493,7 +499,7 @@ class Stream { fwrite( $this->handle, $encrypted ); $this->writeCache = ''; - + } } @@ -501,16 +507,16 @@ class Stream { public function stream_close() { $this->flush(); - + if ( $this->meta['mode']!='r' and $this->meta['mode']!='rb' ) { - + \OC\Files\Filesystem::putFileInfo( $this->path, array( 'encrypted' => true, 'size' => $this->size ), '' ); } - + return fclose( $this->handle ); } diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index c964bd94dfa..2fc7b959ece 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -29,6 +29,9 @@ # Sharing all files to admin for recovery purposes still in progress # Possibly public links are broken (not tested since last merge of master) # getOwner() currently returns false in all circumstances, unsure what code is returning this... +# encryptAll during login mangles paths: /files/files/ +# encryptAll is accessing files via encryption proxy - perhaps proxies should be disabled? +# Sharekeys appear to not be deleted when their parent file is, and thus get orphaned # Missing features -- cgit v1.2.3 From 2434739d699e2ca4316ea3aece86d7f609ff8e6d Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Thu, 18 Apr 2013 02:03:03 +0200 Subject: fix for trashbin --- apps/files_encryption/lib/proxy.php | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 1e7ac609a4b..3af9dc73d83 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -254,6 +254,11 @@ class Proxy extends \OC_FileProxy { */ public function preUnlink( $path ) { + // let the trashbin handle this + if ( \OCP\App::isEnabled('files_trashbin') ) { + return true; + } + $path = Keymanager::fixPartialFilePath( $path ); // Disable encryption proxy to prevent recursive calls -- cgit v1.2.3 From a646a1169f9a17be8d520489ae85c16bbcc7236c Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Thu, 18 Apr 2013 13:41:21 +0200 Subject: return filename relative to users file dir and not relative to data dir --- apps/files_encryption/lib/util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 2fc7b959ece..f03b2308b2f 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -950,7 +950,7 @@ class Util { // Check that the filename we're using is working if ( $this->view->file_exists( $relpath ) ) { - return array ( $fileOwnerUid, $relpath ); + return array ( $fileOwnerUid, $filename ); } else { -- cgit v1.2.3 From bd3024242f95a0761c0ce2295b39b4e350a6795d Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Thu, 18 Apr 2013 15:42:28 +0200 Subject: always save key file, the key doesn't change but the encrypted keyfile change always the same way like the share-keys change --- apps/files_encryption/lib/proxy.php | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 1e7ac609a4b..4f02c60e103 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -113,8 +113,6 @@ class Proxy extends \OC_FileProxy { // Check if there is an existing key we can reuse if ( $encKeyfile = Keymanager::getFileKey( $rootView, $fileOwner, $filePath ) ) { - - $keyPreExists = true; // Fetch shareKey $shareKey = Keymanager::getShareKey( $rootView, $userId, $filePath ); @@ -127,8 +125,6 @@ class Proxy extends \OC_FileProxy { } else { - $keyPreExists = false; - // Make a new key $plainKey = Crypt::generateKey(); @@ -157,14 +153,9 @@ class Proxy extends \OC_FileProxy { // Set encrypted keyfile as common varname $encKey = $multiEncrypted['data']; - // Save the key if its new - if ( ! $keyPreExists ) { - - // Save keyfile for newly encrypted file in parallel directory tree - Keymanager::setFileKey( $rootView, $filePath, $fileOwner, $encKey ); - - } - + // Save keyfile for newly encrypted file in parallel directory tree + Keymanager::setFileKey( $rootView, $filePath, $fileOwner, $encKey ); + // Replace plain content with encrypted content by reference $data = $encData; -- cgit v1.2.3 From 7892fddcb95d5d4becde224b1d387025b2a5dd5f Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Thu, 18 Apr 2013 15:44:57 +0200 Subject: remove ToDo, every time the file key gets encrypted new share keys are generated and a new encrypted filekey. We always need to use the latest share-keys and encrypted keyfiles --- apps/files_encryption/lib/proxy.php | 1 - 1 file changed, 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 4f02c60e103..f996a612bfe 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -146,7 +146,6 @@ class Proxy extends \OC_FileProxy { $multiEncrypted = Crypt::multiKeyEncrypt( $plainKey, $publicKeys ); // Save sharekeys to user folders - // TODO: openssl_seal generates new shareKeys (envelope keys) each time data is encrypted, but will data still be decryptable using old shareKeys? If so we don't need to replace the old shareKeys here, we only need to set the new ones Keymanager::setShareKeys( $rootView, $filePath, $multiEncrypted['keys'] ); -- cgit v1.2.3 From 40905c8941fa707fe358c0f4a5413931b34f8217 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Thu, 18 Apr 2013 16:34:23 +0200 Subject: fix file sharing, sharing files works now; moved the identification of file owner and the owner path in the keymanager functions so that other functions doesn't have to deal with it --- apps/files_encryption/lib/keymanager.php | 17 ++++++++++------- apps/files_encryption/lib/proxy.php | 13 +++---------- 2 files changed, 13 insertions(+), 17 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index c37680fcbea..52d100055e0 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -107,11 +107,13 @@ class Keymanager { public static function setFileKey( \OC_FilesystemView $view, $path, $userId, $catfile ) { \OC_FileProxy::$enabled = false; + + $util = new Util($view, $userId); + list($owner, $filename) = $util->getUidAndFilename($path); + + $basePath = '/' . $owner . '/files_encryption/keyfiles'; - \OC\Files\Filesystem::initMountPoints($userId); - $basePath = '/' . $userId . '/files_encryption/keyfiles'; - - $targetPath = self::keySetPreparation( $view, $path, $basePath, $userId ); + $targetPath = self::keySetPreparation( $view, $filename, $basePath, $owner ); if ( !$view->is_dir( $basePath . '/' . $targetPath ) ) { @@ -166,10 +168,11 @@ class Keymanager { */ public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) { - \OC\Files\Filesystem::initMountPoints($userId); - $filePath_f = ltrim( $filePath, '/' ); + $util = new Util($view, $userId); + list($owner, $filename) = $util->getUidAndFilename($filePath); + $filePath_f = ltrim( $filename, '/' ); - $keyfilePath = '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key'; + $keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key'; \OC_FileProxy::$enabled = false; diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index f996a612bfe..88a8c072ea0 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -102,7 +102,6 @@ class Proxy extends \OC_FileProxy { $rootView = new \OC_FilesystemView( '/' ); $util = new Util( $rootView, $userId ); $session = new Session( $rootView ); - $fileOwner = \OC\Files\Filesystem::getOwner( $path ); $privateKey = $session->getPrivateKey(); $filePath = $util->stripUserFilesPath( $path ); // Set the filesize for userland, before encrypting @@ -112,7 +111,7 @@ class Proxy extends \OC_FileProxy { \OC_FileProxy::$enabled = false; // Check if there is an existing key we can reuse - if ( $encKeyfile = Keymanager::getFileKey( $rootView, $fileOwner, $filePath ) ) { + if ( $encKeyfile = Keymanager::getFileKey( $rootView, $userId, $filePath ) ) { // Fetch shareKey $shareKey = Keymanager::getShareKey( $rootView, $userId, $filePath ); @@ -153,7 +152,7 @@ class Proxy extends \OC_FileProxy { $encKey = $multiEncrypted['data']; // Save keyfile for newly encrypted file in parallel directory tree - Keymanager::setFileKey( $rootView, $filePath, $fileOwner, $encKey ); + Keymanager::setFileKey( $rootView, $filePath, $userId, $encKey ); // Replace plain content with encrypted content by reference $data = $encData; @@ -198,14 +197,8 @@ class Proxy extends \OC_FileProxy { $session = new Session( $view ); $privateKey = $session->getPrivateKey( $userId ); - // Get the file owner so we can retrieve its keyfile -// list( $fileOwner, $ownerPath ) = $util->getUidAndFilename( $relPath ); - - $fileOwner = \OC\Files\Filesystem::getOwner( $path ); - $ownerPath = $util->stripUserFilesPath( $path ); // TODO: Don't trust $path, fetch owner path - // Get the encrypted keyfile - $encKeyfile = Keymanager::getFileKey( $view, $fileOwner, $ownerPath ); + $encKeyfile = Keymanager::getFileKey( $view, $userId, $relPath ); // Attempt to fetch the user's shareKey $shareKey = Keymanager::getShareKey( $view, $userId, $relPath ); -- cgit v1.2.3 From 1df36e0c889e9f80f821274f7f5d1e01a7cc01ae Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Thu, 18 Apr 2013 16:37:49 +0200 Subject: rename $shareFilePath to $path to avoid confusions, it is not about paths to share files but about general path to files stored in ownCloud --- apps/files_encryption/lib/util.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index f03b2308b2f..dbe4acc74ea 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -909,19 +909,19 @@ class Util { /** * @brief get uid of the owners of the file and the path to the file - * @param $shareFilePath Path of the file to check + * @param $path Path of the file to check * @note $shareFilePath must be relative to data/UID/files. Files * relative to /Shared are also acceptable * @return array */ - public function getUidAndFilename( $shareFilePath ) { - - $fileOwnerUid = \OC\Files\Filesystem::getOwner( $shareFilePath ); + public function getUidAndFilename( $path ) { + + $fileOwnerUid = \OC\Files\Filesystem::getOwner( $path ); // Check that UID is valid if ( ! \OCP\User::userExists( $fileOwnerUid ) ) { - throw new \Exception( 'Could not find owner (UID = "' . var_export( $fileOwnerUid, 1 ) . '") of file "' . $shareFilePath . '"' ); + throw new \Exception( 'Could not find owner (UID = "' . var_export( $fileOwnerUid, 1 ) . '") of file "' . $path . '"' ); } @@ -932,11 +932,11 @@ class Util { if ( $fileOwnerUid == $this->userId ) { // Assume the path supplied is correct - $filename = $shareFilePath; + $filename = $path; } else { - $info = \OC\Files\Filesystem::getFileInfo( $shareFilePath ); + $info = \OC\Files\Filesystem::getFileInfo( $path ); $ownerView = new \OC\Files\View( '/' . $fileOwnerUid . '/files' ); // Fetch real file path from DB @@ -954,7 +954,7 @@ class Util { } else { - throw new \Exception( 'Supplied path could not be resolved "' . $shareFilePath . '"' ); + throw new \Exception( 'Supplied path could not be resolved "' . $path . '"' ); } -- cgit v1.2.3 From 39c717b24cd4551a78d07256e15b29e52841f49b Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Thu, 18 Apr 2013 17:52:27 +0200 Subject: some fixes to the keymanager class to identify the file owner and the owner path correctly. --- apps/files_encryption/lib/keymanager.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 52d100055e0..5c5a6c7ec5c 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -108,7 +108,8 @@ class Keymanager { \OC_FileProxy::$enabled = false; - $util = new Util($view, $userId); + //here we need the currently logged in user, while userId can be a different user + $util = new Util($view, \OCP\User::getUser()); list($owner, $filename) = $util->getUidAndFilename($path); $basePath = '/' . $owner . '/files_encryption/keyfiles'; @@ -168,7 +169,7 @@ class Keymanager { */ public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) { - $util = new Util($view, $userId); + $util = new Util($view, \OCP\User::getUser()); list($owner, $filename) = $util->getUidAndFilename($filePath); $filePath_f = ltrim( $filename, '/' ); @@ -298,7 +299,8 @@ class Keymanager { */ public static function setShareKey( \OC_FilesystemView $view, $path, $userId, $shareKey ) { - $util = new Util( $view, $userId ); + //here we need the currently logged in user, while userId can be a different user + $util = new Util( $view, \OCP\User::getUser() ); list($owner, $filename) = $util->getUidAndFilename($path); @@ -368,7 +370,8 @@ class Keymanager { \OC_FileProxy::$enabled = false; - $util = new Util( $view, $userId ); + //here we need the currently logged in user, while userId can be a different user + $util = new Util( $view, \OCP\User::getUser() ); list($owner, $filename) = $util->getUidAndFilename($filePath); -- cgit v1.2.3 From 935d0398600df7c0f46f1cf5d5905c423b9c22e5 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Thu, 18 Apr 2013 17:53:59 +0200 Subject: necessary changes in util.php after the changes in \OCP\Share::getUsersSharingFile() (fe58e4b1a6a0f3b63afe74690986493facdad2c4) --- apps/files_encryption/lib/util.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index dbe4acc74ea..e4321fdb9df 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -878,12 +878,15 @@ class Util { $recoveryEnabled = $this->recoveryEnabled(); // Make sure that a share key is generated for the owner too - $userIds = array( $this->userId ); - + list($owner, $ownerPath) = $this->getUidAndFilename($filePath); + + //$userIds = array( $this->userId ); + $userIds = array(); + if ( $sharingEnabled ) { // Find out who, if anyone, is sharing the file - $shareUids = \OCP\Share::getUsersSharingFile( $filePath, true, true, true ); + $shareUids = \OCP\Share::getUsersSharingFile( $ownerPath, $owner,true, true, true ); $userIds = array_merge( $userIds, $shareUids ); -- cgit v1.2.3 From 2bd338c49fd15a992ecc8c796cb921af4ee59e09 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Thu, 18 Apr 2013 20:02:27 +0200 Subject: getUsersSharingFile() no longer needed, use getSharingUsersArray() instead; fix filterShareReadyUsers() to return the correct results --- apps/files_encryption/lib/util.php | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index e4321fdb9df..8807de7c2ad 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -657,14 +657,12 @@ class Util { public function filterShareReadyUsers( $unfilteredUsers ) { // This array will collect the filtered IDs - $userIds = array(); + $readyIds = $unreadyIds = array(); // Loop through users and create array of UIDs that need new keyfiles foreach ( $unfilteredUsers as $user ) { $util = new Util( $this->view, $user ); - - $readyIds = $unreadyIds = array(); // Check that the user is encryption capable, or is the // public system user 'ownCloud' (for public shares) @@ -690,7 +688,7 @@ class Util { } return array ( - 'ready' => $userIds + 'ready' => $readyIds , 'unready' => $unreadyIds ); @@ -810,7 +808,7 @@ class Util { } // Get public keys for each user, ready for generating sharekeys - $userPubKeys = Keymanager::getPublicKeys( $this->view, $filteredUids['ready'] ); // TODO: check this includes the owner's public key + $userPubKeys = Keymanager::getPublicKeys( $this->view, $filteredUids['ready'] ); \OC_FileProxy::$enabled = false; @@ -846,28 +844,6 @@ class Util { return true; } - /** - * @brief Returns the users who are sharing a file, including the file owner - * @param $path Relative path of the file, like files/file.txt - * @return $users array of UIDs - * @note This wraps the OCP\Share method, but includes the owner even if - * the file isn't registered in sharing API - */ - public function getUsersSharingFile( $path ) { - - $users = \OCP\Share::getUsersSharingFile( $path, true, true ); - - // FIXME: this is returning empty :/ - $owner = \OC\Files\Filesystem::getOwner( $path ); - -// trigger_error( var_export( $owner, 1)); - - $users[] = $owner; - - return array_unique( $users ); - - } - /** * @brief Find, sanitise and format users sharing a file * @note This wraps other methods into a portable bundle -- cgit v1.2.3 From 0e1970438b6dd7b6f705aeb420e1d4b4bd27c609 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Thu, 18 Apr 2013 22:34:22 +0200 Subject: fixed incorrect filesize, download via web is now possible fixed broken file-info --- apps/files_encryption/lib/proxy.php | 36 ++++++++++++++++++++++++++++++++++-- apps/files_encryption/lib/stream.php | 2 +- 2 files changed, 35 insertions(+), 3 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 3af9dc73d83..e23598bb5ff 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -439,9 +439,41 @@ class Proxy extends \OC_FileProxy { public function postFileSize( $path, $size ) { - if ( Crypt::isCatfileContent( $path ) ) { + // Reformat path for use with OC_FSV + $path_split = explode( '/', $path ); + $path_f = implode( '/', array_slice( $path_split, 3 ) ); + + if ( Crypt::isEncryptedMeta( $path_f ) ) { - $cached = \OC\Files\Filesystem::getFileInfo( $path, '' ); + // Disable encryption proxy to prevent recursive calls + \OC_FileProxy::$enabled = false; + + // get file info + $cached = \OC\Files\Filesystem::getFileInfo( $path_f, '' ); + + // calculate last chunk nr + $lastChunckNr = floor( $size / 8192); + + // open stream + $result = fopen( 'crypt://'.$path_f, "r" ); + + // calculate last chunk position + $lastChunckPos = ( $lastChunckNr * 8192 ); + + // seek to end + fseek( $result, $lastChunckPos ); + + // get the content of the last chunck + $lastChunkContent = fgets( $result ); + + // calc the real filesize with the size of the last chunk + $realSize = ( ( $lastChunckNr * 6126 ) + strlen( $lastChunkContent ) ); + + // enable proxy + \OC_FileProxy::$enabled = true; + + // set the size + $cached['size'] = $realSize; return $cached['size']; diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 01eee177cd9..4b33c200bf3 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -513,7 +513,7 @@ class Stream { and $this->meta['mode']!='rb' ) { - \OC\Files\Filesystem::putFileInfo( $this->path, array( 'encrypted' => true, 'size' => $this->size ), '' ); + \OC\Files\Filesystem::putFileInfo( $this->relPath, array( 'encrypted' => true, 'size' => $this->size ), '' ); } -- cgit v1.2.3 From 12785b93f188c85f19e52917c66aa749b9836ad2 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Fri, 19 Apr 2013 13:17:08 +0200 Subject: make sure that all share keys get deleted if a file/folder gets unshared from a user/group --- apps/files_encryption/hooks/hooks.php | 15 +++++++---- apps/files_encryption/lib/keymanager.php | 46 +++++++++++++++++++++++--------- 2 files changed, 44 insertions(+), 17 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 265b90a87a1..2731ee11125 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -240,22 +240,27 @@ class Hooks { // [shareType] => 0 // [shareWith] => test1 - // TODO: Should other kinds of item be encrypted too? - if ( $params['itemType'] === 'file' ) { + if ( $params['itemType'] === 'file' || $params['itemType'] === 'folder' ) { $view = new \OC_FilesystemView( '/' ); - $session = new Session(); + $session = new Session($view); $userId = \OCP\User::getUser(); $util = new Util( $view, $userId ); $path = $util->fileIdToPath( $params['itemSource'] ); - + + if ($params['shareType'] == \OCP\Share::SHARE_TYPE_GROUP) { + $userIds = \OC_Group::usersInGroup($params['shareWith']); + } else { + $userIds = array($params['shareWith']); + } + // If path is a folder, get all children $allPaths = $util->getPaths( $path ); foreach ( $allPaths as $path ) { // Unshare each child path - if ( ! Keymanager::delShareKey( $view, $params['shareWith'], $path ) ) { + if ( ! Keymanager::delShareKey( $view, $userIds, $path ) ) { $failed[] = $path; diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 5c5a6c7ec5c..f23423062b9 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -395,27 +395,28 @@ class Keymanager { /** * @brief Delete a single user's shareKey for a single file */ - public static function delShareKey( \OC_FilesystemView $view, $userId, $filePath ) { + public static function delShareKey( \OC_FilesystemView $view, $userIds, $filePath ) { \OC_FileProxy::$enabled = false; - $shareKeyPath = '/' . $userId . '/files_encryption/share-keys/' . $filePath; + //here we need the currently logged in user, while userId can be a different user + $util = new Util( $view, \OCP\User::getUser() ); + + list($owner, $filename) = $util->getUidAndFilename($filePath); + + $shareKeyPath = '/' . $owner . '/files_encryption/share-keys/' . $filename; $result = false; if ( $view->is_dir($shareKeyPath) ) { - $result = $view->unlink($shareKeyPath); - } else { - $absPath = $view->getLocalFile($shareKeyPath); - - $matches = glob(preg_quote($absPath).'.*.shareKey' ); - if ( $matches ) { + $localPath = \OC_Filesystem::normalizePath($view->getLocalFolder($shareKeyPath)); + $result = self::recursiveDelShareKeys($localPath, $userIds); - foreach ( $matches as $ma ) { - unlink($ma); - } + } else { + foreach ($userIds as $userId) { + $view->unlink($shareKeyPath.'.'.$userId.'.shareKey'); } $result = true; @@ -432,7 +433,28 @@ class Keymanager { return $result; } - + + /** + * @brief recursively delete share keys from given users + * + * @param type $dir directory + * @param type $userIds user ids for which the share keys should be deleted + */ + private static function recursiveDelShareKeys($dir, $userIds) { + foreach ($userIds as $userId) { + $completePath = $dir.'/.*'.'.'.$userId.'.shareKey'; + $matches = glob(preg_quote($dir).'/*'.preg_quote('.'.$userId.'.shareKey')); + } + foreach ($matches as $ma) { + unlink($ma); + } + $subdirs = $directories = glob(preg_quote($dir) . '/*' , GLOB_ONLYDIR); + foreach ( $subdirs as $subdir ) { + self::recursiveDelShareKeys($subdir, $userIds); + } + return $true; + } + /** * @brief Make preparations to vars and filesystem for saving a keyfile */ -- cgit v1.2.3 From 6b47da10bea66d7a925de2850919b503201558be Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Mon, 22 Apr 2013 04:40:49 +0200 Subject: improved rename and file size support fix missing user_id on write --- apps/files_encryption/lib/proxy.php | 174 ++++++++++++++++++++--------------- apps/files_encryption/lib/stream.php | 31 ++++--- 2 files changed, 115 insertions(+), 90 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 67c93694e33..505fad440d5 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -288,38 +288,54 @@ class Proxy extends \OC_FileProxy { * @return bool Result of rename() * @note This is pre rather than post because using post didn't work */ - public function preRename( $oldPath, $newPath ) { - - // Disable encryption proxy to prevent recursive calls - \OC_FileProxy::$enabled = false; - - $view = new \OC_FilesystemView( '/' ); - - $userId = \OCP\USER::getUser(); - - // Format paths to be relative to user files dir - $oldTrimmed = ltrim( $oldPath, '/' ); - $oldSplit = explode( '/', $oldTrimmed ); - $oldSliced = array_slice( $oldSplit, 2 ); - $oldRelPath = implode( '/', $oldSliced ); - $oldKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $oldRelPath . '.key'; - - $newTrimmed = ltrim( $newPath, '/' ); - $newSplit = explode( '/', $newTrimmed ); - $newSliced = array_slice( $newSplit, 2 ); - $newRelPath = implode( '/', $newSliced ); - $newKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $newRelPath . '.key'; - - // Rename keyfile so it isn't orphaned - $result = $view->rename( $oldKeyfilePath, $newKeyfilePath ); - - \OC_FileProxy::$enabled = true; - - return $result; - - } - - public function postFopen( $path, &$result ){ + public function preRename( $oldPath, $newPath ) + { + + // Disable encryption proxy to prevent recursive calls + \OC_FileProxy::$enabled = false; + + $view = new \OC_FilesystemView('/'); + + $userId = \OCP\USER::getUser(); + + // Format paths to be relative to user files dir + $oldTrimmed = ltrim($oldPath, '/'); + $oldSplit = explode('/', $oldTrimmed); + $oldSliced = array_slice($oldSplit, 2); + $oldRelPath = implode('/', $oldSliced); + $oldKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $oldRelPath; + + + $newTrimmed = ltrim($newPath, '/'); + $newSplit = explode('/', $newTrimmed); + $newSliced = array_slice($newSplit, 2); + $newRelPath = implode('/', $newSliced); + $newKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $newRelPath; + + // add key ext if this is not an folder + if (!$view->is_dir($oldKeyfilePath)) { + $oldKeyfilePath .= '.key'; + $newKeyfilePath .= '.key'; + } else { + // handle share-keys folders + $oldShareKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'share-keys' . '/' . $oldRelPath; + $newShareKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'share-keys' . '/' . $newRelPath; + $view->rename($oldShareKeyfilePath, $newShareKeyfilePath); + } + + //TODO add support for share-keys files + //... + + // Rename keyfile so it isn't orphaned + $result = $view->rename($oldKeyfilePath, $newKeyfilePath); + + \OC_FileProxy::$enabled = true; + + return $result; + + } + + public function postFopen( $path, &$result ){ if ( !$result ) { @@ -421,49 +437,55 @@ class Proxy extends \OC_FileProxy { } public function postFileSize( $path, $size ) { - - // Reformat path for use with OC_FSV - $path_split = explode( '/', $path ); - $path_f = implode( '/', array_slice( $path_split, 3 ) ); - - if ( Crypt::isEncryptedMeta( $path_f ) ) { - - // Disable encryption proxy to prevent recursive calls - \OC_FileProxy::$enabled = false; - - // get file info - $cached = \OC\Files\Filesystem::getFileInfo( $path_f, '' ); - - // calculate last chunk nr - $lastChunckNr = floor( $size / 8192); - - // open stream - $result = fopen( 'crypt://'.$path_f, "r" ); - - // calculate last chunk position - $lastChunckPos = ( $lastChunckNr * 8192 ); - - // seek to end - fseek( $result, $lastChunckPos ); - - // get the content of the last chunck - $lastChunkContent = fgets( $result ); - - // calc the real filesize with the size of the last chunk - $realSize = ( ( $lastChunckNr * 6126 ) + strlen( $lastChunkContent ) ); - - // enable proxy - \OC_FileProxy::$enabled = true; - - // set the size - $cached['size'] = $realSize; - - return $cached['size']; - - } else { - - return $size; - - } + + // Reformat path for use with OC_FSV + $path_split = explode('/', $path); + $path_f = implode('/', array_slice($path_split, 3)); + + $view = new \OC_FilesystemView( '/' ); + $userId = \OCP\User::getUser(); + $util = new Util( $view, $userId ); + + if ($util->isEncryptedPath($path)) { + + // Disable encryption proxy to prevent recursive calls + \OC_FileProxy::$enabled = false; + + // get file info + $cached = \OC\Files\Filesystem::getFileInfo($path_f, ''); + + // calculate last chunk nr + $lastChunckNr = floor($size / 8192); + + // open stream + $result = fopen('crypt://' . $path_f, "r"); + + if(is_resource($result)) { + // calculate last chunk position + $lastChunckPos = ($lastChunckNr * 8192); + + // seek to end + fseek($result, $lastChunckPos); + + // get the content of the last chunck + $lastChunkContent = fgets($result); + + // calc the real file size with the size of the last chunk + $realSize = (($lastChunckNr * 6126) + strlen($lastChunkContent)); + + // set the size + $cached['size'] = $realSize; + } + + // enable proxy + \OC_FileProxy::$enabled = true; + + return $cached['size']; + + } else { + + return $size; + + } } } diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 4b33c200bf3..c12fab783b3 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -101,6 +101,9 @@ class Stream { } else { + // Disable fileproxies so we can get the file size and open the source file without recursive encryption + \OC_FileProxy::$enabled = false; + if ( $mode == 'w' or $mode == 'w+' @@ -119,9 +122,6 @@ class Stream { } - // Disable fileproxies so we can open the source file without recursive encryption - \OC_FileProxy::$enabled = false; - //$this->handle = fopen( $this->rawPath, $mode ); $this->handle = $this->rootView->fopen( $this->rawPath, $mode ); @@ -240,14 +240,13 @@ class Stream { // Avoid problems with .part file extensions $this->relPath = Keymanager::fixPartialFilePath( $this->relPath ); - + + // Fetch and decrypt keyfile + // Fetch existing keyfile + $this->encKeyfile = Keymanager::getFileKey( $this->rootView, $this->userId, $this->relPath ); + // If a keyfile already exists - if ( $this->rootView->file_exists( $this->userId . '/'. 'files_encryption' . '/' . 'keyfiles' . '/' . $this->relPath . '.key' ) ) { - - // Fetch and decrypt keyfile - // Fetch existing keyfile - $this->encKeyfile = Keymanager::getFileKey( $this->rootView, $this->userId, $this->relPath ); - + if ( $this->encKeyfile ) { $this->setUserProperty(); $session = new Session( $this->rootView ); @@ -338,11 +337,15 @@ class Stream { // Get all users sharing the file $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $this->relPath ); - + + // allways add current user + $uniqueUserIds[] = $this->userId; + array_unique( $uniqueUserIds ); + // Fetch public keys for all sharing users $publicKeys = Keymanager::getPublicKeys( $this->rootView, $uniqueUserIds ); - - // Encrypt enc key for all sharing users + + // Encrypt enc key for all sharing users $this->encKeyfiles = Crypt::multiKeyEncrypt( $this->plainKey, $publicKeys ); $view = new \OC_FilesystemView( '/' ); @@ -429,7 +432,7 @@ class Stream { $encrypted = $this->preWriteEncrypt( $chunk, $this->plainKey ); - trigger_error("\$encrypted = $encrypted"); + //trigger_error("\$encrypted = $encrypted"); // Write the data chunk to disk. This will be // attended to the last data chunk if the file -- cgit v1.2.3 From a2ba3c8a43780eab5ad8a4d96db33c584e7ae2ec Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Mon, 22 Apr 2013 11:58:39 +0200 Subject: fix sharing of folders. First we need to collect all files. Than we need to find all users with access to the file because this can vary from file to file and than we can encrypt it for all recipients --- apps/files_encryption/hooks/hooks.php | 58 ++++++++++++++++------------------- apps/files_encryption/lib/util.php | 20 ++++++++++++ 2 files changed, 47 insertions(+), 31 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 2731ee11125..13cf352b4ed 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -166,8 +166,8 @@ class Hooks { /** * @brief */ - public static function postShared( $params ) { - + public static function postShared($params) { + // NOTE: $params has keys: // [itemType] => file // itemSource -> int, filecache file ID @@ -183,50 +183,46 @@ class Hooks { // [fileSource] => 13 // [fileTarget] => /test8 // [id] => 10 - // [token] => - + // [token] => // TODO: Should other kinds of item be encrypted too? - if ( $params['itemType'] === 'file' ) { - - $view = new \OC_FilesystemView( '/' ); + if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') { + + $view = new \OC_FilesystemView('/'); $session = new Session($view); $userId = \OCP\User::getUser(); - $util = new Util( $view, $userId ); - $path = $util->fileIdToPath( $params['itemSource'] ); + $util = new Util($view, $userId); + $path = $util->fileIdToPath($params['itemSource']); $sharingEnabled = \OCP\Share::isEnabled(); - $usersSharing = $util->getSharingUsersArray( $sharingEnabled, $path); - - // Recursively expand path to include subfiles - $allPaths = $util->getPaths( $path ); - - $failed = array(); - - // Loop through all subfiles - foreach ( $allPaths as $path ) { - + + if ($params['itemType'] === 'folder') { + //list($owner, $ownerPath) = $util->getUidAndFilename($filePath); + $allFiles = $util->getAllFiles($path); + } else { + $allFiles = array($path); + } + + foreach ($allFiles as $path) { + $usersSharing = $util->getSharingUsersArray($sharingEnabled, $path); + + $failed = array(); + // Attempt to set shareKey - if ( ! $util->setSharedFileKeyfiles( $session, $usersSharing, $path ) ) { - + if (!$util->setSharedFileKeyfiles($session, $usersSharing, $path)) { + $failed[] = $path; - } - } - + // If no attempts to set keyfiles failed - if ( empty( $failed ) ) { - + if (empty($failed)) { + return true; - } else { - + return false; - } - } - } /** diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 8807de7c2ad..b3df7f0db03 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -939,4 +939,24 @@ class Util { } + /** + *@ brief geo recursively through a dir and collect all files and sub files. + * @param type $dir relative to the users files folder + * @return array with list of files relative to the users files folder + */ + public function getAllFiles($dir) { + $result = array(); + $path = $this->view->getLocalFile(); + $content = $this->view->getDirectoryContent("/".$this->userFilesDir.'/'.$this->filesFolderName.$dir); + + foreach ($content as $c) { + if ($c['type'] === "dir" ) { + $result = array_merge($result, $this->getAllFiles(substr($c['path'],5))); + } else { + $result[] = substr($c['path'], 5); + } + } + return $result; + } + } -- cgit v1.2.3 From 8a46e809f00745f4b67d118e85ec2d35e74b732e Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Mon, 22 Apr 2013 12:22:07 +0200 Subject: remove util::getPaths(), this function was broken and is replaced my util::getAllFiles(). When unsharing a folder only remove the share key for sub files if the user really no longer have access to the file. Can happen that a sub-file/-folder is shared to a group the user is a member of or explicitly once more to the same user --- apps/files_encryption/hooks/hooks.php | 21 ++++++++++----- apps/files_encryption/lib/util.php | 51 ----------------------------------- 2 files changed, 14 insertions(+), 58 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 13cf352b4ed..e3861e7cc5a 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -196,7 +196,6 @@ class Hooks { $sharingEnabled = \OCP\Share::isEnabled(); if ($params['itemType'] === 'folder') { - //list($owner, $ownerPath) = $util->getUidAndFilename($filePath); $allFiles = $util->getAllFiles($path); } else { $allFiles = array($path); @@ -250,13 +249,21 @@ class Hooks { $userIds = array($params['shareWith']); } - // If path is a folder, get all children - $allPaths = $util->getPaths( $path ); - - foreach ( $allPaths as $path ) { + if ($params['itemType'] === 'folder') { + $allFiles = $util->getAllFiles($path); + } else { + $allFiles = array($path); + } + - // Unshare each child path - if ( ! Keymanager::delShareKey( $view, $userIds, $path ) ) { + foreach ( $allFiles as $path ) { + + // check if the user still has access to the file, otherwise delete share key + $sharingUsers = $util->getSharingUsersArray(true, $path); + + // Unshare every user who no longer has access to the file + $delUsers = array_diff($userIds, $sharingUsers); + if ( ! Keymanager::delShareKey( $view, $delUsers, $path ) ) { $failed[] = $path; diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index b3df7f0db03..de63e0ff9f4 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -693,58 +693,7 @@ class Util { ); } - - /** - * @brief Expand given path to all sub files & folders - * @param string $path path which needs to be updated - * @return array $pathsArray all found file paths - * @note Paths of directories excluded, only *file* paths are returned - */ - public function getPaths( $path ) { - // Default return value is success - $result = true; - - // Make path include 'files' dir for OC_FSV operations - $fPath = 'files' . $path; - - // If we're handling a single file - if ( ! $this->view->is_dir( $fPath ) ) { - - $pathsArray[] = $path; - - // If we're handling a folder (recursively) - } else { - - $subFiles = $this->view->getDirectoryContent( $fPath ); - - foreach ( $subFiles as $file ) { - - $filePath = substr( $file['path'], 5 ); - - // If this is a nested file - if ( ! $this->view->is_dir( $fPath ) ) { - - // Add the file path to array - $pathsArray[] = $path; - - } else { - - // If this is a nested folder - $dirPaths = $this->getPaths( $filePath ); - - // Add all subfiles & folders to the array - $pathsArray = array_merge( $dirPaths, $pathsArray ); - - } - } - - } - - return $pathsArray; - - } - /** * @brief Decrypt a keyfile without knowing how it was encrypted * @param string $filePath -- cgit v1.2.3 From f6ac34afea6c1f68f53e0e7a076b0b274559fd8b Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Mon, 22 Apr 2013 12:25:55 +0200 Subject: improved handling for getSharingUsersArray --- apps/files_encryption/lib/proxy.php | 2 +- apps/files_encryption/lib/stream.php | 10 +++------- apps/files_encryption/lib/util.php | 9 +++++++-- 3 files changed, 11 insertions(+), 10 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 505fad440d5..bc6280ff61b 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -134,7 +134,7 @@ class Proxy extends \OC_FileProxy { $sharingEnabled = \OCP\Share::isEnabled(); - $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $filePath ); + $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $filePath, $userId ); // Fetch public keys for all users who will share the file $publicKeys = Keymanager::getPublicKeys( $rootView, $uniqueUserIds ); diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index c12fab783b3..6fb95934c32 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -335,14 +335,10 @@ class Stream { $util = new Util( $this->rootView, $this->userId ); - // Get all users sharing the file - $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $this->relPath ); + // Get all users sharing the file includes current user + $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $this->relPath, $this->userId); - // allways add current user - $uniqueUserIds[] = $this->userId; - array_unique( $uniqueUserIds ); - - // Fetch public keys for all sharing users + // Fetch public keys for all sharing users $publicKeys = Keymanager::getPublicKeys( $this->rootView, $uniqueUserIds ); // Encrypt enc key for all sharing users diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index b3df7f0db03..e69314e099a 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -848,7 +848,7 @@ class Util { * @brief Find, sanitise and format users sharing a file * @note This wraps other methods into a portable bundle */ - public function getSharingUsersArray( $sharingEnabled, $filePath ) { + public function getSharingUsersArray( $sharingEnabled, $filePath, $currentUserId = false ) { // Check if key recovery is enabled $recoveryEnabled = $this->recoveryEnabled(); @@ -878,7 +878,12 @@ class Util { $userIds[] = $adminUid; } - + + // add current user if given + if($currentUserId != false) { + $userIds[] = $currentUserId; + } + // Remove duplicate UIDs $uniqueUserIds = array_unique ( $userIds ); -- cgit v1.2.3 From 17059388482eabf6a1d05ea4c8d09e0f67ed9c43 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Mon, 22 Apr 2013 12:32:38 +0200 Subject: removed some leftover code; use already existing var for path to users file folder --- apps/files_encryption/lib/util.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index de63e0ff9f4..d1377df9a95 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -895,8 +895,8 @@ class Util { */ public function getAllFiles($dir) { $result = array(); - $path = $this->view->getLocalFile(); - $content = $this->view->getDirectoryContent("/".$this->userFilesDir.'/'.$this->filesFolderName.$dir); + + $content = $this->view->getDirectoryContent($this->userFilesDir.$dir); foreach ($content as $c) { if ($c['type'] === "dir" ) { -- cgit v1.2.3 From b57478fa27a2dc2dcfeba68064e44aca5848e145 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Mon, 22 Apr 2013 14:14:28 +0200 Subject: fix comment, remove unused variable --- apps/files_encryption/lib/util.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index d1377df9a95..1ba339c15df 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -805,15 +805,10 @@ class Util { // Make sure that a share key is generated for the owner too list($owner, $ownerPath) = $this->getUidAndFilename($filePath); - //$userIds = array( $this->userId ); - $userIds = array(); - if ( $sharingEnabled ) { // Find out who, if anyone, is sharing the file - $shareUids = \OCP\Share::getUsersSharingFile( $ownerPath, $owner,true, true, true ); - - $userIds = array_merge( $userIds, $shareUids ); + $userIds = \OCP\Share::getUsersSharingFile( $ownerPath, $owner,true, true, true ); } @@ -889,7 +884,7 @@ class Util { } /** - *@ brief geo recursively through a dir and collect all files and sub files. + * @brief geo recursively through a dir and collect all files and sub files. * @param type $dir relative to the users files folder * @return array with list of files relative to the users files folder */ -- cgit v1.2.3 From b5cb5dab513441b8c914aaa043921d0affae4604 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Mon, 22 Apr 2013 14:30:10 +0200 Subject: fix encryption to owncloud user for public link shares --- apps/files_encryption/lib/keymanager.php | 2 +- apps/files_encryption/lib/util.php | 2 +- lib/public/share.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index f23423062b9..6fb1f128b5e 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -54,7 +54,7 @@ class Keymanager { \OC_FileProxy::$enabled = false; - return $view->file_get_contents( '/public-keys/' . '/' . $userId . '.public.key' ); + return $view->file_get_contents( '/public-keys/' . $userId . '.public.key' ); \OC_FileProxy::$enabled = true; diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 1ba339c15df..143ba69f254 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -668,7 +668,7 @@ class Util { // public system user 'ownCloud' (for public shares) if ( $util->ready() - or $user == 'ownCloud' + or $user == 'owncloud' ) { // Construct array of ready UIDs for Keymanager{} diff --git a/lib/public/share.php b/lib/public/share.php index 9fd8eb42fb7..5cd556c6acb 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -200,7 +200,7 @@ class Share { } if ($result->fetchRow()) { - $shares[] = "ownCloud"; + $shares[] = "owncloud"; } } // Include owner in list of users, if requested -- cgit v1.2.3 From a4364a93d0e80e0d1daa2b28713df05c25970fd1 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Mon, 22 Apr 2013 15:29:58 +0200 Subject: delete all share keys if a file gets deleted --- apps/files_encryption/lib/keymanager.php | 21 ++++++++++++++++++++- apps/files_encryption/lib/proxy.php | 11 +++-------- 2 files changed, 23 insertions(+), 9 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 6fb1f128b5e..9885f5e5508 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -391,7 +391,26 @@ class Keymanager { return $result; } - + + /** + * @brief delete all share keys of a given file + * @param \OC_FilesystemView $view + * @param type $userId owner of the file + * @param type $filePath path to the file, relative to the owners file dir + */ + public static function delAllShareKeys(\OC_FilesystemView $view, $userId, $filePath) { + + if ($view->is_dir($userId.'/files/'.$filePath)) { + $view->unlink($userId.'/files_encryption/share-keys/'.$filePath); + } else { + $localKeyPath = $view->getLocalFile($userId.'/files_encryption/share-keys/'.$filePath); + $matches = glob(preg_quote($localKeyPath).'*.shareKey'); + foreach ($matches as $ma) { + unlink($ma); + } + } + } + /** * @brief Delete a single user's shareKey for a single file */ diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 505fad440d5..bd25465ee69 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -256,18 +256,13 @@ class Proxy extends \OC_FileProxy { // Format path to be relative to user files dir $relPath = $util->stripUserFilesPath( $path ); -// list( $owner, $ownerPath ) = $util->getUidAndFilename( $relPath ); - - $fileOwner = \OC\Files\Filesystem::getOwner( $path ); - $ownerPath = $util->stripUserFilesPath( $path ); // TODO: Don't trust $path, fetch owner path - - $filePath = $fileOwner . '/' . 'files_encryption' . '/' . 'keyfiles' . '/'. $ownerPath; + list( $owner, $ownerPath ) = $util->getUidAndFilename( $relPath ); // Delete keyfile & shareKey so it isn't orphaned if ( ! ( - Keymanager::deleteFileKey( $view, $fileOwner, $ownerPath ) - && Keymanager::delShareKey( $view, $fileOwner, $ownerPath ) + Keymanager::deleteFileKey( $view, $owner, $ownerPath ) + && Keymanager::delAllShareKeys( $view, $owner, $ownerPath ) ) ) { -- cgit v1.2.3 From 37c72059417d2f2f776ee4318e3705adf6c54fe7 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Mon, 22 Apr 2013 18:50:59 +0200 Subject: fix wrong file path in util --- apps/files_encryption/lib/util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 9868aba02e8..6e8786b7cdb 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -337,7 +337,7 @@ class Util { // scanning every file like this // will eat server resources :( if ( - Keymanager::getFileKey( $this->view, $this->userId, $file ) + Keymanager::getFileKey( $this->view, $this->userId, $relPath ) && Crypt::isCatfileContent( $data ) ) { -- cgit v1.2.3 From 8ab9433fdff179649a5e5b9d6046d85efd81d3b8 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Mon, 22 Apr 2013 18:54:23 +0200 Subject: fix wrong file path in proxy --- apps/files_encryption/lib/proxy.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 1a96f1e4955..e058a528ad0 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -266,7 +266,7 @@ class Proxy extends \OC_FileProxy { ) ) { - \OC_Log::write( 'Encryption library', 'Keyfile or shareKey could not be deleted for file "'.$filePath.'"', \OC_Log::ERROR ); + \OC_Log::write( 'Encryption library', 'Keyfile or shareKey could not be deleted for file "'.$ownerPath.'"', \OC_Log::ERROR ); } -- cgit v1.2.3 From a1d241783ee44529fac99ba25cb34b658f827876 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Tue, 23 Apr 2013 14:12:28 +0200 Subject: Updated buglist --- apps/files_encryption/lib/util.php | 4 ---- 1 file changed, 4 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 1b69ad320cf..f7bb51a8613 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -24,20 +24,16 @@ # Bugs # ---- # Sharing a file to a user without encryption set up will not provide them with access but won't notify the sharer -# Sharing files to other users currently broken (due to merge + ongoing implementation of support for lost password recovery) # Timeouts on first login due to encryption of very large files (fix in progress, as a result streaming is currently broken) # Sharing all files to admin for recovery purposes still in progress # Possibly public links are broken (not tested since last merge of master) -# getOwner() currently returns false in all circumstances, unsure what code is returning this... # encryptAll during login mangles paths: /files/files/ # encryptAll is accessing files via encryption proxy - perhaps proxies should be disabled? -# Sharekeys appear to not be deleted when their parent file is, and thus get orphaned # Missing features # ---------------- # Make sure user knows if large files weren't encrypted -# Support for resharing encrypted files # Test -- cgit v1.2.3 From c6bfc7315b380710d7c59f7bb23588822063dc6f Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Tue, 23 Apr 2013 17:36:35 +0200 Subject: Stream writing improved: working with dolphin + kate, gedit & nautilus give errors, suspect those issues are clientside .part file paths fixed in stream{} --- apps/files_encryption/lib/proxy.php | 5 ----- apps/files_encryption/lib/stream.php | 22 ++++++---------------- apps/files_encryption/lib/util.php | 2 +- 3 files changed, 7 insertions(+), 22 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index e058a528ad0..0d20ff1af1a 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -118,9 +118,6 @@ class Proxy extends \OC_FileProxy { // Decrypt the keyfile $plainKey = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); - -// trigger_error("\$shareKey = $shareKey"); -// trigger_error("\$plainKey = $plainKey"); } else { @@ -207,8 +204,6 @@ class Proxy extends \OC_FileProxy { $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); $plainData = Crypt::symmetricDecryptFileContent( $data, $plainKeyfile ); - -// trigger_error("PLAINDATA = ". var_export($plainData, 1)); } elseif ( Crypt::mode() == 'server' diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 6fb95934c32..9a37c3b08ee 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -86,6 +86,9 @@ class Stream { // rawPath is relative to the data directory $this->rawPath = $this->userId . '/files/' . $this->relPath; + // Fix .part filenames + $this->rawPath = Keymanager::fixPartialFilePath( $this->rawPath ); + if ( dirname( $this->rawPath ) == 'streams' and isset( self::$sourceStreams[basename( $this->rawPath )] ) @@ -257,11 +260,6 @@ class Stream { $this->plainKey = Crypt::multiKeyDecrypt( $this->encKeyfile, $shareKey, $privateKey ); -// trigger_error( '$this->relPath = '.$this->relPath ); -// trigger_error( '$this->userId = '.$this->userId); -// trigger_error( '$this->encKeyfile = '.$this->encKeyfile ); -// trigger_error( '$this->plainKey1 = '.var_export($this->plainKey, 1)); - return true; } else { @@ -352,12 +350,6 @@ class Stream { // Save the sharekeys Keymanager::setShareKeys( $view, $this->relPath, $this->encKeyfiles['keys'] ); -// trigger_error( "\$this->encKeyfiles['data'] = ".$this->encKeyfiles['data'] ); -// trigger_error( '$this->relPath = '.$this->relPath ); -// trigger_error( '$this->userId = '.$this->userId); -// trigger_error( '$this->encKeyfile = '.var_export($this->encKeyfiles, 1) ); -// trigger_error( '$this->plainKey2 = '.var_export($this->plainKey, 1)); - // If extra data is left over from the last round, make sure it // is integrated into the next 6126 / 8192 block if ( $this->writeCache ) { @@ -420,7 +412,7 @@ class Stream { // Clear $data ready for next round $data = ''; -// + } else { // Read the chunk from the start of $data @@ -428,8 +420,6 @@ class Stream { $encrypted = $this->preWriteEncrypt( $chunk, $this->plainKey ); - //trigger_error("\$encrypted = $encrypted"); - // Write the data chunk to disk. This will be // attended to the last data chunk if the file // being handled totals more than 6126 bytes @@ -515,9 +505,9 @@ class Stream { \OC\Files\Filesystem::putFileInfo( $this->relPath, array( 'encrypted' => true, 'size' => $this->size ), '' ); } - - return fclose( $this->handle ); + return fclose( $this->handle ); + } } diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index f7bb51a8613..38b4219f6e2 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -492,7 +492,7 @@ class Util { * @note Encryption is recursive */ public function encryptAll( $publicKey, $dirPath, $legacyPassphrase = null, $newPassphrase = null ) { - + if ( $found = $this->findEncFiles( $dirPath ) ) { // Disable proxy to prevent file being encrypted twice -- cgit v1.2.3 From b7d8da87d0b094c5e55a0ac43995074fa3351618 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Tue, 23 Apr 2013 18:41:01 +0200 Subject: Development snapshot working on stream handling (large files) in Util->encryptAll() --- apps/files_encryption/lib/keymanager.php | 3 +- apps/files_encryption/lib/proxy.php | 1 - apps/files_encryption/lib/util.php | 50 +++++++++++++++++--------------- 3 files changed, 28 insertions(+), 26 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 9885f5e5508..0e1dafeed75 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -106,6 +106,7 @@ class Keymanager { */ public static function setFileKey( \OC_FilesystemView $view, $path, $userId, $catfile ) { + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; //here we need the currently logged in user, while userId can be a different user @@ -129,7 +130,7 @@ class Keymanager { $result = $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); - \OC_FileProxy::$enabled = true; + \OC_FileProxy::$enabled = $proxyStatus; return $result; diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 0d20ff1af1a..620f7cc8c31 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -142,7 +142,6 @@ class Proxy extends \OC_FileProxy { $multiEncrypted = Crypt::multiKeyEncrypt( $plainKey, $publicKeys ); // Save sharekeys to user folders - Keymanager::setShareKeys( $rootView, $filePath, $multiEncrypted['keys'] ); // Set encrypted keyfile as common varname diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 38b4219f6e2..f9198e0606a 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -500,37 +500,39 @@ class Util { // Encrypt unencrypted files foreach ( $found['plain'] as $plainFile ) { - - // Open plain file handle - - - // Open enc file handle - - - // Read plain file in chunks //relative to data//file $relPath = $plainFile['path']; + //relative to /data $rawPath = $this->userId . '/files/' . $plainFile['path']; - - // Open handle with for binary reading - $plainHandle = $this->view->fopen( $rawPath, 'rb' ); - // Open handle with for binary writing - - $encHandle = fopen( 'crypt://' . $relPath . '.tmp', 'wb' ); - // Overwrite the existing file with the encrypted one - //$this->view->file_put_contents( $plainFile['path'], $encrypted['data'] ); - $size = stream_copy_to_stream( $plainHandle, $encHandle ); - - $this->view->rename($rawPath . '.tmp', $rawPath); - - // Fetch the key that has just been set/updated by the stream - //$encKey = Keymanager::getFileKey( $this->view, $this->userId, $relPath ); + // Open plain file handle for binary reading + $plainHandle1 = $this->view->fopen( $rawPath, 'rb' ); + + // 2nd handle for moving plain file - view->rename() doesn't work, this is a workaround + $plainHandle2 = $this->view->fopen( $rawPath . '.plaintmp', 'wb' ); + + // Move plain file to a temporary location + stream_copy_to_stream( $plainHandle1, $plainHandle2 ); + + // Close access to original file +// $this->view->fclose( $plainHandle1 ); // not implemented in view{} + + // Delete original plain file so we can rename enc file later + $this->view->unlink( $rawPath ); + + // Open enc file handle for binary writing, with same filename as original plain file + $encHandle = fopen( 'crypt://' . $relPath, 'wb' ); + + // Save data from plain stream to new encrypted file via enc stream + // NOTE: Stream{} will be invoked for handling + // the encryption, and should handle all keys + // and their generation etc. automatically + $size = stream_copy_to_stream( $plainHandle2, $encHandle ); - // Save keyfile - //Keymanager::setFileKey( $this->view, $relPath, $this->userId, $encKey ); + // Delete temporary plain copy of file + $this->view->unlink( $rawPath . '.plaintmp' ); // Add the file to the cache \OC\Files\Filesystem::putFileInfo( $plainFile['path'], array( 'encrypted'=>true, 'size' => $size ), '' ); -- cgit v1.2.3 From baa6fd639fb9e6b2a954975603428603fcd04a85 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Tue, 23 Apr 2013 19:08:52 +0200 Subject: improved file size handling --- apps/files_encryption/lib/proxy.php | 92 ++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 32 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index e058a528ad0..cb7cb8a2cc7 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -91,14 +91,14 @@ class Proxy extends \OC_FileProxy { return false; } - public function preFile_put_contents( $path, &$data ) { - - if ( self::shouldEncrypt( $path ) ) { - - // Stream put contents should have been converted to fopen + public function preFile_put_contents( $path, &$data ) { + + if ( self::shouldEncrypt( $path ) ) { + + // Stream put contents should have been converted to fopen if ( !is_resource( $data ) ) { - - $userId = \OCP\USER::getUser(); + + $userId = \OCP\USER::getUser(); $rootView = new \OC_FilesystemView( '/' ); $util = new Util( $rootView, $userId ); $session = new Session( $rootView ); @@ -135,8 +135,8 @@ class Proxy extends \OC_FileProxy { $sharingEnabled = \OCP\Share::isEnabled(); $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $filePath, $userId ); - - // Fetch public keys for all users who will share the file + + // Fetch public keys for all users who will share the file $publicKeys = Keymanager::getPublicKeys( $rootView, $uniqueUserIds ); \OC_FileProxy::$enabled = false; @@ -165,7 +165,8 @@ class Proxy extends \OC_FileProxy { } } - + + return true; } /** @@ -174,7 +175,7 @@ class Proxy extends \OC_FileProxy { */ public function postFile_get_contents( $path, $data ) { - // FIXME: $path for shared files is just /uid/files/Shared/filepath + // FIXME: $path for shared files is just /uid/files/Shared/filepath $userId = \OCP\USER::getUser(); $view = new \OC_FilesystemView( '/' ); @@ -300,7 +301,6 @@ class Proxy extends \OC_FileProxy { $oldRelPath = implode('/', $oldSliced); $oldKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $oldRelPath; - $newTrimmed = ltrim($newPath, '/'); $newSplit = explode('/', $newTrimmed); $newSliced = array_slice($newSplit, 2); @@ -331,14 +331,14 @@ class Proxy extends \OC_FileProxy { } public function postFopen( $path, &$result ){ - - if ( !$result ) { + + if ( !$result ) { return $result; } - - // Reformat path for use with OC_FSV + + // Reformat path for use with OC_FSV $path_split = explode( '/', $path ); $path_f = implode( '/', array_slice( $path_split, 3 ) ); @@ -394,8 +394,8 @@ class Proxy extends \OC_FileProxy { // fclose( $tmp ); } - - $result = fopen( 'crypt://'.$path_f, $meta['mode'] ); + + $result = fopen( 'crypt://'.$path_f, $meta['mode'] ); } @@ -407,8 +407,8 @@ class Proxy extends \OC_FileProxy { } public function postGetMimeType( $path, $mime ) { - - if ( Crypt::isCatfileContent( $path ) ) { + + if ( Crypt::isCatfileContent( $path ) ) { $mime = \OCP\Files::getMimeType( 'crypt://' . $path, 'w' ); @@ -418,9 +418,28 @@ class Proxy extends \OC_FileProxy { } + public function postGetFileInfo( $path, $data ) { + + // if path is a folder do nothing + if(is_array($data) && array_key_exists('size', $data)) { + // Disable encryption proxy to prevent recursive calls + \OC_FileProxy::$enabled = false; + + // get file size + $data['size'] = self::postFileSize($path, $data['size']); + + // Re-enable the proxy + \OC_FileProxy::$enabled = true; + + trigger_error('postGetFileInfo '.$path.' size: '.$data['size']); + } + + return $data; + } + public function postStat( $path, $data ) { - - if ( Crypt::isCatfileContent( $path ) ) { + + if ( Crypt::isCatfileContent( $path ) ) { $cached = \OC\Files\Filesystem::getFileInfo( $path, '' ); @@ -433,29 +452,38 @@ class Proxy extends \OC_FileProxy { public function postFileSize( $path, $size ) { + $view = new \OC_FilesystemView( '/' ); + + // if path is a folder do nothing + if($view->is_dir($path)) { + return $size; + } + // Reformat path for use with OC_FSV $path_split = explode('/', $path); $path_f = implode('/', array_slice($path_split, 3)); - $view = new \OC_FilesystemView( '/' ); $userId = \OCP\User::getUser(); $util = new Util( $view, $userId ); - if ($util->isEncryptedPath($path)) { + + // FIXME: is there a better solution to check if file belongs to files path? + // only get file size if file is in 'files' path + if (count($path_split) >= 2 && $path_split[2] == 'files' && $util->isEncryptedPath($path)) { // Disable encryption proxy to prevent recursive calls \OC_FileProxy::$enabled = false; - // get file info - $cached = \OC\Files\Filesystem::getFileInfo($path_f, ''); - - // calculate last chunk nr - $lastChunckNr = floor($size / 8192); - // open stream $result = fopen('crypt://' . $path_f, "r"); if(is_resource($result)) { + // don't trust the given size, allways get the size from filesystem + $size = $view->filesize($path); + + // calculate last chunk nr + $lastChunckNr = floor($size / 8192); + // calculate last chunk position $lastChunckPos = ($lastChunckNr * 8192); @@ -469,13 +497,13 @@ class Proxy extends \OC_FileProxy { $realSize = (($lastChunckNr * 6126) + strlen($lastChunkContent)); // set the size - $cached['size'] = $realSize; + $size = $realSize; } // enable proxy \OC_FileProxy::$enabled = true; - return $cached['size']; + return $size; } else { -- cgit v1.2.3 From 170d09203f376fad452fc6959729a0f778b5934f Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Thu, 25 Apr 2013 14:56:11 +0200 Subject: fixed file_proxy handling --- apps/files_encryption/lib/keymanager.php | 52 ++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 19 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 0e1dafeed75..ceefe8887ac 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -51,12 +51,15 @@ class Keymanager { * @return string public key or false */ public static function getPublicKey( \OC_FilesystemView $view, $userId ) { - + + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - return $view->file_get_contents( '/public-keys/' . $userId . '.public.key' ); + $result = $view->file_get_contents( '/public-keys/' . $userId . '.public.key' ); - \OC_FileProxy::$enabled = true; + \OC_FileProxy::$enabled = $proxyStatus; + + return $result; } @@ -175,7 +178,8 @@ class Keymanager { $filePath_f = ltrim( $filename, '/' ); $keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key'; - + + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; if ( $view->file_exists( $keyfilePath ) ) { @@ -188,7 +192,7 @@ class Keymanager { } - \OC_FileProxy::$enabled = true; + \OC_FileProxy::$enabled = $proxyStatus; return $result; @@ -243,15 +247,17 @@ class Keymanager { $user = \OCP\User::getUser(); $view = new \OC_FilesystemView( '/' . $user . '/files_encryption' ); - + + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; if ( !$view->file_exists( '' ) ) $view->mkdir( '' ); - return $view->file_put_contents( $user . '.private.key', $key ); - - \OC_FileProxy::$enabled = true; + $result = $view->file_put_contents( $user . '.private.key', $key ); + \OC_FileProxy::$enabled = $proxyStatus; + + return $result; } /** @@ -276,14 +282,17 @@ class Keymanager { public static function setPublicKey( $key ) { $view = new \OC_FilesystemView( '/public-keys' ); - + + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; if ( !$view->file_exists( '' ) ) $view->mkdir( '' ); - return $view->file_put_contents( \OCP\User::getUser() . '.public.key', $key ); + $result = $view->file_put_contents( \OCP\User::getUser() . '.public.key', $key ); - \OC_FileProxy::$enabled = true; + \OC_FileProxy::$enabled = $proxyStatus; + + return $result; } @@ -310,11 +319,14 @@ class Keymanager { $shareKeyPath = self::keySetPreparation( $view, $filename, $basePath, $owner ); $writePath = $basePath . '/' . $shareKeyPath . '.' . $userId . '.shareKey'; - + + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; $result = $view->file_put_contents( $writePath, $shareKey ); - + + \OC_FileProxy::$enabled = $proxyStatus; + if ( is_int( $result ) && $result > 0 @@ -368,7 +380,8 @@ class Keymanager { * of the keyfile must be performed by client code */ public static function getShareKey( \OC_FilesystemView $view, $userId, $filePath ) { - + + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; //here we need the currently logged in user, while userId can be a different user @@ -387,7 +400,7 @@ class Keymanager { } - \OC_FileProxy::$enabled = true; + \OC_FileProxy::$enabled = $proxyStatus; return $result; @@ -416,7 +429,8 @@ class Keymanager { * @brief Delete a single user's shareKey for a single file */ public static function delShareKey( \OC_FilesystemView $view, $userIds, $filePath ) { - + + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; //here we need the currently logged in user, while userId can be a different user @@ -448,7 +462,7 @@ class Keymanager { } - \OC_FileProxy::$enabled = false; + \OC_FileProxy::$enabled = $proxyStatus; return $result; @@ -472,7 +486,7 @@ class Keymanager { foreach ( $subdirs as $subdir ) { self::recursiveDelShareKeys($subdir, $userIds); } - return $true; + return true; } /** -- cgit v1.2.3 From fac288a4ad8f6db907c0a2ddfeb0b772fe616db5 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Thu, 25 Apr 2013 15:20:06 +0200 Subject: added unencrypted file size to file cache improved file size calculation and speeds --- apps/files_encryption/lib/proxy.php | 113 +++++++++++++---------------------- apps/files_encryption/lib/stream.php | 14 +++-- db_structure.xml | 8 +++ lib/files/cache/cache.php | 11 ++-- 4 files changed, 62 insertions(+), 84 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index b805ec648d4..c07b9a8a7aa 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -108,7 +108,8 @@ class Proxy extends \OC_FileProxy { $size = strlen( $data ); // Disable encryption proxy to prevent recursive calls - \OC_FileProxy::$enabled = false; + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; // Check if there is an existing key we can reuse if ( $encKeyfile = Keymanager::getFileKey( $rootView, $userId, $filePath ) ) { @@ -135,10 +136,8 @@ class Proxy extends \OC_FileProxy { // Fetch public keys for all users who will share the file $publicKeys = Keymanager::getPublicKeys( $rootView, $uniqueUserIds ); - - \OC_FileProxy::$enabled = false; - - // Encrypt plain keyfile to multiple sharefiles + + // Encrypt plain keyfile to multiple sharefiles $multiEncrypted = Crypt::multiKeyEncrypt( $plainKey, $publicKeys ); // Save sharekeys to user folders @@ -157,7 +156,7 @@ class Proxy extends \OC_FileProxy { \OC\Files\Filesystem::putFileInfo( $path, array( 'encrypted'=>true, 'size' => $size ), '' ); // Re-enable proxy - our work is done - \OC_FileProxy::$enabled = true; + \OC_FileProxy::$enabled = $proxyStatus; } } @@ -182,9 +181,10 @@ class Proxy extends \OC_FileProxy { // TODO check for existing key file and reuse it if possible to avoid problems with versioning etc. // Disable encryption proxy to prevent recursive calls - \OC_FileProxy::$enabled = false; - - // If data is a catfile + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + // If data is a catfile if ( Crypt::mode() == 'server' && Crypt::isCatfileContent( $data ) // TODO: Do we really need this check? Can't we assume it is properly encrypted? @@ -215,7 +215,7 @@ class Proxy extends \OC_FileProxy { } - \OC_FileProxy::$enabled = true; + \OC_FileProxy::$enabled = $proxyStatus; if ( ! isset( $plainData ) ) { @@ -240,7 +240,8 @@ class Proxy extends \OC_FileProxy { $path = Keymanager::fixPartialFilePath( $path ); // Disable encryption proxy to prevent recursive calls - \OC_FileProxy::$enabled = false; + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; $view = new \OC_FilesystemView( '/' ); @@ -265,7 +266,7 @@ class Proxy extends \OC_FileProxy { } - \OC_FileProxy::$enabled = true; + \OC_FileProxy::$enabled = $proxyStatus; // If we don't return true then file delete will fail; better // to leave orphaned keyfiles than to disallow file deletion @@ -282,6 +283,7 @@ class Proxy extends \OC_FileProxy { { // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; $view = new \OC_FilesystemView('/'); @@ -318,7 +320,7 @@ class Proxy extends \OC_FileProxy { // Rename keyfile so it isn't orphaned $result = $view->rename($oldKeyfilePath, $newKeyfilePath); - \OC_FileProxy::$enabled = true; + \OC_FileProxy::$enabled = $proxyStatus; return $result; @@ -337,9 +339,10 @@ class Proxy extends \OC_FileProxy { $path_f = implode( '/', array_slice( $path_split, 3 ) ); // Disable encryption proxy to prevent recursive calls - \OC_FileProxy::$enabled = false; - - $meta = stream_get_meta_data( $result ); + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $meta = stream_get_meta_data( $result ); $view = new \OC_FilesystemView( '' ); @@ -369,13 +372,13 @@ class Proxy extends \OC_FileProxy { // NOTE: this is the case for new files saved via WebDAV - if ( - $view->file_exists( $path ) - and $view->filesize( $path ) > 0 - ) { - $x = $view->file_get_contents( $path ); - - $tmp = tmpfile(); +// if ( +// $view->file_exists( $path ) +// and $view->filesize( $path ) > 0 +// ) { +// $x = $view->file_get_contents( $path ); +// +// $tmp = tmpfile(); // // Make a temporary copy of the original file // \OCP\Files::streamCopy( $result, $tmp ); @@ -387,14 +390,14 @@ class Proxy extends \OC_FileProxy { // // fclose( $tmp ); - } +// } $result = fopen( 'crypt://'.$path_f, $meta['mode'] ); } // Re-enable the proxy - \OC_FileProxy::$enabled = true; + \OC_FileProxy::$enabled = $proxyStatus; return $result; @@ -417,15 +420,15 @@ class Proxy extends \OC_FileProxy { // if path is a folder do nothing if(is_array($data) && array_key_exists('size', $data)) { // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; + // get file size $data['size'] = self::postFileSize($path, $data['size']); // Re-enable the proxy - \OC_FileProxy::$enabled = true; - - trigger_error('postGetFileInfo '.$path.' size: '.$data['size']); + \OC_FileProxy::$enabled = $proxyStatus; } return $data; @@ -437,7 +440,7 @@ class Proxy extends \OC_FileProxy { $cached = \OC\Files\Filesystem::getFileInfo( $path, '' ); - $data['size'] = $cached['size']; + $data['size'] = $cached['unencrypted_size']; } @@ -453,56 +456,20 @@ class Proxy extends \OC_FileProxy { return $size; } + $path = Keymanager::fixPartialFilePath( $path ); + // Reformat path for use with OC_FSV $path_split = explode('/', $path); $path_f = implode('/', array_slice($path_split, 3)); - $userId = \OCP\User::getUser(); - $util = new Util( $view, $userId ); - - - // FIXME: is there a better solution to check if file belongs to files path? - // only get file size if file is in 'files' path - if (count($path_split) >= 2 && $path_split[2] == 'files' && $util->isEncryptedPath($path)) { - - // Disable encryption proxy to prevent recursive calls - \OC_FileProxy::$enabled = false; - - // open stream - $result = fopen('crypt://' . $path_f, "r"); - - if(is_resource($result)) { - // don't trust the given size, allways get the size from filesystem - $size = $view->filesize($path); - - // calculate last chunk nr - $lastChunckNr = floor($size / 8192); - - // calculate last chunk position - $lastChunckPos = ($lastChunckNr * 8192); - - // seek to end - fseek($result, $lastChunckPos); - - // get the content of the last chunck - $lastChunkContent = fgets($result); - - // calc the real file size with the size of the last chunk - $realSize = (($lastChunckNr * 6126) + strlen($lastChunkContent)); - - // set the size - $size = $realSize; - } - - // enable proxy - \OC_FileProxy::$enabled = true; - - return $size; + // get file info from database/cache + $fileInfo = \OC\Files\Filesystem::getFileInfo($path_f); + // if file is encrypted return real file size + if(is_array($fileInfo) && $fileInfo['encrypted'] == 1) { + return $fileInfo['unencrypted_size']; } else { - - return $size; - + return $fileInfo['size']; } } } diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 9a37c3b08ee..7e42627f8ca 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -64,6 +64,7 @@ class Stream { private $count; private $writeCache; public $size; + public $unencryptedSize; private $publicKey; private $keyfile; private $encKeyfile; @@ -105,6 +106,7 @@ class Stream { } else { // Disable fileproxies so we can get the file size and open the source file without recursive encryption + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; if ( @@ -116,6 +118,7 @@ class Stream { // We're writing a new file so start write counter with 0 bytes $this->size = 0; + $this->unencryptedSize = 0; } else { @@ -129,7 +132,7 @@ class Stream { $this->handle = $this->rootView->fopen( $this->rawPath, $mode ); - \OC_FileProxy::$enabled = true; + \OC_FileProxy::$enabled = $proxyStatus; if ( ! is_resource( $this->handle ) ) { @@ -301,7 +304,7 @@ class Stream { // automatically attempted when the file is written to disk - // we are handling that separately here and we don't want to // get into an infinite loop - \OC_FileProxy::$enabled = false; + //\OC_FileProxy::$enabled = false; // Get the length of the unencrypted data that we are handling $length = strlen( $data ); @@ -438,7 +441,8 @@ class Stream { } $this->size = max( $this->size, $pointer + $length ); - + $this->unencryptedSize += $length; + return $length; } @@ -501,9 +505,7 @@ class Stream { $this->meta['mode']!='r' and $this->meta['mode']!='rb' ) { - - \OC\Files\Filesystem::putFileInfo( $this->relPath, array( 'encrypted' => true, 'size' => $this->size ), '' ); - + \OC\Files\Filesystem::putFileInfo( $this->relPath, array( 'encrypted' => 1, 'size' => $this->size, 'unencrypted_size' => $this->unencryptedSize ), '' ); } return fclose( $this->handle ); diff --git a/db_structure.xml b/db_structure.xml index dce90697b1c..366f51a82d0 100644 --- a/db_structure.xml +++ b/db_structure.xml @@ -288,6 +288,14 @@ 4 + + unencrypted_size + integer + + true + 8 + + etag text diff --git a/lib/files/cache/cache.php b/lib/files/cache/cache.php index 71b70abe3fe..4e32ff2ba8a 100644 --- a/lib/files/cache/cache.php +++ b/lib/files/cache/cache.php @@ -117,7 +117,7 @@ class Cache { $params = array($file); } $query = \OC_DB::prepare( - 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag` + 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag` FROM `*PREFIX*filecache` ' . $where); $result = $query->execute($params); $data = $result->fetchRow(); @@ -133,6 +133,7 @@ class Cache { $data['size'] = (int)$data['size']; $data['mtime'] = (int)$data['mtime']; $data['encrypted'] = (bool)$data['encrypted']; + $data['unencrypted_size'] = (int)$data['unencrypted_size']; $data['storage'] = $this->storageId; $data['mimetype'] = $this->getMimetype($data['mimetype']); $data['mimepart'] = $this->getMimetype($data['mimepart']); @@ -151,7 +152,7 @@ class Cache { $fileId = $this->getId($folder); if ($fileId > -1) { $query = \OC_DB::prepare( - 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag` + 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag` FROM `*PREFIX*filecache` WHERE parent = ? ORDER BY `name` ASC'); $result = $query->execute(array($fileId)); $files = $result->fetchAll(); @@ -234,7 +235,7 @@ class Cache { * @return array */ function buildParts(array $data) { - $fields = array('path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'encrypted', 'etag'); + $fields = array('path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'encrypted', 'unencrypted_size', 'etag'); $params = array(); $queryParts = array(); foreach ($data as $name => $value) { @@ -391,7 +392,7 @@ class Cache { */ public function search($pattern) { $query = \OC_DB::prepare(' - SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag` + SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag` FROM `*PREFIX*filecache` WHERE `name` LIKE ? AND `storage` = ?' ); $result = $query->execute(array($pattern, $this->numericId)); @@ -417,7 +418,7 @@ class Cache { $where = '`mimepart` = ?'; } $query = \OC_DB::prepare(' - SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag` + SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag` FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?' ); $mimetype = $this->getMimetypeId($mimetype); -- cgit v1.2.3 From 328dea93c7a4a68bfb83c15f97af64275c953782 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Thu, 25 Apr 2013 20:23:54 +0200 Subject: webdav fix for file chunking upload with big files should now work @samtuke and @schiesbn we need a solution for the cache files created by webdav --- apps/files_encryption/lib/proxy.php | 7 ++++++- apps/files_encryption/lib/util.php | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index c07b9a8a7aa..66ea282312e 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -337,7 +337,12 @@ class Proxy extends \OC_FileProxy { // Reformat path for use with OC_FSV $path_split = explode( '/', $path ); $path_f = implode( '/', array_slice( $path_split, 3 ) ); - + + // FIXME: handling for /userId/cache used by webdav for chunking. The cache chunks are NOT encrypted + if($path_split[2] == 'cache') { + return $result; + } + // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index f9198e0606a..2198963ce14 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -880,7 +880,7 @@ class Util { } else { - throw new \Exception( 'Supplied path could not be resolved "' . $path . '"' ); + return false; } -- cgit v1.2.3 From 8ee7959092d8363f35de49819b44b6b8fe19bc34 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Thu, 25 Apr 2013 22:49:47 +0200 Subject: implement postRename @samtuke no need anymore for fixPartialFilePath this is now handled by rename share-keys are now handled properly webdav .part files are handled properly --- apps/files_encryption/lib/keymanager.php | 22 --------- apps/files_encryption/lib/proxy.php | 84 ++++++++++++++++++++++++++++---- apps/files_encryption/lib/stream.php | 10 +--- 3 files changed, 77 insertions(+), 39 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index ceefe8887ac..cfc13ee132d 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -139,28 +139,6 @@ class Keymanager { } - /** - * @brief Remove .path extension from a file path - * @param string $path Path that may identify a .part file - * @return string File path without .part extension - */ - public static function fixPartialFilePath( $path ) { - - if ( preg_match( '/\.part$/', $path ) ) { - - $newLength = strlen( $path ) - 5; - $fPath = substr( $path, 0, $newLength ); - - return $fPath; - - } else { - - return $path; - - } - - } - /** * @brief retrieve keyfile for an encrypted file * @param \OC_FilesystemView $view diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 66ea282312e..7294c243664 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -237,8 +237,6 @@ class Proxy extends \OC_FileProxy { return true; } - $path = Keymanager::fixPartialFilePath( $path ); - // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; @@ -307,6 +305,15 @@ class Proxy extends \OC_FileProxy { if (!$view->is_dir($oldKeyfilePath)) { $oldKeyfilePath .= '.key'; $newKeyfilePath .= '.key'; + + // handle share-keys + $localKeyPath = $view->getLocalFile($userId.'/files_encryption/share-keys/'.$oldRelPath); + $matches = glob(preg_quote($localKeyPath).'*.shareKey'); + foreach ($matches as $src) { + $dst = str_replace($oldRelPath, $newRelPath, $src); + rename($src, $dst); + } + } else { // handle share-keys folders $oldShareKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'share-keys' . '/' . $oldRelPath; @@ -314,9 +321,6 @@ class Proxy extends \OC_FileProxy { $view->rename($oldShareKeyfilePath, $newShareKeyfilePath); } - //TODO add support for share-keys files - //... - // Rename keyfile so it isn't orphaned $result = $view->rename($oldKeyfilePath, $newKeyfilePath); @@ -326,6 +330,70 @@ class Proxy extends \OC_FileProxy { } + /** + * @brief When a file is renamed, rename its keyfile also + * @return bool Result of rename() + * @note This is pre rather than post because using post didn't work + */ + public function postRename( $oldPath, $newPath ) + { + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $view = new \OC_FilesystemView('/'); + $userId = \OCP\User::getUser(); + $util = new Util( $view, $userId ); + + // Reformat path for use with OC_FSV + $newPathSplit = explode( '/', $newPath ); + $newPathRelative = implode( '/', array_slice( $newPathSplit, 3 ) ); + $newPathRelativeToUser = implode( '/', array_slice( $newPathSplit, 2 ) ); + + // get file info from database/cache + //$newFileInfo = \OC\Files\Filesystem::getFileInfo($newPathRelative); + + if ($util->isEncryptedPath($newPath)) { + $cached = $view->getFileInfo($newPath); + $cached['encrypted'] = 1; + + // get the size from filesystem + $size = $view->filesize($newPath); + + // calculate last chunk nr + $lastChunckNr = floor($size / 8192); + + // open stream + $result = fopen('crypt://' . $newPathRelative, "r"); + + if(is_resource($result)) { + // calculate last chunk position + $lastChunckPos = ($lastChunckNr * 8192); + + // seek to end + fseek($result, $lastChunckPos); + + // get the content of the last chunck + $lastChunkContent = fread($result, 8192); + + // calc the real file size with the size of the last chunk + $realSize = (($lastChunckNr * 6126) + strlen($lastChunkContent)); + + // set the size + $cached['unencrypted_size'] = $realSize; + } + + $view->putFileInfo( $newPath, $cached ); + + } + + \OC_FileProxy::$enabled = $proxyStatus; + + return true; + + } + public function postFopen( $path, &$result ){ if ( !$result ) { @@ -424,11 +492,11 @@ class Proxy extends \OC_FileProxy { // if path is a folder do nothing if(is_array($data) && array_key_exists('size', $data)) { + // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - // get file size $data['size'] = self::postFileSize($path, $data['size']); @@ -461,8 +529,6 @@ class Proxy extends \OC_FileProxy { return $size; } - $path = Keymanager::fixPartialFilePath( $path ); - // Reformat path for use with OC_FSV $path_split = explode('/', $path); $path_f = implode('/', array_slice($path_split, 3)); @@ -474,7 +540,7 @@ class Proxy extends \OC_FileProxy { if(is_array($fileInfo) && $fileInfo['encrypted'] == 1) { return $fileInfo['unencrypted_size']; } else { - return $fileInfo['size']; + return $size; } } } diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 7e42627f8ca..411bcdac92d 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -87,10 +87,7 @@ class Stream { // rawPath is relative to the data directory $this->rawPath = $this->userId . '/files/' . $this->relPath; - // Fix .part filenames - $this->rawPath = Keymanager::fixPartialFilePath( $this->rawPath ); - - if ( + if ( dirname( $this->rawPath ) == 'streams' and isset( self::$sourceStreams[basename( $this->rawPath )] ) ) { @@ -244,10 +241,7 @@ class Stream { } - // Avoid problems with .part file extensions - $this->relPath = Keymanager::fixPartialFilePath( $this->relPath ); - - // Fetch and decrypt keyfile + // Fetch and decrypt keyfile // Fetch existing keyfile $this->encKeyfile = Keymanager::getFileKey( $this->rootView, $this->userId, $this->relPath ); -- cgit v1.2.3 From d017bbb065245212e8aa4091f4bee0a4e8ea9055 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Thu, 25 Apr 2013 23:24:07 +0200 Subject: fix share for renamed or moved files --- apps/files_encryption/lib/proxy.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 7294c243664..73f72a9e23e 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -343,13 +343,13 @@ class Proxy extends \OC_FileProxy { \OC_FileProxy::$enabled = false; $view = new \OC_FilesystemView('/'); + $session = new Session($view); $userId = \OCP\User::getUser(); $util = new Util( $view, $userId ); // Reformat path for use with OC_FSV $newPathSplit = explode( '/', $newPath ); $newPathRelative = implode( '/', array_slice( $newPathSplit, 3 ) ); - $newPathRelativeToUser = implode( '/', array_slice( $newPathSplit, 2 ) ); // get file info from database/cache //$newFileInfo = \OC\Files\Filesystem::getFileInfo($newPathRelative); @@ -386,8 +386,19 @@ class Proxy extends \OC_FileProxy { $view->putFileInfo( $newPath, $cached ); + // get sharing app state + $sharingEnabled = \OCP\Share::isEnabled(); + + // get users + $usersSharing = $util->getSharingUsersArray($sharingEnabled, $newPathRelative); + + // update sharing-keys + $util->setSharedFileKeyfiles($session, $usersSharing, $newPathRelative); } + + + \OC_FileProxy::$enabled = $proxyStatus; return true; -- cgit v1.2.3 From 813641e6e86601cc73da0f00d8430da62e872180 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Sat, 27 Apr 2013 00:05:20 +0200 Subject: improved file size created new method fixFileSize in Util so it can be used with files_trashbin --- apps/files_encryption/lib/proxy.php | 40 +-------------------- apps/files_encryption/lib/util.php | 70 ++++++++++++++++++++++++++++++++++--- 2 files changed, 66 insertions(+), 44 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 73f72a9e23e..24821d8a05c 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -351,41 +351,7 @@ class Proxy extends \OC_FileProxy { $newPathSplit = explode( '/', $newPath ); $newPathRelative = implode( '/', array_slice( $newPathSplit, 3 ) ); - // get file info from database/cache - //$newFileInfo = \OC\Files\Filesystem::getFileInfo($newPathRelative); - - if ($util->isEncryptedPath($newPath)) { - $cached = $view->getFileInfo($newPath); - $cached['encrypted'] = 1; - - // get the size from filesystem - $size = $view->filesize($newPath); - - // calculate last chunk nr - $lastChunckNr = floor($size / 8192); - - // open stream - $result = fopen('crypt://' . $newPathRelative, "r"); - - if(is_resource($result)) { - // calculate last chunk position - $lastChunckPos = ($lastChunckNr * 8192); - - // seek to end - fseek($result, $lastChunckPos); - - // get the content of the last chunck - $lastChunkContent = fread($result, 8192); - - // calc the real file size with the size of the last chunk - $realSize = (($lastChunckNr * 6126) + strlen($lastChunkContent)); - - // set the size - $cached['unencrypted_size'] = $realSize; - } - - $view->putFileInfo( $newPath, $cached ); - + if($util->fixFileSize($newPath)) { // get sharing app state $sharingEnabled = \OCP\Share::isEnabled(); @@ -396,13 +362,9 @@ class Proxy extends \OC_FileProxy { $util->setSharedFileKeyfiles($session, $usersSharing, $newPathRelative); } - - - \OC_FileProxy::$enabled = $proxyStatus; return true; - } public function postFopen( $path, &$result ){ diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 2198963ce14..9d9e420e4d3 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -421,10 +421,10 @@ class Util { return $text; } - /** - * @brief Check if a given path identifies an encrypted file - * @return true / false - */ + /** + * @brief Check if a given path identifies an encrypted file + * @return true / false + */ public function isEncryptedPath( $path ) { // Disable encryption proxy so data retreived is in its @@ -438,7 +438,67 @@ class Util { return Crypt::isCatfileContent( $data ); } - + + /** + * @brief fix the file size of the encrypted file + * + * @param $path absolute path + * @return true / false if file is encrypted + */ + + public function fixFileSize($path) { + $result = false; + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + if ($this->isEncryptedPath($path)) { + + // Reformat path for use with OC_FSV + $pathSplit = explode( '/', $path ); + $pathRelative = implode( '/', array_slice( $pathSplit, 3 ) ); + + $cached = $this->view->getFileInfo($path); + $cached['encrypted'] = 1; + + // get the size from filesystem + $size = $this->view->filesize($path); + + // calculate last chunk nr + $lastChunckNr = floor($size / 8192); + + // open stream + $result = fopen('crypt://' . $pathRelative, "r"); + + if(is_resource($result)) { + // calculate last chunk position + $lastChunckPos = ($lastChunckNr * 8192); + + // seek to end + fseek($result, $lastChunckPos); + + // get the content of the last chunk + $lastChunkContent = fread($result, 8192); + + // calc the real file size with the size of the last chunk + $realSize = (($lastChunckNr * 6126) + strlen($lastChunkContent)); + + // set the size + $cached['unencrypted_size'] = $realSize; + } + + // put file info + $this->view->putFileInfo( $path, $cached ); + + $result = true; + } + + \OC_FileProxy::$enabled = $proxyStatus; + + return $result; + } + /** * @brief Format a path to be relative to the /user/files/ directory */ -- cgit v1.2.3 From 05523b76c0c17a74db6604f2689a9219d318153d Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Sat, 27 Apr 2013 20:18:57 +0200 Subject: fix reusing keys fix webdav part files --- apps/files_encryption/lib/keymanager.php | 76 +++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 10 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index cfc13ee132d..9f3cb8120ca 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -129,16 +129,51 @@ class Keymanager { mkdir($keyfileFolderName, 0750, true); } } - - $result = $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); - + + // try reusing key file if part file + if(self::isPartialFilePath($targetPath)) { + $result = $view->file_put_contents( $basePath . '/' . self::fixPartialFilePath($targetPath) . '.key', $catfile ); + } else { + $result = $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); + } \OC_FileProxy::$enabled = $proxyStatus; return $result; } - + + /** + * @brief Remove .path extension from a file path + * @param string $path Path that may identify a .part file + * @return string File path without .part extension + * @note this is needed for reusing keys + */ + public static function fixPartialFilePath($path) + { + if (preg_match('/\.part$/', $path)) { + + $newLength = strlen($path) - 5; + $fPath = substr($path, 0, $newLength); + + return $fPath; + } else { + + return $path; + + } + + } + + public static function isPartialFilePath($path) + { + if (preg_match('/\.part$/', $path)) { + return true; + } else { + return false; + } + + } /** * @brief retrieve keyfile for an encrypted file * @param \OC_FilesystemView $view @@ -150,12 +185,20 @@ class Keymanager { * of the keyfile must be performed by client code */ public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) { - + + // try reusing key file if part file + if(self::isPartialFilePath($filePath)) { + $result = self::getFileKey($view, $userId, self::fixPartialFilePath($filePath)); + if($result) { + return $result; + } + } + $util = new Util($view, \OCP\User::getUser()); list($owner, $filename) = $util->getUidAndFilename($filePath); $filePath_f = ltrim( $filename, '/' ); - - $keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key'; + + $keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key'; $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; @@ -287,7 +330,7 @@ class Keymanager { */ public static function setShareKey( \OC_FilesystemView $view, $path, $userId, $shareKey ) { - //here we need the currently logged in user, while userId can be a different user + //here we need the currently logged in user, while userId can be a different user $util = new Util( $view, \OCP\User::getUser() ); list($owner, $filename) = $util->getUidAndFilename($path); @@ -295,8 +338,13 @@ class Keymanager { $basePath = '/' . $owner . '/files_encryption/share-keys'; $shareKeyPath = self::keySetPreparation( $view, $filename, $basePath, $owner ); - - $writePath = $basePath . '/' . $shareKeyPath . '.' . $userId . '.shareKey'; + + // try reusing key file if part file + if(self::isPartialFilePath($shareKeyPath)) { + $writePath = $basePath . '/' . self::fixPartialFilePath($shareKeyPath) . '.' . $userId . '.shareKey'; + } else { + $writePath = $basePath . '/' . $shareKeyPath . '.' . $userId . '.shareKey'; + } $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; @@ -359,6 +407,14 @@ class Keymanager { */ public static function getShareKey( \OC_FilesystemView $view, $userId, $filePath ) { + // try reusing key file if part file + if(self::isPartialFilePath($filePath)) { + $result = self::getShareKey($view, $userId, self::fixPartialFilePath($filePath)); + if($result) { + return $result; + } + } + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; -- cgit v1.2.3 From ba080e0d2e43a24b891aa7d8bb8bcf54ccd5faa4 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Sat, 27 Apr 2013 20:21:46 +0200 Subject: removed preRename and moved postRename to hooks.php added postWrite and postTouch to fix file size and sharing keys --- apps/files_encryption/lib/proxy.php | 158 +++++++++++++----------------------- 1 file changed, 58 insertions(+), 100 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 24821d8a05c..439aa0da251 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -273,96 +273,20 @@ class Proxy extends \OC_FileProxy { } /** - * @brief When a file is renamed, rename its keyfile also - * @return bool Result of rename() - * @note This is pre rather than post because using post didn't work - */ - public function preRename( $oldPath, $newPath ) - { - - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - - $view = new \OC_FilesystemView('/'); - - $userId = \OCP\USER::getUser(); - - // Format paths to be relative to user files dir - $oldTrimmed = ltrim($oldPath, '/'); - $oldSplit = explode('/', $oldTrimmed); - $oldSliced = array_slice($oldSplit, 2); - $oldRelPath = implode('/', $oldSliced); - $oldKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $oldRelPath; - - $newTrimmed = ltrim($newPath, '/'); - $newSplit = explode('/', $newTrimmed); - $newSliced = array_slice($newSplit, 2); - $newRelPath = implode('/', $newSliced); - $newKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $newRelPath; - - // add key ext if this is not an folder - if (!$view->is_dir($oldKeyfilePath)) { - $oldKeyfilePath .= '.key'; - $newKeyfilePath .= '.key'; - - // handle share-keys - $localKeyPath = $view->getLocalFile($userId.'/files_encryption/share-keys/'.$oldRelPath); - $matches = glob(preg_quote($localKeyPath).'*.shareKey'); - foreach ($matches as $src) { - $dst = str_replace($oldRelPath, $newRelPath, $src); - rename($src, $dst); - } - - } else { - // handle share-keys folders - $oldShareKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'share-keys' . '/' . $oldRelPath; - $newShareKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'share-keys' . '/' . $newRelPath; - $view->rename($oldShareKeyfilePath, $newShareKeyfilePath); - } - - // Rename keyfile so it isn't orphaned - $result = $view->rename($oldKeyfilePath, $newKeyfilePath); - - \OC_FileProxy::$enabled = $proxyStatus; - - return $result; - - } - - /** * @brief When a file is renamed, rename its keyfile also * @return bool Result of rename() * @note This is pre rather than post because using post didn't work */ - public function postRename( $oldPath, $newPath ) + public function postWrite( $path ) { + $this->handleFile($path); - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - - $view = new \OC_FilesystemView('/'); - $session = new Session($view); - $userId = \OCP\User::getUser(); - $util = new Util( $view, $userId ); - - // Reformat path for use with OC_FSV - $newPathSplit = explode( '/', $newPath ); - $newPathRelative = implode( '/', array_slice( $newPathSplit, 3 ) ); - - if($util->fixFileSize($newPath)) { - // get sharing app state - $sharingEnabled = \OCP\Share::isEnabled(); - - // get users - $usersSharing = $util->getSharingUsersArray($sharingEnabled, $newPathRelative); - - // update sharing-keys - $util->setSharedFileKeyfiles($session, $usersSharing, $newPathRelative); - } + return true; + } - \OC_FileProxy::$enabled = $proxyStatus; + public function postTouch( $path ) + { + $this->handleFile($path); return true; } @@ -480,25 +404,28 @@ class Proxy extends \OC_FileProxy { return $data; } - public function postStat( $path, $data ) { + public function postStat($path, $data) + { + // check if file is encrypted + if (Crypt::isCatfileContent($path)) { - if ( Crypt::isCatfileContent( $path ) ) { - - $cached = \OC\Files\Filesystem::getFileInfo( $path, '' ); - - $data['size'] = $cached['unencrypted_size']; - - } - - return $data; - } + // get file info from cache + $cached = \OC\Files\Filesystem::getFileInfo($path, ''); - public function postFileSize( $path, $size ) { + // set the real file size + $data['size'] = $cached['unencrypted_size']; + } - $view = new \OC_FilesystemView( '/' ); + return $data; + } + + public function postFileSize($path, $size) + { + + $view = new \OC_FilesystemView('/'); // if path is a folder do nothing - if($view->is_dir($path)) { + if ($view->is_dir($path)) { return $size; } @@ -510,10 +437,41 @@ class Proxy extends \OC_FileProxy { $fileInfo = \OC\Files\Filesystem::getFileInfo($path_f); // if file is encrypted return real file size - if(is_array($fileInfo) && $fileInfo['encrypted'] == 1) { + if (is_array($fileInfo) && $fileInfo['encrypted'] == 1) { return $fileInfo['unencrypted_size']; } else { return $size; } - } -} + } + + public function handleFile($path) { + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $view = new \OC_FilesystemView('/'); + $session = new Session($view); + $userId = \OCP\User::getUser(); + $util = new Util( $view, $userId ); + + // Reformat path for use with OC_FSV + $path_split = explode( '/', $path ); + $path_f = implode( '/', array_slice( $path_split, 3 ) ); + + // only if file is on 'files' folder fix file size and sharing + if($path_split[2] == 'files' && $util->fixFileSize($path)) { + + // get sharing app state + $sharingEnabled = \OCP\Share::isEnabled(); + + // get users + $usersSharing = $util->getSharingUsersArray($sharingEnabled, $path_f); + + // update sharing-keys + $util->setSharedFileKeyfiles($session, $usersSharing, $path_f); + } + + \OC_FileProxy::$enabled = $proxyStatus; + } + } -- cgit v1.2.3 From 770aebfb9ed7703010ee2bceca73dee35f660c00 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Sat, 27 Apr 2013 20:22:38 +0200 Subject: check if file exists before fixing file size --- apps/files_encryption/lib/util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 9d9e420e4d3..a9996999a3a 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -453,7 +453,7 @@ class Util { $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - if ($this->isEncryptedPath($path)) { + if ($this->view->file_exists($path) && $this->isEncryptedPath($path)) { // Reformat path for use with OC_FSV $pathSplit = explode( '/', $path ); -- cgit v1.2.3 From 7f1f0464a882dc8df80cc2da79079dad0933ecdd Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Sat, 27 Apr 2013 23:02:42 +0200 Subject: added self healing if file get remove from file cache --- apps/files_encryption/lib/proxy.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 439aa0da251..23290b5b20b 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -438,10 +438,24 @@ class Proxy extends \OC_FileProxy { // if file is encrypted return real file size if (is_array($fileInfo) && $fileInfo['encrypted'] == 1) { - return $fileInfo['unencrypted_size']; + $size = $fileInfo['unencrypted_size']; } else { - return $size; + // self healing if file was removed from file cache + $userId = \OCP\User::getUser(); + $util = new Util( $view, $userId ); + $fixSize = $util->getFileSize($path); + if($fixSize > 0) { + $size = $fixSize; + + $fileInfo['encrypted'] = 1; + $fileInfo['unencrypted_size'] = $size; + + // put file info + $view->putFileInfo( $path, $fileInfo ); + } } + + return $size; } public function handleFile($path) { -- cgit v1.2.3 From f9760f65212bd6464685ec1dd60a73825b4a3f66 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Sat, 27 Apr 2013 23:34:25 +0200 Subject: improved file size --- apps/files_encryption/lib/util.php | 59 +++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 17 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index a9996999a3a..fe040d88775 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -440,53 +440,78 @@ class Util { } /** - * @brief fix the file size of the encrypted file + * @brief get the file size of the unencrypted file * * @param $path absolute path * @return true / false if file is encrypted */ - public function fixFileSize($path) { - $result = false; + public function getFileSize($path) { + $result = 0; // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - if ($this->view->file_exists($path) && $this->isEncryptedPath($path)) { - - // Reformat path for use with OC_FSV - $pathSplit = explode( '/', $path ); - $pathRelative = implode( '/', array_slice( $pathSplit, 3 ) ); + // Reformat path for use with OC_FSV + $pathSplit = explode( '/', $path ); + $pathRelative = implode( '/', array_slice( $pathSplit, 3 ) ); - $cached = $this->view->getFileInfo($path); - $cached['encrypted'] = 1; + if ($pathSplit[2] == 'files' && $this->view->file_exists($path) && $this->isEncryptedPath($path)) { // get the size from filesystem - $size = $this->view->filesize($path); + $fullPath = $this->view->getLocalFile($path); + $size = filesize($fullPath); // calculate last chunk nr $lastChunckNr = floor($size / 8192); // open stream - $result = fopen('crypt://' . $pathRelative, "r"); + $stream = fopen('crypt://' . $pathRelative, "r"); - if(is_resource($result)) { + if(is_resource($stream)) { // calculate last chunk position $lastChunckPos = ($lastChunckNr * 8192); // seek to end - fseek($result, $lastChunckPos); + fseek($stream, $lastChunckPos); // get the content of the last chunk - $lastChunkContent = fread($result, 8192); + $lastChunkContent = fread($stream, 8192); // calc the real file size with the size of the last chunk $realSize = (($lastChunckNr * 6126) + strlen($lastChunkContent)); - // set the size - $cached['unencrypted_size'] = $realSize; + // store file size + $result = $realSize; } + } + + \OC_FileProxy::$enabled = $proxyStatus; + + return $result; + } + /** + * @brief fix the file size of the encrypted file + * + * @param $path absolute path + * @return true / false if file is encrypted + */ + + public function fixFileSize($path) { + $result = false; + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $realSize = $this->getFileSize($path); + if($realSize > 0) { + $cached = $this->view->getFileInfo($path); + $cached['encrypted'] = 1; + + // set the size + $cached['unencrypted_size'] = $realSize; // put file info $this->view->putFileInfo( $path, $cached ); -- cgit v1.2.3 From 4a63faf64b14b21af7cb73f43ca3fcf841aff804 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Mon, 29 Apr 2013 01:43:59 +0200 Subject: speed improvement --- apps/files_encryption/lib/stream.php | 65 +++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 26 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 411bcdac92d..a51f2c56d95 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -298,7 +298,8 @@ class Stream { // automatically attempted when the file is written to disk - // we are handling that separately here and we don't want to // get into an infinite loop - //\OC_FileProxy::$enabled = false; + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; // Get the length of the unencrypted data that we are handling $length = strlen( $data ); @@ -322,30 +323,7 @@ class Stream { } - // Fetch user's public key - $this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId ); - - // 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, $this->userId); - - // Fetch public keys for all sharing users - $publicKeys = Keymanager::getPublicKeys( $this->rootView, $uniqueUserIds ); - // Encrypt enc key for all sharing users - $this->encKeyfiles = Crypt::multiKeyEncrypt( $this->plainKey, $publicKeys ); - - $view = new \OC_FilesystemView( '/' ); - - // Save the new encrypted file key - Keymanager::setFileKey( $this->rootView, $this->relPath, $this->userId, $this->encKeyfiles['data'] ); - - // Save the sharekeys - Keymanager::setShareKeys( $view, $this->relPath, $this->encKeyfiles['keys'] ); // If extra data is left over from the last round, make sure it // is integrated into the next 6126 / 8192 block @@ -437,6 +415,8 @@ class Stream { $this->size = max( $this->size, $pointer + $length ); $this->unencryptedSize += $length; + \OC_FileProxy::$enabled = $proxyStatus; + return $length; } @@ -492,13 +472,46 @@ class Stream { } public function stream_close() { - - $this->flush(); + + $this->flush(); if ( $this->meta['mode']!='r' and $this->meta['mode']!='rb' ) { + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + // Fetch user's public key + $this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId ); + + // 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, $this->userId); + + // Fetch public keys for all sharing users + $publicKeys = Keymanager::getPublicKeys( $this->rootView, $uniqueUserIds ); + + // Encrypt enc key for all sharing users + $this->encKeyfiles = Crypt::multiKeyEncrypt( $this->plainKey, $publicKeys ); + + $view = new \OC_FilesystemView( '/' ); + + // Save the new encrypted file key + Keymanager::setFileKey( $this->rootView, $this->relPath, $this->userId, $this->encKeyfiles['data'] ); + + // Save the sharekeys + Keymanager::setShareKeys( $view, $this->relPath, $this->encKeyfiles['keys'] ); + + // Re-enable proxy - our work is done + \OC_FileProxy::$enabled = $proxyStatus; + \OC\Files\Filesystem::putFileInfo( $this->relPath, array( 'encrypted' => 1, 'size' => $this->size, 'unencrypted_size' => $this->unencryptedSize ), '' ); } -- cgit v1.2.3 From 27ce7845b4205650e50f3777d8b152470440cbe6 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Tue, 30 Apr 2013 01:35:46 +0200 Subject: fixed tests, now tests should work via autotest.sh files_encryption app is now enabled in enable_all.php --- apps/files_encryption/lib/util.php | 7 +++- apps/files_encryption/tests/keymanager.php | 4 +- apps/files_encryption/tests/util.php | 61 ++++++++++++++++++++---------- tests/enable_all.php | 1 + 4 files changed, 50 insertions(+), 23 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index fe040d88775..4097250b252 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -204,7 +204,12 @@ class Util { $this->view->file_put_contents( $this->privateKeyPath, $encryptedPrivateKey ); \OC_FileProxy::$enabled = true; - + + // create database configuration + $sql = 'INSERT INTO `*PREFIX*encryption` (`uid`,`mode`,`recovery`) VALUES (?,?,?)'; + $args = array( $this->userId, 'server-side', 0); + $query = \OCP\DB::prepare( $sql ); + $query->execute( $args ); } return true; diff --git a/apps/files_encryption/tests/keymanager.php b/apps/files_encryption/tests/keymanager.php index 3dba6d0df97..7fe37838a42 100644 --- a/apps/files_encryption/tests/keymanager.php +++ b/apps/files_encryption/tests/keymanager.php @@ -50,8 +50,8 @@ class Test_Keymanager extends \PHPUnit_Framework_TestCase { $userHome = \OC_User::getHome($this->userId); $this->dataDir = str_replace('/'.$this->userId, '', $userHome); - \OC_Filesystem::init( $this->userId, '/' ); - \OC_Filesystem::mount( 'OC_Filestorage_Local', array('datadir' => $this->dataDir), '/' ); + \OC\Files\Filesystem::init( $this->userId, '/' ); + \OC\Files\Filesystem::mount( 'OC_Filestorage_Local', array('datadir' => $this->dataDir), '/' ); } diff --git a/apps/files_encryption/tests/util.php b/apps/files_encryption/tests/util.php index 3ebc484809b..0659b468a37 100755 --- a/apps/files_encryption/tests/util.php +++ b/apps/files_encryption/tests/util.php @@ -29,19 +29,20 @@ use OCA\Encryption; class Test_Enc_Util extends \PHPUnit_Framework_TestCase { function setUp() { - - \OC_Filesystem::mount( 'OC_Filestorage_Local', array(), '/' ); - - // set content for encrypting / decrypting in tests + // reset backend + \OC_User::useBackend('database'); + + \OC_User::setUserId( 'admin' ); + $this->userId = 'admin'; + $this->pass = 'admin'; + + // set content for encrypting / decrypting in tests $this->dataUrl = realpath( dirname(__FILE__).'/../lib/crypt.php' ); $this->dataShort = 'hats'; $this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) ); $this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' ); $this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' ); - - $this->userId = 'admin'; - $this->pass = 'admin'; - + $keypair = Encryption\Crypt::createKeypair(); $this->genPublicKey = $keypair['publicKey']; @@ -54,9 +55,15 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase { $this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key $this->view = new \OC_FilesystemView( '/' ); - - $this->mockView = m::mock('OC_FilesystemView'); - $this->util = new Encryption\Util( $this->mockView, $this->userId ); + + $userHome = \OC_User::getHome($this->userId); + $this->dataDir = str_replace('/'.$this->userId, '', $userHome); + + \OC\Files\Filesystem::init( $this->userId, '/' ); + \OC\Files\Filesystem::mount( 'OC_Filestorage_Local', array('datadir' => $this->dataDir), '/' ); + + $mockView = m::mock('OC_FilesystemView'); + $this->util = new Encryption\Util( $mockView, $this->userId ); } @@ -90,8 +97,8 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase { $mockView = m::mock('OC_FilesystemView'); - $mockView->shouldReceive( 'file_exists' )->times(5)->andReturn( false ); - $mockView->shouldReceive( 'mkdir' )->times(4)->andReturn( true ); + $mockView->shouldReceive( 'file_exists' )->times(7)->andReturn( false ); + $mockView->shouldReceive( 'mkdir' )->times(6)->andReturn( true ); $mockView->shouldReceive( 'file_put_contents' )->withAnyArgs(); $util = new Encryption\Util( $mockView, $this->userId ); @@ -107,7 +114,7 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase { $mockView = m::mock('OC_FilesystemView'); - $mockView->shouldReceive( 'file_exists' )->times(6)->andReturn( true ); + $mockView->shouldReceive( 'file_exists' )->times(8)->andReturn( true ); $mockView->shouldReceive( 'file_put_contents' )->withAnyArgs(); $util = new Encryption\Util( $mockView, $this->userId ); @@ -141,7 +148,7 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase { $mockView = m::mock('OC_FilesystemView'); - $mockView->shouldReceive( 'file_exists' )->times(3)->andReturn( true ); + $mockView->shouldReceive( 'file_exists' )->times(5)->andReturn( true ); $util = new Encryption\Util( $mockView, $this->userId ); @@ -190,11 +197,25 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase { function testGetUidAndFilename() { \OC_User::setUserId( 'admin' ); - - $this->util->getUidAndFilename( 'test1.txt' ); - - - + + $filename = 'tmp-'.time().'.test'; + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $this->view->file_put_contents($this->userId . '/files/' . $filename, $this->dataShort); + + // Re-enable proxy - our work is done + \OC_FileProxy::$enabled = $proxyStatus; + + $util = new Encryption\Util( $this->view, $this->userId ); + + list($fileOwnerUid, $file) = $util->getUidAndFilename( $filename ); + + $this->assertEquals('admin', $fileOwnerUid); + + $this->assertEquals($file, $filename); } // /** diff --git a/tests/enable_all.php b/tests/enable_all.php index 44af0115650..111ed0e1357 100644 --- a/tests/enable_all.php +++ b/tests/enable_all.php @@ -8,6 +8,7 @@ require_once __DIR__.'/../lib/base.php'; +OC_App::enable('files_encryption'); OC_App::enable('calendar'); OC_App::enable('contacts'); OC_App::enable('apptemplateadvanced'); -- cgit v1.2.3 From fbbc76f281f50afa3072d99e4e0d413df835b3d3 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Tue, 30 Apr 2013 20:44:42 +0200 Subject: fix for sharing files --- apps/files_encryption/lib/proxy.php | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 23290b5b20b..50f30594b42 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -153,9 +153,9 @@ class Proxy extends \OC_FileProxy { $data = $encData; // Update the file cache with file info - \OC\Files\Filesystem::putFileInfo( $path, array( 'encrypted'=>true, 'size' => $size ), '' ); - - // Re-enable proxy - our work is done + \OC\Files\Filesystem::putFileInfo( $filePath, array( 'encrypted'=>true, 'size' => strlen($size), 'unencrypted_size' => $size), '' ); + + // Re-enable proxy - our work is done \OC_FileProxy::$enabled = $proxyStatus; } @@ -437,24 +437,25 @@ class Proxy extends \OC_FileProxy { $fileInfo = \OC\Files\Filesystem::getFileInfo($path_f); // if file is encrypted return real file size - if (is_array($fileInfo) && $fileInfo['encrypted'] == 1) { + if (is_array($fileInfo) && $fileInfo['encrypted'] === true) { $size = $fileInfo['unencrypted_size']; } else { // self healing if file was removed from file cache - $userId = \OCP\User::getUser(); - $util = new Util( $view, $userId ); - $fixSize = $util->getFileSize($path); - if($fixSize > 0) { - $size = $fixSize; - - $fileInfo['encrypted'] = 1; - $fileInfo['unencrypted_size'] = $size; - - // put file info - $view->putFileInfo( $path, $fileInfo ); + if(is_array($fileInfo)) { + $userId = \OCP\User::getUser(); + $util = new Util( $view, $userId ); + $fixSize = $util->getFileSize($path); + if($fixSize > 0) { + $size = $fixSize; + + $fileInfo['encrypted'] = 1; + $fileInfo['unencrypted_size'] = $size; + + // put file info + $view->putFileInfo( $path_f, $fileInfo ); + } } } - return $size; } -- cgit v1.2.3 From d3db4ee103903e97ec2cfb8430b14699f1f6e8ae Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Wed, 1 May 2013 11:04:40 +0200 Subject: fixed re-share problems --- apps/files_encryption/hooks/hooks.php | 8 ++++---- apps/files_encryption/lib/util.php | 15 +++++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 67d289ad68a..c0e493752a0 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -200,13 +200,13 @@ class Hooks { $util = new Util($view, $userId); $path = $util->fileIdToPath($params['itemSource']); - //check if this is a reshare action, that's true if the item source is already shared with me - $sharedItem = \OCP\Share::getItemSharedWithBySource($params['itemType'], $params['itemSource']); + //check if this is a reshare action, that's true if the item source is already shared with me + $sharedItem = \OCP\Share::getItemSharedWithBySource($params['itemType'], $params['fileSource']); if ($sharedItem) { // if it is a re-share than the file is located in my Shared folder $path = '/Shared'.$sharedItem['file_target']; } else { - $path = $util->fileIdToPath($params['itemSource']); + $path = $util->fileIdToPath($params['fileSource']); } $sharingEnabled = \OCP\Share::isEnabled(); @@ -224,7 +224,7 @@ class Hooks { $failed = array(); // Attempt to set shareKey - if (!$util->setSharedFileKeyfiles($session, $usersSharing, $path)) { + if (!$util->setSharedFileKeyfiles($session, $usersSharing, $path)) { $failed[] = $path; } diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 4097250b252..eabb34f7ab0 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -983,14 +983,21 @@ class Util { */ public function getAllFiles($dir) { $result = array(); - - $content = $this->view->getDirectoryContent($this->userFilesDir.$dir); + + $content = $this->view->getDirectoryContent($this->userFilesDir.$dir); + + // handling for re shared folders + $path_split = explode( '/', $dir ); + $shared = ''; + if($path_split[1] === 'Shared') { + $shared = '/Shared'; + } foreach ($content as $c) { if ($c['type'] === "dir" ) { - $result = array_merge($result, $this->getAllFiles(substr($c['path'],5))); + $result = array_merge($result, $this->getAllFiles($shared.substr($c['path'],5))); } else { - $result[] = substr($c['path'], 5); + $result[] = $shared.substr($c['path'], 5); } } return $result; -- cgit v1.2.3 From ba29147e34a22142c4bfd2afa3f5b9f1e6efcd63 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Wed, 1 May 2013 19:18:31 +0200 Subject: Fixed recoveryadmin settings in user and admin settings pages (js, templates, ajax) Renamed recovery methods in Util{} for clarity Added note about bug causing slow page load and redundant keypair generation recoveryAdmin functionality not yet complete --- apps/files_encryption/ajax/adminrecovery.php | 27 ++++++-- apps/files_encryption/ajax/userrecovery.php | 9 +-- apps/files_encryption/appinfo/app.php | 4 +- apps/files_encryption/js/settings-admin.js | 37 ++++++++++ apps/files_encryption/js/settings-personal.js | 23 +++++++ apps/files_encryption/js/settings.js | 36 ---------- apps/files_encryption/lib/keymanager.php | 2 +- apps/files_encryption/lib/session.php | 18 +++-- apps/files_encryption/lib/util.php | 79 ++++++++++++++-------- apps/files_encryption/settings-admin.php | 28 ++++++++ apps/files_encryption/settings-personal.php | 20 ++++++ apps/files_encryption/settings.php | 27 -------- apps/files_encryption/templates/settings-admin.php | 39 +++++++++++ .../templates/settings-personal.php | 22 ++++++ apps/files_encryption/templates/settings.php | 39 ----------- apps/files_encryption/tests/util.php | 14 ++-- 16 files changed, 267 insertions(+), 157 deletions(-) create mode 100644 apps/files_encryption/js/settings-admin.js create mode 100644 apps/files_encryption/js/settings-personal.js delete mode 100644 apps/files_encryption/js/settings.js create mode 100644 apps/files_encryption/settings-admin.php delete mode 100644 apps/files_encryption/settings.php create mode 100644 apps/files_encryption/templates/settings-admin.php delete mode 100644 apps/files_encryption/templates/settings.php (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/ajax/adminrecovery.php b/apps/files_encryption/ajax/adminrecovery.php index cec0cd4ddda..157fc8f313c 100644 --- a/apps/files_encryption/ajax/adminrecovery.php +++ b/apps/files_encryption/ajax/adminrecovery.php @@ -17,11 +17,12 @@ use OCA\Encryption; $return = $doSetup = false; +// Enable recoveryAdmin if ( isset( $_POST['adminEnableRecovery'] ) - && $_POST['adminEnableRecovery'] == 1 - && isset( $_POST['recoveryPassword'] ) - && ! empty ( $_POST['recoveryPassword'] ) + && 1 == $_POST['adminEnableRecovery'] +// && isset( $_POST['recoveryPassword'] ) +// && ! empty ( $_POST['recoveryPassword'] ) ) { // TODO: Let the admin set this themselves @@ -29,7 +30,7 @@ if ( // If desired recoveryAdmin UID is already in use if ( ! \OC_User::userExists( $recoveryAdminUid ) ) { - + // Create new recoveryAdmin user \OC_User::createUser( $recoveryAdminUid, $_POST['recoveryPassword'] ); @@ -55,11 +56,11 @@ if ( } - // If recoveryAdmin has passed other checks + // Setup recoveryAdmin user for encryption if ( $doSetup ) { $view = new \OC_FilesystemView( '/' ); - $util = new Util( $view, $recoveryAdminUid ); + $util = new \OCA\Encryption\Util( $view, $recoveryAdminUid ); // Ensure recoveryAdmin is ready for encryption (has usable keypair etc.) $util->setupServerSide( $_POST['recoveryPassword'] ); @@ -71,6 +72,20 @@ if ( } + // Set recoveryAdmin as enabled + OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminEnabled', 1 ); + +// Disable recoveryAdmin +} elseif ( + isset( $_POST['adminEnableRecovery'] ) + && 0 == $_POST['adminEnableRecovery'] +) { + + // Set recoveryAdmin as enabled + OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminEnabled', 0 ); + + $return = true; + } ($return) ? OC_JSON::success() : OC_JSON::error(); \ No newline at end of file diff --git a/apps/files_encryption/ajax/userrecovery.php b/apps/files_encryption/ajax/userrecovery.php index 56c18f7ad5b..f72be3181ef 100644 --- a/apps/files_encryption/ajax/userrecovery.php +++ b/apps/files_encryption/ajax/userrecovery.php @@ -13,21 +13,18 @@ use OCA\Encryption; \OCP\JSON::checkLoggedIn(); \OCP\JSON::checkAppEnabled( 'files_encryption' ); -\OCP\JSON::callCheck(); if ( isset( $_POST['userEnableRecovery'] ) + && ( 0 == $_POST['userEnableRecovery'] || 1 == $_POST['userEnableRecovery'] ) ) { - // Ensure preference is an integer - $recoveryEnabled = intval( $_POST['userEnableRecovery'] ); - $userId = \OCP\USER::getUser(); $view = new \OC_FilesystemView( '/' ); - $util = new Util( $view, $userId ); + $util = new \OCA\Encryption\Util( $view, $userId ); // Save recovery preference to DB - $result = $util->setRecovery( $recoveryEnabled ); + $result = $util->setRecoveryForUser( $_POST['userEnableRecovery'] ); if ( $result ) { diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index 9ae6c8331f8..a7253c43332 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -28,7 +28,7 @@ OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'p stream_wrapper_register( 'crypt', 'OCA\Encryption\Stream' ); -$view = new OC_FilesystemView( '/' ); +$view = new \OC\Files\View( '/' ); $session = new OCA\Encryption\Session( $view ); @@ -50,5 +50,5 @@ if ( } // Register settings scripts -OCP\App::registerAdmin( 'files_encryption', 'settings' ); +OCP\App::registerAdmin( 'files_encryption', 'settings-admin' ); OCP\App::registerPersonal( 'files_encryption', 'settings-personal' ); diff --git a/apps/files_encryption/js/settings-admin.js b/apps/files_encryption/js/settings-admin.js new file mode 100644 index 00000000000..48b5598d524 --- /dev/null +++ b/apps/files_encryption/js/settings-admin.js @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2013, Sam Tuke , Robin Appelman + * + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + + +$(document).ready(function(){ + // Trigger ajax on filetype blacklist change + $('#encryption_blacklist').multiSelect({ + oncheck:blackListChange, + onuncheck:blackListChange, + createText:'...' + }); + + // Trigger ajax on recoveryAdmin status change + $( 'input:radio[name="adminEnableRecovery"]' ).change( + function() { + + var recoveryStatus = $( this ).val(); + + $.post( + OC.filePath( 'files_encryption', 'ajax', 'adminrecovery.php' ) + , { adminEnableRecovery: recoveryStatus, recoveryPassword: 'password' } + , function( data ) { + alert( data ); + } + ); + } + ); + + function blackListChange(){ + var blackList=$( '#encryption_blacklist' ).val().join( ',' ); + OC.AppConfig.setValue( 'files_encryption', 'type_blacklist', blackList ); + } +}) \ No newline at end of file diff --git a/apps/files_encryption/js/settings-personal.js b/apps/files_encryption/js/settings-personal.js new file mode 100644 index 00000000000..e4a1b7448f4 --- /dev/null +++ b/apps/files_encryption/js/settings-personal.js @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2013, Sam Tuke + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +$(document).ready(function(){ + // Trigger ajax on recoveryAdmin status change + $( 'input:radio[name="userEnableRecovery"]' ).change( + function() { + + var recoveryStatus = $( this ).val(); + + $.post( + OC.filePath( 'files_encryption', 'ajax', 'userrecovery.php' ) + , { userEnableRecovery: recoveryStatus } + , function( data ) { + alert( data ); + } + ); + } + ); +}) \ No newline at end of file diff --git a/apps/files_encryption/js/settings.js b/apps/files_encryption/js/settings.js deleted file mode 100644 index 9a0bebf2478..00000000000 --- a/apps/files_encryption/js/settings.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2011, Robin Appelman - * This file is licensed under the Affero General Public License version 3 or later. - * See the COPYING-README file. - */ - - -$(document).ready(function(){ - // Trigger ajax on filetype blacklist change - $('#encryption_blacklist').multiSelect({ - oncheck:blackListChange, - onuncheck:blackListChange, - createText:'...' - }); - - // Trigger ajax on recoveryAdmin status change - $( 'input:radio[name="adminEnableRecovery"]' ).change( - function() { - - var foo = $( this ).val(); - - $.post( - OC.filePath('files_encryption', 'ajax', 'adminrecovery.php') - , { adminEnableRecovery: foo, recoveryPassword: 'password' } - , function( data ) { - alert( data ); - } - ); - } - ); - - function blackListChange(){ - var blackList=$('#encryption_blacklist').val().join(','); - OC.AppConfig.setValue('files_encryption','type_blacklist',blackList); - } -}) \ No newline at end of file diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 9f3cb8120ca..51d4f8ffc04 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -32,7 +32,7 @@ class Keymanager { /** * @brief retrieve the ENCRYPTED private key from a user * - * @return string private key or false + * @return string private key or false (hopefully) * @note the key returned by this method must be decrypted before use */ public static function getPrivateKey( \OC_FilesystemView $view, $user ) { diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index 0c6a7131fd9..0e6bb96605f 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -35,22 +35,28 @@ class Session { * * The ownCloud key pair is used to allow public link sharing even if encryption is enabled */ - public function __construct( \OC_FilesystemView $view ) { + public function __construct( $view ) { $this->view = $view; if ( ! $this->view->is_dir( 'owncloud_private_key' ) ) { - $this->view->mkdir('owncloud_private_key'); + $this->view->mkdir( 'owncloud_private_key' ); + } - if ( - ! $this->view->file_exists("/public-keys/owncloud.public.key") - || ! $this->view->file_exists("/owncloud_private_key/owncloud.private.key" ) + ! $this->view->file_exists( "/public-keys/owncloud.public.key" ) + || ! $this->view->file_exists( "/owncloud_private_key/owncloud.private.key" ) ) { - + + //FIXME: Bug: for some reason file_exists is returning + // false in above if statement, and causing new keys + // to be generated on each page load. At last check + // our app.php is being executed 18 times per page load + // , causing 18 new keypairs and huge performance hit. + $keypair = Crypt::createKeypair(); \OC_FileProxy::$enabled = false; diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index eabb34f7ab0..015125370bc 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -24,11 +24,8 @@ # Bugs # ---- # Sharing a file to a user without encryption set up will not provide them with access but won't notify the sharer -# Timeouts on first login due to encryption of very large files (fix in progress, as a result streaming is currently broken) # Sharing all files to admin for recovery purposes still in progress # Possibly public links are broken (not tested since last merge of master) -# encryptAll during login mangles paths: /files/files/ -# encryptAll is accessing files via encryption proxy - perhaps proxies should be disabled? # Missing features @@ -204,12 +201,18 @@ class Util { $this->view->file_put_contents( $this->privateKeyPath, $encryptedPrivateKey ); \OC_FileProxy::$enabled = true; - - // create database configuration - $sql = 'INSERT INTO `*PREFIX*encryption` (`uid`,`mode`,`recovery`) VALUES (?,?,?)'; - $args = array( $this->userId, 'server-side', 0); - $query = \OCP\DB::prepare( $sql ); - $query->execute( $args ); + + } + + // If there's no record for this user's encryption preferences + if ( false === $this->recoveryEnabledForUser() ) { + + // create database configuration + $sql = 'INSERT INTO `*PREFIX*encryption` (`uid`,`mode`,`recovery`) VALUES (?,?,?)'; + $args = array( $this->userId, 'server-side', 0); + $query = \OCP\DB::prepare( $sql ); + $query->execute( $args ); + } return true; @@ -218,11 +221,11 @@ class Util { /** * @brief Check whether pwd recovery is enabled for a given user - * @return bool + * @return 1 = yes, 0 = no, false = no record * @note If records are not being returned, check for a hidden space * at the start of the uid in db */ - public function recoveryEnabled() { + public function recoveryEnabledForUser() { $sql = 'SELECT recovery @@ -237,16 +240,25 @@ class Util { $result = $query->execute( $args ); - // Set default in case no records found - $recoveryEnabled = 0; + $recoveryEnabled = array(); while( $row = $result->fetchRow() ) { - $recoveryEnabled = $row['recovery']; + $recoveryEnabled[] = $row['recovery']; } - return $recoveryEnabled; + // If no record is found + if ( empty( $recoveryEnabled ) ) { + + return false; + + // If a record is found + } else { + + return $recoveryEnabled[0]; + + } } @@ -255,20 +267,33 @@ class Util { * @param bool $enabled Whether to enable or disable recovery * @return bool */ - public function setRecovery( $enabled ) { + public function setRecoveryForUser( $enabled ) { - $sql = 'UPDATE - *PREFIX*encryption - SET - recovery = ? - WHERE - uid = ?'; + $recoveryStatus = $this->recoveryEnabledForUser(); + + // If a record for this user already exists, update it + if ( false === $recoveryStatus ) { - // Ensure value is an integer - $enabled = intval( $enabled ); + $sql = 'INSERT INTO `*PREFIX*encryption` + (`uid`,`mode`,`recovery`) + VALUES (?,?,?)'; + + $args = array( $this->userId, 'server-side', $enabled ); - $args = array( $enabled, $this->userId ); - + // Create a new record instead + } else { + + $sql = 'UPDATE + *PREFIX*encryption + SET + recovery = ? + WHERE + uid = ?'; + + $args = array( $enabled, $this->userId ); + + } + $query = \OCP\DB::prepare( $sql ); if ( $query->execute( $args ) ) { @@ -888,7 +913,7 @@ class Util { public function getSharingUsersArray( $sharingEnabled, $filePath, $currentUserId = false ) { // Check if key recovery is enabled - $recoveryEnabled = $this->recoveryEnabled(); + $recoveryEnabled = $this->recoveryEnabledForUser(); // Make sure that a share key is generated for the owner too list($owner, $ownerPath) = $this->getUidAndFilename($filePath); diff --git a/apps/files_encryption/settings-admin.php b/apps/files_encryption/settings-admin.php new file mode 100644 index 00000000000..b09515f0c33 --- /dev/null +++ b/apps/files_encryption/settings-admin.php @@ -0,0 +1,28 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +\OC_Util::checkAdminUser(); + +$tmpl = new OCP\Template( 'files_encryption', 'settings-admin' ); + +$blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) ); + +// Check if an adminRecovery account is enabled for recovering files after lost pwd +$view = new OC_FilesystemView( '' ); + +$recoveryAdminEnabled = OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' ); +$recoveryAdminUid = OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminUid' ); + +$tmpl->assign( 'blacklist', $blackList ); +$tmpl->assign( 'encryption_mode', \OC_Appconfig::getValue( 'files_encryption', 'mode', 'none' ) ); +$tmpl->assign( 'recoveryEnabled', $recoveryAdminEnabled ); + +\OCP\Util::addscript( 'files_encryption', 'settings-admin' ); +\OCP\Util::addscript( 'core', 'multiselect' ); + +return $tmpl->fetchPage(); diff --git a/apps/files_encryption/settings-personal.php b/apps/files_encryption/settings-personal.php index c001bb0d725..f7ebc425120 100644 --- a/apps/files_encryption/settings-personal.php +++ b/apps/files_encryption/settings-personal.php @@ -10,6 +10,26 @@ $tmpl = new OCP\Template( 'files_encryption', 'settings-personal'); $blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) ); +// Add human readable message in case nothing is blacklisted +if ( + 1 == count( $blackList ) + && $blackList[0] == '' +) { + + // FIXME: Make this string translatable + $blackList[0] = "(None - all filetypes will be encrypted)"; + +} + +$user = \OCP\USER::getUser(); +$view = new \OC_FilesystemView( '/' ); +$util = new \OCA\Encryption\Util( $view, $user ); + +$recoveryEnabledForUser = $util->recoveryEnabledForUser(); + +\OCP\Util::addscript( 'files_encryption', 'settings-personal' ); + +$tmpl->assign( 'recoveryEnabled', $recoveryEnabledForUser ); $tmpl->assign( 'blacklist', $blackList ); return $tmpl->fetchPage(); diff --git a/apps/files_encryption/settings.php b/apps/files_encryption/settings.php deleted file mode 100644 index 71d47f061af..00000000000 --- a/apps/files_encryption/settings.php +++ /dev/null @@ -1,27 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -\OC_Util::checkAdminUser(); - -$tmpl = new OCP\Template( 'files_encryption', 'settings' ); - -$blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) ); - -// Check if an adminRecovery account is enabled for recovering files after lost pwd -$view = new OC_FilesystemView( '' ); -$util = new \OCA\Encryption\Util( $view, \OCP\USER::getUser() ); -$recoveryEnabled = $util->recoveryEnabled(); - -$tmpl->assign( 'blacklist', $blackList ); -$tmpl->assign( 'encryption_mode', \OC_Appconfig::getValue( 'files_encryption', 'mode', 'none' ) ); -$tmpl->assign( 'recoveryEnabled', $recoveryEnabled ); - -\OCP\Util::addscript( 'files_encryption', 'settings' ); -\OCP\Util::addscript( 'core', 'multiselect' ); - -return $tmpl->fetchPage(); diff --git a/apps/files_encryption/templates/settings-admin.php b/apps/files_encryption/templates/settings-admin.php new file mode 100644 index 00000000000..6499d0c8e80 --- /dev/null +++ b/apps/files_encryption/templates/settings-admin.php @@ -0,0 +1,39 @@ +
+
+ +

+ t( 'Encryption' )); ?> +
+ + t( "Exclude the following file types from encryption:" )); ?> +
+ + +

+

+ t( "Enable encryption passwords recovery account (allow sharing to recovery account):" )); ?> +
+ /> + t( "Enabled" )); ?> +
+ + /> + t( "Disabled" )); ?> +

+
+
diff --git a/apps/files_encryption/templates/settings-personal.php b/apps/files_encryption/templates/settings-personal.php index 5f0accaed5f..0cefde36b61 100644 --- a/apps/files_encryption/templates/settings-personal.php +++ b/apps/files_encryption/templates/settings-personal.php @@ -3,6 +3,7 @@ t( 'Encryption' )); ?> +

t( 'File encryption is enabled.' )); ?>

@@ -10,6 +11,7 @@

t( 'The following file types will not be encrypted:' )); ?>

+
  • @@ -18,5 +20,25 @@
+ +

+ t( "Enable password recovery by sharing all files with administrator:" )); ?> +
+ /> + t( "Enabled" )); ?> +
+ + /> + t( "Disabled" )); ?> +

+ diff --git a/apps/files_encryption/templates/settings.php b/apps/files_encryption/templates/settings.php deleted file mode 100644 index 6499d0c8e80..00000000000 --- a/apps/files_encryption/templates/settings.php +++ /dev/null @@ -1,39 +0,0 @@ -
-
- -

- t( 'Encryption' )); ?> -
- - t( "Exclude the following file types from encryption:" )); ?> -
- - -

-

- t( "Enable encryption passwords recovery account (allow sharing to recovery account):" )); ?> -
- /> - t( "Enabled" )); ?> -
- - /> - t( "Disabled" )); ?> -

-
-
diff --git a/apps/files_encryption/tests/util.php b/apps/files_encryption/tests/util.php index e3ec0860fa5..d0a988f96b9 100755 --- a/apps/files_encryption/tests/util.php +++ b/apps/files_encryption/tests/util.php @@ -179,23 +179,23 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase { } - function testRecoveryEnabled() { + function testRecoveryEnabledForUser() { $util = new Encryption\Util( $this->view, $this->userId ); // Record the value so we can return it to it's original state later - $enabled = $util->recoveryEnabled(); + $enabled = $util->recoveryEnabledForUser(); - $this->assertTrue( $util->setRecovery( 1 ) ); + $this->assertTrue( $util->setRecoveryForUser( 1 ) ); - $this->assertEquals( 1, $util->recoveryEnabled() ); + $this->assertEquals( 1, $util->recoveryEnabledForUser() ); - $this->assertTrue( $util->setRecovery( 0 ) ); + $this->assertTrue( $util->setRecoveryForUser( 0 ) ); - $this->assertEquals( 0, $util->recoveryEnabled() ); + $this->assertEquals( 0, $util->recoveryEnabledForUser() ); // Return the setting to it's previous state - $this->assertTrue( $util->setRecovery( $enabled ) ); + $this->assertTrue( $util->setRecoveryForUser( $enabled ) ); } -- cgit v1.2.3 From 9605d14a17522dd47c760a1c37a0374cfb0551b9 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Sat, 4 May 2013 03:37:22 +0200 Subject: fixed re-share problems --- apps/files_encryption/hooks/hooks.php | 64 +++++++++++++++++++++++++++++------ apps/files_encryption/lib/util.php | 19 +++++++++++ 2 files changed, 72 insertions(+), 11 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index c0e493752a0..c21b9d69f69 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -200,16 +200,57 @@ class Hooks { $util = new Util($view, $userId); $path = $util->fileIdToPath($params['itemSource']); - //check if this is a reshare action, that's true if the item source is already shared with me - $sharedItem = \OCP\Share::getItemSharedWithBySource($params['itemType'], $params['fileSource']); - if ($sharedItem) { - // if it is a re-share than the file is located in my Shared folder - $path = '/Shared'.$sharedItem['file_target']; - } else { - $path = $util->fileIdToPath($params['fileSource']); - } + //if parent is set, then this is a re-share action + if($params['parent']) { + + // get the parent from current share + $parent = $util->getShareParent($params['parent']); + + // if parent is file the it is an 1:1 share + if($parent['item_type'] === 'file') { + + // prefix path with Shared + $path = '/Shared'.$parent['file_target']; + + } else { + // parent is folder but shared was a file! + // we try to rebuild the missing path + // some examples we face here + // user1 share folder1 with user2 folder1 has the following structure /folder1/subfolder1/subsubfolder1/somefile.txt + // user2 re-share subfolder2 with user3 + // user3 re-share somefile.txt user4 + // so our path should be /Shared/subfolder1/subsubfolder1/somefile.txt while user3 is sharing + if($params['itemType'] === 'file') { + // get target path + $targetPath = $util->fileIdToPath($params['fileSource']); + $targetPathSplit = array_reverse(explode('/', $targetPath)); + + // init values + $path = ''; + $sharedPart = ltrim( $parent['file_target'], '/' ); + + // rebuild path + foreach ($targetPathSplit as $pathPart) { + if($pathPart !== $sharedPart) { + $path = '/'.$pathPart.$path; + } else { + break; + } + } + + // prefix path with Shared + $path = '/Shared'.$parent['file_target'].$path; + + } else { + + // prefix path with Shared + $path = '/Shared'.$parent['file_target']; + } + } + + } - $sharingEnabled = \OCP\Share::isEnabled(); + $sharingEnabled = \OCP\Share::isEnabled(); // if a folder was shared, get a list if all (sub-)folders if ($params['itemType'] === 'folder') { @@ -274,13 +315,14 @@ class Hooks { $allFiles = array($path); } - + foreach ( $allFiles as $path ) { // check if the user still has access to the file, otherwise delete share key $sharingUsers = $util->getSharingUsersArray(true, $path); - // Unshare every user who no longer has access to the file + // Unshare every user who no longer has access to the file + //TODO: does not work properly atm $delUsers = array_diff($userIds, $sharingUsers); if ( ! Keymanager::delShareKey( $view, $delUsers, $path ) ) { diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 015125370bc..f442a89f6f9 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -1028,4 +1028,23 @@ class Util { return $result; } + /** + * @brief get shares parent. + * @param int $Id of the current share + * @return array of the parent + */ + public static function getShareParent($Id) { + + $query = \OC_DB::prepare( 'SELECT `file_target`, `item_type`' + .' FROM `*PREFIX*share`' + .' WHERE `id` = ?' ); + + $result = $query->execute( array( $Id ) ); + + $row = $result->fetchRow(); + + return $row; + + } + } -- cgit v1.2.3 From c8946ea6086c642a5c367f2e5f63d58bc185c331 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Sat, 4 May 2013 16:14:38 +0200 Subject: Added support for user-specified password for adminRecovery account in admin settings page Made encryptAll() (file migration for unencrypted + legacy encrypted files) run only on first login for each user (status stored in DB) Made recoveryAdmin user member of 'admin' user group automatically Set recoveryadmin settings to only display on user settings if enabled by an admin Updated encryption db xml schema --- apps/files_encryption/ajax/adminrecovery.php | 3 + apps/files_encryption/appinfo/database.xml | 7 ++ apps/files_encryption/hooks/hooks.php | 73 ++++++++------ apps/files_encryption/js/settings-admin.js | 24 +++-- apps/files_encryption/lib/session.php | 34 +++---- apps/files_encryption/lib/util.php | 109 ++++++++++++++++++--- apps/files_encryption/settings-admin.php | 1 + apps/files_encryption/settings-personal.php | 4 +- apps/files_encryption/templates/settings-admin.php | 11 ++- .../templates/settings-personal.php | 38 +++---- 10 files changed, 215 insertions(+), 89 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/ajax/adminrecovery.php b/apps/files_encryption/ajax/adminrecovery.php index 157fc8f313c..eeeaf4c6ed7 100644 --- a/apps/files_encryption/ajax/adminrecovery.php +++ b/apps/files_encryption/ajax/adminrecovery.php @@ -34,6 +34,9 @@ if ( // Create new recoveryAdmin user \OC_User::createUser( $recoveryAdminUid, $_POST['recoveryPassword'] ); + // Make recovery user an administrator + \OC_Group::addToGroup ( $recoveryAdminUid, 'admin' ); + $doSetup = true; } else { diff --git a/apps/files_encryption/appinfo/database.xml b/apps/files_encryption/appinfo/database.xml index b144b6cb2a4..64c9ef65fa8 100644 --- a/apps/files_encryption/appinfo/database.xml +++ b/apps/files_encryption/appinfo/database.xml @@ -27,6 +27,13 @@ 0 Whether encryption key recovery is enabled
+ + migrationStatus + boolean + true + 0 + Whether encryption migration has been performed + \ No newline at end of file diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index c21b9d69f69..0633a81a057 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -69,43 +69,52 @@ class Hooks { $session = new Session( $view ); $session->setPrivateKey( $privateKey, $params['uid'] ); - - //FIXME: disabled because it gets called each time a user do an operation on iPhone - //FIXME: we need a better place doing this and maybe only one time or by user - /*$view1 = new \OC_FilesystemView( '/' . $params['uid'] ); - - // Set legacy encryption key if it exists, to support - // depreciated encryption system - if ( - $view1->file_exists( 'encryption.key' ) - && $encLegacyKey = $view1->file_get_contents( 'encryption.key' ) - ) { - - $plainLegacyKey = Crypt::legacyDecrypt( $encLegacyKey, $params['password'] ); - - $session->setLegacyKey( $plainLegacyKey ); - - } - \OC_FileProxy::$enabled = false; - - $publicKey = Keymanager::getPublicKey( $view, $params['uid'] ); + // Check if first-run file migration has already been performed + $migrationCompleted = $util->getMigrationStatus(); - \OC_FileProxy::$enabled = false;*/ + // If migration not yet done + if ( ! $migrationCompleted ) { - // Encrypt existing user files: - // This serves to upgrade old versions of the encryption - // app (see appinfo/spec.txt) - /*if ( - $util->encryptAll( $publicKey, '/' . $params['uid'] . '/' . 'files', $session->getLegacyKey(), $params['password'] ) - ) { + $view1 = new \OC_FilesystemView( '/' . $params['uid'] ); + + // Set legacy encryption key if it exists, to support + // depreciated encryption system + if ( + $view1->file_exists( 'encryption.key' ) + && $encLegacyKey = $view1->file_get_contents( 'encryption.key' ) + ) { - \OC_Log::write( - 'Encryption library', 'Encryption of existing files belonging to "' . $params['uid'] . '" started at login' - , \OC_Log::INFO - ); + $plainLegacyKey = Crypt::legacyDecrypt( $encLegacyKey, $params['password'] ); + + $session->setLegacyKey( $plainLegacyKey ); + + } + + \OC_FileProxy::$enabled = false; + + $publicKey = Keymanager::getPublicKey( $view, $params['uid'] ); + + \OC_FileProxy::$enabled = false; + + // Encrypt existing user files: + // This serves to upgrade old versions of the encryption + // app (see appinfo/spec.txt) + if ( + $util->encryptAll( $publicKey, '/' . $params['uid'] . '/' . 'files', $session->getLegacyKey(), $params['password'] ) + ) { + + \OC_Log::write( + 'Encryption library', 'Encryption of existing files belonging to "' . $params['uid'] . '" completed' + , \OC_Log::INFO + ); + + } + + // Register successful migration in DB + $util->setMigrationStatus( 1 ); - }*/ + } return true; diff --git a/apps/files_encryption/js/settings-admin.js b/apps/files_encryption/js/settings-admin.js index 48b5598d524..8e9c8c22306 100644 --- a/apps/files_encryption/js/settings-admin.js +++ b/apps/files_encryption/js/settings-admin.js @@ -19,14 +19,24 @@ $(document).ready(function(){ function() { var recoveryStatus = $( this ).val(); + var recoveryPassword = $( '#recoveryPassword' ).val(); - $.post( - OC.filePath( 'files_encryption', 'ajax', 'adminrecovery.php' ) - , { adminEnableRecovery: recoveryStatus, recoveryPassword: 'password' } - , function( data ) { - alert( data ); - } - ); + if ( '' == recoveryPassword ) { + + // FIXME: add proper OC notification + alert( 'You must set a recovery account password first' ); + + } else { + + $.post( + OC.filePath( 'files_encryption', 'ajax', 'adminrecovery.php' ) + , { adminEnableRecovery: recoveryStatus, recoveryPassword: recoveryPassword } + , function( data ) { + alert( data ); + } + ); + + } } ); diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index 0e6bb96605f..22453131db7 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -57,23 +57,23 @@ class Session { // our app.php is being executed 18 times per page load // , causing 18 new keypairs and huge performance hit. - $keypair = Crypt::createKeypair(); - - \OC_FileProxy::$enabled = false; - - // Save public key - - if (!$view->is_dir('/public-keys')) { - $view->mkdir('/public-keys'); - } - - $this->view->file_put_contents( '/public-keys/owncloud.public.key', $keypair['publicKey'] ); - - // Encrypt private key empthy passphrase - $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], '' ); - - // Save private key - $this->view->file_put_contents( '/owncloud_private_key/owncloud.private.key', $encryptedPrivateKey ); +// $keypair = Crypt::createKeypair(); +// +// \OC_FileProxy::$enabled = false; +// +// // Save public key +// +// if (!$view->is_dir('/public-keys')) { +// $view->mkdir('/public-keys'); +// } +// +// $this->view->file_put_contents( '/public-keys/owncloud.public.key', $keypair['publicKey'] ); +// +// // Encrypt private key empthy passphrase +// $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], '' ); +// +// // Save private key +// $this->view->file_put_contents( '/owncloud_private_key/owncloud.private.key', $encryptedPrivateKey ); \OC_FileProxy::$enabled = true; diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index f442a89f6f9..91502af4a3f 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -859,8 +859,6 @@ class Util { // Make sure users are capable of sharing $filteredUids = $this->filterShareReadyUsers( $users ); -// trigger_error( print_r($filteredUids, 1) ); - if ( ! empty( $filteredUids['unready'] ) ) { // Notify user of unready userDir @@ -913,10 +911,21 @@ class Util { public function getSharingUsersArray( $sharingEnabled, $filePath, $currentUserId = false ) { // Check if key recovery is enabled - $recoveryEnabled = $this->recoveryEnabledForUser(); + if ( + \OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' ) + && $this->recoveryEnabledForUser() + ) { + + $recoveryEnabled = true; + + } else { + + $recoveryEnabled = false; + + } // Make sure that a share key is generated for the owner too - list($owner, $ownerPath) = $this->getUidAndFilename($filePath); + list( $owner, $ownerPath ) = $this->getUidAndFilename( $filePath ); if ( $sharingEnabled ) { @@ -928,18 +937,21 @@ class Util { // If recovery is enabled, add the // Admin UID to list of users to share to if ( $recoveryEnabled ) { - - // FIXME: Create a separate admin user purely for recovery, and create method in util for fetching this id from DB? - $adminUid = 'recoveryAdmin'; - - $userIds[] = $adminUid; + + // Find recoveryAdmin user ID + $recoveryAdminUid = \OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminUid' ); + + // Add recoveryAdmin to list of users sharing + $userIds[] = $recoveryAdminUid; } - // add current user if given - if($currentUserId != false) { - $userIds[] = $currentUserId; - } + // add current user if given + if ( $currentUserId != false ) { + + $userIds[] = $currentUserId; + + } // Remove duplicate UIDs $uniqueUserIds = array_unique ( $userIds ); @@ -947,6 +959,77 @@ class Util { return $uniqueUserIds; } + + /** + * @brief Set file migration status for user + */ + public function setMigrationStatus( $status ) { + + $sql = 'UPDATE + *PREFIX*encryption + SET + migrationStatus = ? + WHERE + uid = ?'; + + $args = array( $status, $this->userId ); + + $query = \OCP\DB::prepare( $sql ); + + if ( $query->execute( $args ) ) { + + return true; + + } else { + + return false; + + } + + } + + /** + * @brief Check whether pwd recovery is enabled for a given user + * @return 1 = yes, 0 = no, false = no record + * @note If records are not being returned, check for a hidden space + * at the start of the uid in db + */ + public function getMigrationStatus() { + + $sql = 'SELECT + migrationStatus + FROM + `*PREFIX*encryption` + WHERE + uid = ?'; + + $args = array( $this->userId ); + + $query = \OCP\DB::prepare( $sql ); + + $result = $query->execute( $args ); + + $migrationStatus = array(); + + while( $row = $result->fetchRow() ) { + + $migrationStatus[] = $row['migrationStatus']; + + } + + // If no record is found + if ( empty( $migrationStatus ) ) { + + return false; + + // If a record is found + } else { + + return $migrationStatus[0]; + + } + + } /** * @brief get uid of the owners of the file and the path to the file diff --git a/apps/files_encryption/settings-admin.php b/apps/files_encryption/settings-admin.php index b09515f0c33..ae9a85643ef 100644 --- a/apps/files_encryption/settings-admin.php +++ b/apps/files_encryption/settings-admin.php @@ -21,6 +21,7 @@ $recoveryAdminUid = OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminUi $tmpl->assign( 'blacklist', $blackList ); $tmpl->assign( 'encryption_mode', \OC_Appconfig::getValue( 'files_encryption', 'mode', 'none' ) ); $tmpl->assign( 'recoveryEnabled', $recoveryAdminEnabled ); +$tmpl->assign( 'recoveryAdminUid', $recoveryAdminUid ); \OCP\Util::addscript( 'files_encryption', 'settings-admin' ); \OCP\Util::addscript( 'core', 'multiselect' ); diff --git a/apps/files_encryption/settings-personal.php b/apps/files_encryption/settings-personal.php index f7ebc425120..c6d9d80f0b9 100644 --- a/apps/files_encryption/settings-personal.php +++ b/apps/files_encryption/settings-personal.php @@ -25,11 +25,13 @@ $user = \OCP\USER::getUser(); $view = new \OC_FilesystemView( '/' ); $util = new \OCA\Encryption\Util( $view, $user ); +$recoveryAdminEnabled = OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' ); $recoveryEnabledForUser = $util->recoveryEnabledForUser(); \OCP\Util::addscript( 'files_encryption', 'settings-personal' ); -$tmpl->assign( 'recoveryEnabled', $recoveryEnabledForUser ); +$tmpl->assign( 'recoveryEnabled', $recoveryAdminEnabled ); +$tmpl->assign( 'recoveryEnabledForUser', $recoveryEnabledForUser ); $tmpl->assign( 'blacklist', $blackList ); return $tmpl->fetchPage(); diff --git a/apps/files_encryption/templates/settings-admin.php b/apps/files_encryption/templates/settings-admin.php index 6499d0c8e80..863f1dfa9a5 100644 --- a/apps/files_encryption/templates/settings-admin.php +++ b/apps/files_encryption/templates/settings-admin.php @@ -18,8 +18,17 @@

- t( "Enable encryption passwords recovery account (allow sharing to recovery account):" )); ?> + + t( "Enable encryption passwords recovery account (allow sharing to recovery account):" )); ?>
+
+ t( "To perform a recovery log in using the 'recoveryAdmin' account and the specified password" )); ?> +
+ + + +
+ -

- t( "Enable password recovery by sharing all files with administrator:" )); ?> -
- /> - t( "Enabled" )); ?> -
- - /> - t( "Disabled" )); ?> -

+ +

+ t( "Enable password recovery by sharing all files with administrator:" )); ?> +
+ /> + t( "Enabled" )); ?> +
+ + /> + t( "Disabled" )); ?> +

+ -- cgit v1.2.3 From 5610429a02352df36e2e64f25e0a8af474915268 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Sun, 5 May 2013 23:41:42 +0200 Subject: handling for re-share and re-unshare should work now --- apps/files_encryption/hooks/hooks.php | 132 +++++++++++++++++++--------------- apps/files_encryption/lib/util.php | 48 ++++++++++++- 2 files changed, 120 insertions(+), 60 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 0633a81a057..a72d339277a 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -23,10 +23,11 @@ namespace OCA\Encryption; +use OC\Files\Filesystem; + /** * Class for hook specific logic */ - class Hooks { // TODO: use passphrase for encrypting private key that is separate to @@ -253,10 +254,9 @@ class Hooks { } else { // prefix path with Shared - $path = '/Shared'.$parent['file_target']; + $path = '/Shared'.$parent['file_target'].$params['fileTarget']; } } - } $sharingEnabled = \OCP\Share::isEnabled(); @@ -282,10 +282,8 @@ class Hooks { // If no attempts to set keyfiles failed if (empty($failed)) { - return true; } else { - return false; } } @@ -294,73 +292,91 @@ class Hooks { /** * @brief */ - public static function postUnshare( $params ) { - - // NOTE: $params has keys: - // [itemType] => file - // [itemSource] => 13 - // [shareType] => 0 - // [shareWith] => test1 - - if ( $params['itemType'] === 'file' || $params['itemType'] === 'folder' ) { - - $view = new \OC_FilesystemView( '/' ); - $session = new Session($view); - $userId = \OCP\User::getUser(); - $util = new Util( $view, $userId ); - $path = $util->fileIdToPath( $params['itemSource'] ); + public static function postUnshare($params) + { - // for group shares get a list of the group members - if ($params['shareType'] == \OCP\Share::SHARE_TYPE_GROUP) { - $userIds = \OC_Group::usersInGroup($params['shareWith']); - } else { - $userIds = array($params['shareWith']); - } + // NOTE: $params has keys: + // [itemType] => file + // [itemSource] => 13 + // [shareType] => 0 + // [shareWith] => test1 + // [itemParent] => - // if we unshare a folder we need a list of all (sub-)files - if ($params['itemType'] === 'folder') { - $allFiles = $util->getAllFiles($path); - } else { - $allFiles = array($path); - } + if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') { + + $view = new \OC_FilesystemView('/'); + $userId = \OCP\User::getUser(); + $util = new Util($view, $userId); + $path = $util->fileIdToPath($params['itemSource']); + // check if this is a re-share + if ($params['itemParent']) { + + // get the parent from current share + $parent = $util->getShareParent($params['itemParent']); - foreach ( $allFiles as $path ) { + // get target path + $targetPath = $util->fileIdToPath($params['itemSource']); + $targetPathSplit = array_reverse(explode('/', $targetPath)); - // check if the user still has access to the file, otherwise delete share key - $sharingUsers = $util->getSharingUsersArray(true, $path); + // init values + $path = ''; + $sharedPart = ltrim($parent['file_target'], '/'); + + // rebuild path + foreach ($targetPathSplit as $pathPart) { + if ($pathPart !== $sharedPart) { + $path = '/' . $pathPart . $path; + } else { + break; + } + } + + // prefix path with Shared + $path = '/Shared' . $parent['file_target'] . $path; + } + + // for group shares get a list of the group members + if ($params['shareType'] == \OCP\Share::SHARE_TYPE_GROUP) { + $userIds = \OC_Group::usersInGroup($params['shareWith']); + } else { + $userIds = array($params['shareWith']); + } + + // if we unshare a folder we need a list of all (sub-)files + if ($params['itemType'] === 'folder') { + $allFiles = $util->getAllFiles($path); + } else { + $allFiles = array($path); + } + + foreach ($allFiles as $path) { + + // check if the user still has access to the file, otherwise delete share key + $sharingUsers = $util->getSharingUsersArray(true, $path); // Unshare every user who no longer has access to the file - //TODO: does not work properly atm - $delUsers = array_diff($userIds, $sharingUsers); - if ( ! Keymanager::delShareKey( $view, $delUsers, $path ) ) { - - $failed[] = $path; - - } - - } - - // If no attempts to set keyfiles failed - if ( empty( $failed ) ) { - - return true; - - } else { - - return false; - - } + $delUsers = array_diff($userIds, $sharingUsers); + if (!Keymanager::delShareKey($view, $delUsers, $path)) { + $failed[] = $path; + } - } + } - } + // If no attempts to set keyfiles failed + if (empty($failed)) { + return true; + } else { + return false; + } + } + } /** * @brief */ public static function postUnshareAll( $params ) { - + // NOTE: It appears that this is never called for files, so // we may not need to implement it diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 91502af4a3f..2e8e2af683b 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -1102,10 +1102,26 @@ class Util { } foreach ($content as $c) { + $sharedPart = $path_split[sizeof($path_split)-1]; + $targetPathSplit = array_reverse(explode('/', $c['path'])); + + $path = ''; + + // rebuild path + foreach ($targetPathSplit as $pathPart) { + if($pathPart !== $sharedPart) { + $path = '/'.$pathPart.$path; + } else { + break; + } + } + + $path = $dir.$path; + if ($c['type'] === "dir" ) { - $result = array_merge($result, $this->getAllFiles($shared.substr($c['path'],5))); + $result = array_merge($result, $this->getAllFiles($path)); } else { - $result[] = $shared.substr($c['path'], 5); + $result[] = $path; } } return $result; @@ -1130,4 +1146,32 @@ class Util { } + /** + * @brief get owner of the shared files. + * @param int $Id of a share + * @return owner + */ + public function getOwnerFromSharedFile($id) { + $query = \OC_DB::prepare('SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1); + $source = $query->execute(array($id))->fetchRow(); + + if (isset($source['parent'])) { + $parent = $source['parent']; + while (isset($parent)) { + $query = \OC_DB::prepare('SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1); + $item = $query->execute(array($parent))->fetchRow(); + if (isset($item['parent'])) { + $parent = $item['parent']; + } else { + $fileOwner = $item['uid_owner']; + break; + } + } + } else { + $fileOwner = $source['uid_owner']; + } + + return $fileOwner; + } + } -- cgit v1.2.3 From fe6d12ddec46e5d68486d5db22a8508a2ab2b2ea Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Mon, 6 May 2013 21:15:25 +0200 Subject: fix file info put on stream --- apps/files_encryption/lib/stream.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index a51f2c56d95..eb1cb45871c 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -512,7 +512,19 @@ class Stream { // Re-enable proxy - our work is done \OC_FileProxy::$enabled = $proxyStatus; - \OC\Files\Filesystem::putFileInfo( $this->relPath, array( 'encrypted' => 1, 'size' => $this->size, 'unencrypted_size' => $this->unencryptedSize ), '' ); + // get file info + $fileInfo = \OC\Files\Filesystem::getFileInfo($this->rawPath); + if(!is_array($fileInfo)) { + $fileInfo = array(); + } + + // set encryption data + $fileInfo['encrypted'] = 1; + $fileInfo['size'] = $this->size; + $fileInfo['unencrypted_size'] = $this->unencryptedSize; + + // set fileinfo + \OC\Files\Filesystem::putFileInfo( $this->rawPath, $fileInfo); } return fclose( $this->handle ); -- cgit v1.2.3 From a9649713d31f9524355680515ed9fe080eba6d63 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Tue, 7 May 2013 13:42:08 +0200 Subject: fix empty path --- apps/files_encryption/lib/proxy.php | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 50f30594b42..820b7d8b67e 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -433,6 +433,11 @@ class Proxy extends \OC_FileProxy { $path_split = explode('/', $path); $path_f = implode('/', array_slice($path_split, 3)); + // if path is empty we cannot resolve anything + if(empty($path_f)) { + return $size; + } + // get file info from database/cache $fileInfo = \OC\Files\Filesystem::getFileInfo($path_f); -- cgit v1.2.3 From 8b545538722179ea7e68c4765fa9722adc77d546 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Tue, 7 May 2013 13:42:49 +0200 Subject: fix for wrong file infos --- apps/files_encryption/lib/stream.php | 4 ++-- apps/files_encryption/lib/util.php | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index eb1cb45871c..c2b13b00b24 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -513,7 +513,7 @@ class Stream { \OC_FileProxy::$enabled = $proxyStatus; // get file info - $fileInfo = \OC\Files\Filesystem::getFileInfo($this->rawPath); + $fileInfo = $view->getFileInfo($this->rawPath); if(!is_array($fileInfo)) { $fileInfo = array(); } @@ -524,7 +524,7 @@ class Stream { $fileInfo['unencrypted_size'] = $this->unencryptedSize; // set fileinfo - \OC\Files\Filesystem::putFileInfo( $this->rawPath, $fileInfo); + $view->putFileInfo( $this->rawPath, $fileInfo); } return fclose( $this->handle ); diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 2e8e2af683b..5ab5ea6425f 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -1040,7 +1040,8 @@ class Util { */ public function getUidAndFilename( $path ) { - $fileOwnerUid = \OC\Files\Filesystem::getOwner( $path ); + $view = new \OC\Files\View($this->userFilesDir); + $fileOwnerUid = $view->getOwner( $path ); // Check that UID is valid if ( ! \OCP\User::userExists( $fileOwnerUid ) ) { @@ -1060,7 +1061,7 @@ class Util { } else { - $info = \OC\Files\Filesystem::getFileInfo( $path ); + $info = $view->getFileInfo( $path ); $ownerView = new \OC\Files\View( '/' . $fileOwnerUid . '/files' ); // Fetch real file path from DB @@ -1069,7 +1070,7 @@ class Util { } // Make path relative for use by $view - $relpath = $fileOwnerUid . '/' . $this->fileFolderName . '/' . $filename; + $relpath = \OC\Files\Filesystem::normalizePath($fileOwnerUid . '/' . $this->fileFolderName . '/' . $filename); // Check that the filename we're using is working if ( $this->view->file_exists( $relpath ) ) { -- cgit v1.2.3 From 28866de44bbf5c5bc2b1e0689b5139047ba5273b Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Wed, 8 May 2013 16:22:08 +0200 Subject: Added pre_share hook Switched it for post_share hook in encryption hooks Stop a file from being shared if the encryption procedure fails for any users --- apps/files_encryption/appinfo/app.php | 2 +- apps/files_encryption/hooks/hooks.php | 17 ++-- apps/files_encryption/lib/util.php | 9 +- lib/public/share.php | 169 +++++++++++++++++++++++----------- 4 files changed, 130 insertions(+), 67 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index a7253c43332..7f01aaeebeb 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -16,7 +16,7 @@ OCP\Util::connectHook( 'OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login' OCP\Util::connectHook( 'OC_User', 'pre_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase' ); // Sharing-related hooks -OCP\Util::connectHook( 'OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared' ); +OCP\Util::connectHook( 'OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared' ); OCP\Util::connectHook( 'OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare' ); OCP\Util::connectHook( 'OCP\Share', 'post_unshareAll', 'OCA\Encryption\Hooks', 'postUnshareAll' ); diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index ddec839acdc..1f642f48415 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -183,7 +183,7 @@ class Hooks { /** * @brief */ - public static function postShared( $params ) { + public static function preShared( $params ) { // NOTE: $params has keys: // [itemType] => file @@ -201,6 +201,7 @@ class Hooks { // [fileTarget] => /test8 // [id] => 10 // [token] => + // [run] => whether emitting script should continue to run // TODO: Should other kinds of item be encrypted too? if ( $params['itemType'] === 'file' || $params['itemType'] === 'folder' ) { @@ -249,7 +250,7 @@ class Hooks { // rebuild path foreach ( $targetPathSplit as $pathPart ) { - if( $pathPart !== $sharedPart ) { + if ( $pathPart !== $sharedPart ) { $path = '/' . $pathPart . $path; @@ -295,15 +296,13 @@ class Hooks { $failed[] = $path; } } - - // If no attempts to set keyfiles failed - if ( empty( $failed ) ) { - return true; + // If some attempts to set keyfiles failed + if ( ! empty( $failed ) ) { - } else { - - return false; + // Set flag var 'run' to notify emitting + // script that hook execution failed + $params['run']->run = false; } } diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 5ab5ea6425f..871d3bcfc37 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -146,7 +146,7 @@ class Util { return false; } else { - + return true; } @@ -855,15 +855,14 @@ class Util { * @param string $filePath path of the file to be shared */ public function setSharedFileKeyfiles( Session $session, array $users, $filePath ) { - + // Make sure users are capable of sharing $filteredUids = $this->filterShareReadyUsers( $users ); if ( ! empty( $filteredUids['unready'] ) ) { - // Notify user of unready userDir - // TODO: Move this out of here; it belongs somewhere else - \OCP\JSON::error(); + // TODO: Notify user of unready userDir + \OC_Log::write( 'Encryption library', 'Sharing to these user(s) failed as they are unready for encryption:"'.print_r( $filteredUids['unready'], 1 ), \OC_Log::WARN ); } diff --git a/lib/public/share.php b/lib/public/share.php index fee906d1877..cb151b9f4bf 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -1223,42 +1223,12 @@ class Share { } else { $groupFileTarget = null; } - $query->execute(array($itemType, $itemSource, $groupItemTarget, $parent, $shareType, - $shareWith['group'], $uidOwner, $permissions, time(), $fileSource, $groupFileTarget, $token)); - // Save this id, any extra rows for this group share will need to reference it - $parent = \OC_DB::insertid('*PREFIX*share'); - // Loop through all users of this group in case we need to add an extra row - foreach ($shareWith['users'] as $uid) { - $itemTarget = self::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $uid, - $uidOwner, $suggestedItemTarget, $parent); - if (isset($fileSource)) { - if ($parentFolder) { - if ($parentFolder === true) { - $fileTarget = self::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $uid, - $uidOwner, $suggestedFileTarget, $parent); - if ($fileTarget != $groupFileTarget) { - $parentFolders[$uid]['folder'] = $fileTarget; - } - } else if (isset($parentFolder[$uid])) { - $fileTarget = $parentFolder[$uid]['folder'].$itemSource; - $parent = $parentFolder[$uid]['id']; - } - } else { - $fileTarget = self::generateTarget('file', $filePath, self::SHARE_TYPE_USER, - $uid, $uidOwner, $suggestedFileTarget, $parent); - } - } else { - $fileTarget = null; - } - // Insert an extra row for the group share if the item or file target is unique for this user - if ($itemTarget != $groupItemTarget || (isset($fileSource) && $fileTarget != $groupFileTarget)) { - $query->execute(array($itemType, $itemSource, $itemTarget, $parent, - self::$shareTypeGroupUserUnique, $uid, $uidOwner, $permissions, time(), - $fileSource, $fileTarget, $token)); - $id = \OC_DB::insertid('*PREFIX*share'); - } - } - \OC_Hook::emit('OCP\Share', 'post_shared', array( + // Trigger hooks before the share is added to DB + // Set flag indicating if execution should continue. + // Use an object as workaround for pass by reference issues + $run = new \stdClass(); + $run->run = true; + $params = array( 'itemType' => $itemType, 'itemSource' => $itemSource, 'itemTarget' => $groupItemTarget, @@ -1270,11 +1240,73 @@ class Share { 'fileSource' => $fileSource, 'fileTarget' => $groupFileTarget, 'id' => $parent, - 'token' => $token - )); - if ($parentFolder === true) { - // Return parent folders to preserve file target paths for potential children - return $parentFolders; + 'token' => $token, + 'run' => $run + ); + $run = \OC_Hook::emit( + 'OCP\Share' + , 'pre_shared' + , $params + ); + // If hook execution didn't encounter errors + if ( ! $run->run ) { + $message = 'Sharing '.$itemSource.' failed, because pre share hooks failed'; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + return false; + } else { + $query->execute(array($itemType, $itemSource, $groupItemTarget, $parent, $shareType, + $shareWith['group'], $uidOwner, $permissions, time(), $fileSource, $groupFileTarget, $token)); + // Save this id, any extra rows for this group share will need to reference it + $parent = \OC_DB::insertid('*PREFIX*share'); + // Loop through all users of this group in case we need to add an extra row + foreach ($shareWith['users'] as $uid) { + $itemTarget = self::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $uid, + $uidOwner, $suggestedItemTarget, $parent); + if (isset($fileSource)) { + if ($parentFolder) { + if ($parentFolder === true) { + $fileTarget = self::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $uid, + $uidOwner, $suggestedFileTarget, $parent); + if ($fileTarget != $groupFileTarget) { + $parentFolders[$uid]['folder'] = $fileTarget; + } + } else if (isset($parentFolder[$uid])) { + $fileTarget = $parentFolder[$uid]['folder'].$itemSource; + $parent = $parentFolder[$uid]['id']; + } + } else { + $fileTarget = self::generateTarget('file', $filePath, self::SHARE_TYPE_USER, + $uid, $uidOwner, $suggestedFileTarget, $parent); + } + } else { + $fileTarget = null; + } + // Insert an extra row for the group share if the item or file target is unique for this user + if ($itemTarget != $groupItemTarget || (isset($fileSource) && $fileTarget != $groupFileTarget)) { + $query->execute(array($itemType, $itemSource, $itemTarget, $parent, + self::$shareTypeGroupUserUnique, $uid, $uidOwner, $permissions, time(), + $fileSource, $fileTarget, $token)); + $id = \OC_DB::insertid('*PREFIX*share'); + } + } + \OC_Hook::emit('OCP\Share', 'post_shared', array( + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'itemTarget' => $groupItemTarget, + 'parent' => $parent, + 'shareType' => $shareType, + 'shareWith' => $shareWith['group'], + 'uidOwner' => $uidOwner, + 'permissions' => $permissions, + 'fileSource' => $fileSource, + 'fileTarget' => $groupFileTarget, + 'id' => $parent, + 'token' => $token + )); + if ($parentFolder === true) { + // Return parent folders to preserve file target paths for potential children + return $parentFolders; + } } } else { $itemTarget = self::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, @@ -1296,10 +1328,14 @@ class Share { } else { $fileTarget = null; } - $query->execute(array($itemType, $itemSource, $itemTarget, $parent, $shareType, $shareWith, $uidOwner, - $permissions, time(), $fileSource, $fileTarget, $token)); - $id = \OC_DB::insertid('*PREFIX*share'); - \OC_Hook::emit('OCP\Share', 'post_shared', array( + // Trigger hooks before the share is added to DB + // Set flag indicating if execution should continue. + // Use an object as workaround for pass by reference issues + $run = new \stdClass(); + $run->run = true; + // NOTE: [id] isn't included as it's not yet available + // (hasn't been inserted) + $params = array( 'itemType' => $itemType, 'itemSource' => $itemSource, 'itemTarget' => $itemTarget, @@ -1310,13 +1346,42 @@ class Share { 'permissions' => $permissions, 'fileSource' => $fileSource, 'fileTarget' => $fileTarget, - 'id' => $id, - 'token' => $token - )); - if ($parentFolder === true) { - $parentFolders['id'] = $id; - // Return parent folder to preserve file target paths for potential children - return $parentFolders; + 'token' => $token, + 'run' => $run + ); + \OC_Hook::emit( + 'OCP\Share' + , 'pre_shared' + , $params + ); + // If hook execution didn't encounter errors + if ( ! $run->run ) { + $message = 'Sharing '.$itemSource.' failed, because pre share hooks failed'; + \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); + return false; + } else { + $query->execute(array($itemType, $itemSource, $itemTarget, $parent, $shareType, $shareWith, $uidOwner, + $permissions, time(), $fileSource, $fileTarget, $token)); + $id = \OC_DB::insertid('*PREFIX*share'); + \OC_Hook::emit('OCP\Share', 'post_shared', array( + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'itemTarget' => $itemTarget, + 'parent' => $parent, + 'shareType' => $shareType, + 'shareWith' => $shareWith, + 'uidOwner' => $uidOwner, + 'permissions' => $permissions, + 'fileSource' => $fileSource, + 'fileTarget' => $fileTarget, + 'id' => $id, + 'token' => $token + )); + if ($parentFolder === true) { + $parentFolders['id'] = $id; + // Return parent folder to preserve file target paths for potential children + return $parentFolders; + } } } return true; -- cgit v1.2.3 From 101e037529fef0273ba9d4de522d2e47d8a6ef0b Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Thu, 9 May 2013 14:43:06 +0200 Subject: Fixed bugs with pre_share hook usage Made sure new user being shared to is added to array of sharing users --- apps/files_encryption/hooks/hooks.php | 18 +++- apps/files_encryption/lib/util.php | 176 +++++++++++++++++++--------------- 2 files changed, 115 insertions(+), 79 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 1f642f48415..e8cd4ade713 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -277,21 +277,28 @@ class Hooks { // if a folder was shared, get a list if all (sub-)folders if ( $params['itemType'] === 'folder' ) { - $allFiles = $util->getAllFiles($path); + + $allFiles = $util->getAllFiles( $path ); + } else { $allFiles = array( $path ); } + + // Set array for collecting paths which can't be shared + $failed = array(); foreach ( $allFiles as $path ) { $usersSharing = $util->getSharingUsersArray( $sharingEnabled, $path ); - - $failed = array(); + + // Because this is a pre_share hook, the user + // being shared to is not yet included; add them + $usersSharing[] = $params['shareWith']; // Attempt to set shareKey - if ( !$util->setSharedFileKeyfiles( $session, $usersSharing, $path ) ) { + if ( ! $util->setSharedFileKeyfiles( $session, $usersSharing, $path ) ) { $failed[] = $path; } @@ -304,6 +311,9 @@ class Hooks { // script that hook execution failed $params['run']->run = false; + // TODO: Make sure files_sharing provides user + // feedback on failed share + } } } diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 871d3bcfc37..068f7148425 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -3,8 +3,8 @@ * ownCloud * * @author Sam Tuke, Frank Karlitschek - * @copyright 2012 Sam Tuke samtuke@owncloud.com, - * Frank Karlitschek frank@owncloud.org + * @copyright 2012 Sam Tuke , + * Frank Karlitschek * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -88,16 +88,9 @@ class Util { //// TODO: add support for optional recovery in case of lost passphrase / keys //// TODO: add admin optional required long passphrase for users - //// TODO: add UI buttons for encrypt / decrypt everything //// TODO: implement flag system to allow user to specify encryption by folder, subfolder, etc. - // Sharing: - - //// TODO: add support for encrypting to multiple public keys - //// TODO: add support for decrypting to multiple private keys - - // Integration testing: //// TODO: test new encryption with versioning @@ -136,11 +129,11 @@ class Util { public function ready() { if( - !$this->view->file_exists( $this->encryptionDir ) - or !$this->view->file_exists( $this->keyfilesPath ) - or !$this->view->file_exists( $this->shareKeysPath ) - or !$this->view->file_exists( $this->publicKeyPath ) - or !$this->view->file_exists( $this->privateKeyPath ) + ! $this->view->file_exists( $this->encryptionDir ) + or ! $this->view->file_exists( $this->keyfilesPath ) + or ! $this->view->file_exists( $this->shareKeysPath ) + or ! $this->view->file_exists( $this->publicKeyPath ) + or ! $this->view->file_exists( $this->privateKeyPath ) ) { return false; @@ -471,9 +464,8 @@ class Util { /** * @brief get the file size of the unencrypted file - * * @param $path absolute path - * @return true / false if file is encrypted + * @return bool */ public function getFileSize($path) { @@ -768,7 +760,7 @@ class Util { * @return multi-dimensional array. keys: ready, unready */ public function filterShareReadyUsers( $unfilteredUsers ) { - + // This array will collect the filtered IDs $readyIds = $unreadyIds = array(); @@ -780,8 +772,8 @@ class Util { // Check that the user is encryption capable, or is the // public system user 'ownCloud' (for public shares) if ( - $util->ready() - or $user == 'owncloud' + $user == 'owncloud' + or $util->ready() ) { // Construct array of ready UIDs for Keymanager{} @@ -853,22 +845,27 @@ class Util { * @brief Encrypt keyfile to multiple users * @param array $users list of users which should be able to access the file * @param string $filePath path of the file to be shared + * @return bool */ public function setSharedFileKeyfiles( Session $session, array $users, $filePath ) { // Make sure users are capable of sharing $filteredUids = $this->filterShareReadyUsers( $users ); + // If we're attempting to share to unready users if ( ! empty( $filteredUids['unready'] ) ) { - - // TODO: Notify user of unready userDir + \OC_Log::write( 'Encryption library', 'Sharing to these user(s) failed as they are unready for encryption:"'.print_r( $filteredUids['unready'], 1 ), \OC_Log::WARN ); + return false; + } // Get public keys for each user, ready for generating sharekeys $userPubKeys = Keymanager::getPublicKeys( $this->view, $filteredUids['ready'] ); - + + // Note proxy status then disable it + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; // Get the current users's private key for decrypting existing keyfile @@ -884,21 +881,19 @@ class Util { // Save the recrypted key to it's owner's keyfiles directory // Save new sharekeys to all necessary user directory - // TODO: Reuse the keyfile, it it exists, instead of making a new one if ( ! Keymanager::setFileKey( $this->view, $filePath, $fileOwner, $multiEncKey['data'] ) || ! Keymanager::setShareKeys( $this->view, $filePath, $multiEncKey['keys'] ) ) { - trigger_error( "SET Share keys failed" ); + \OC_Log::write( 'Encryption library', 'Keyfiles could not be saved for users sharing ' . $filePath, \OC_Log::ERROR ); + + return false; } - - // Delete existing keyfile - // Do this last to ensure file is recoverable in case of error - // Keymanager::deleteFileKey( $this->view, $this->userId, $params['fileTarget'] ); - - \OC_FileProxy::$enabled = true; + + // Return proxy to original status + \OC_FileProxy::$enabled = $proxyStatus; return true; } @@ -948,7 +943,7 @@ class Util { // add current user if given if ( $currentUserId != false ) { - $userIds[] = $currentUserId; + $userIds[] = $currentUserId; } @@ -961,6 +956,7 @@ class Util { /** * @brief Set file migration status for user + * @return bool */ public function setMigrationStatus( $status ) { @@ -1089,42 +1085,59 @@ class Util { * @param type $dir relative to the users files folder * @return array with list of files relative to the users files folder */ - public function getAllFiles($dir) { + public function getAllFiles( $dir ) { + $result = array(); - $content = $this->view->getDirectoryContent($this->userFilesDir.$dir); + $content = $this->view->getDirectoryContent( $this->userFilesDir . $dir ); - // handling for re shared folders - $path_split = explode( '/', $dir ); - $shared = ''; - if($path_split[1] === 'Shared') { - $shared = '/Shared'; - } + // handling for re shared folders + $path_split = explode( '/', $dir ); + $shared = ''; + + if( $path_split[1] === 'Shared' ) { + + $shared = '/Shared'; + + } - foreach ($content as $c) { - $sharedPart = $path_split[sizeof($path_split)-1]; - $targetPathSplit = array_reverse(explode('/', $c['path'])); + foreach ( $content as $c ) { + + $sharedPart = $path_split[sizeof( $path_split )-1]; + $targetPathSplit = array_reverse( explode( '/', $c['path'] ) ); - $path = ''; + $path = ''; - // rebuild path - foreach ($targetPathSplit as $pathPart) { - if($pathPart !== $sharedPart) { - $path = '/'.$pathPart.$path; - } else { - break; - } - } + // rebuild path + foreach ( $targetPathSplit as $pathPart ) { + + if ( $pathPart !== $sharedPart ) { + + $path = '/' . $pathPart . $path; + + } else { + + break; + + } + + } - $path = $dir.$path; + $path = $dir.$path; if ($c['type'] === "dir" ) { - $result = array_merge($result, $this->getAllFiles($path)); + + $result = array_merge( $result, $this->getAllFiles( $path ) ); + } else { - $result[] = $path; + + $result[] = $path; + } } + return $result; + } /** @@ -1132,7 +1145,7 @@ class Util { * @param int $Id of the current share * @return array of the parent */ - public static function getShareParent($Id) { + public static function getShareParent( $Id ) { $query = \OC_DB::prepare( 'SELECT `file_target`, `item_type`' .' FROM `*PREFIX*share`' @@ -1152,26 +1165,39 @@ class Util { * @return owner */ public function getOwnerFromSharedFile($id) { - $query = \OC_DB::prepare('SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1); - $source = $query->execute(array($id))->fetchRow(); - - if (isset($source['parent'])) { - $parent = $source['parent']; - while (isset($parent)) { - $query = \OC_DB::prepare('SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1); - $item = $query->execute(array($parent))->fetchRow(); - if (isset($item['parent'])) { - $parent = $item['parent']; - } else { - $fileOwner = $item['uid_owner']; - break; - } - } - } else { - $fileOwner = $source['uid_owner']; - } + + $query = \OC_DB::prepare( 'SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1 ); + $source = $query->execute( array( $id ) )->fetchRow(); - return $fileOwner; - } + if ( isset($source['parent'] ) ) { + + $parent = $source['parent']; + + while ( isset( $parent ) ) { + + $query = \OC_DB::prepare( 'SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1 ); + $item = $query->execute( array( $parent ) )->fetchRow(); + + if ( isset( $item['parent'] ) ) { + + $parent = $item['parent']; + + } else { + + $fileOwner = $item['uid_owner']; + + break; + + } + } + + } else { + + $fileOwner = $source['uid_owner']; + + } + + return $fileOwner; + } } -- cgit v1.2.3 From 3003dd46d17e9d4b70a5b19d4a7807bb0fbad298 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Thu, 9 May 2013 18:09:20 +0200 Subject: Implemented initial recoveryAdmin functionality in crypto file proxy --- apps/files_encryption/lib/proxy.php | 83 +++++++++++++++++++++++++++---------- apps/files_encryption/lib/util.php | 22 ++++++++-- 2 files changed, 80 insertions(+), 25 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 820b7d8b67e..ae36b9fe09f 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -93,29 +93,29 @@ class Proxy extends \OC_FileProxy { public function preFile_put_contents( $path, &$data ) { - if ( self::shouldEncrypt( $path ) ) { + if ( self::shouldEncrypt( $path ) ) { - // Stream put contents should have been converted to fopen + // Stream put contents should have been converted to fopen if ( !is_resource( $data ) ) { - $userId = \OCP\USER::getUser(); - $rootView = new \OC_FilesystemView( '/' ); - $util = new Util( $rootView, $userId ); - $session = new Session( $rootView ); + $userId = \OCP\USER::getUser(); + $view = new \OC_FilesystemView( '/' ); + $util = new Util( $view, $userId ); + $session = new Session( $view ); $privateKey = $session->getPrivateKey(); $filePath = $util->stripUserFilesPath( $path ); // Set the filesize for userland, before encrypting $size = strlen( $data ); - + // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + // Check if there is an existing key we can reuse - if ( $encKeyfile = Keymanager::getFileKey( $rootView, $userId, $filePath ) ) { + if ( $encKeyfile = Keymanager::getFileKey( $view, $userId, $filePath ) ) { // Fetch shareKey - $shareKey = Keymanager::getShareKey( $rootView, $userId, $filePath ); + $shareKey = Keymanager::getShareKey( $view, $userId, $filePath ); // Decrypt the keyfile $plainKey = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); @@ -124,7 +124,7 @@ class Proxy extends \OC_FileProxy { // Make a new key $plainKey = Crypt::generateKey(); - + } // Encrypt data @@ -134,34 +134,73 @@ class Proxy extends \OC_FileProxy { $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $filePath, $userId ); - // Fetch public keys for all users who will share the file - $publicKeys = Keymanager::getPublicKeys( $rootView, $uniqueUserIds ); + // Fetch public keys for all users who will share the file + $publicKeys = Keymanager::getPublicKeys( $view, $uniqueUserIds ); - // Encrypt plain keyfile to multiple sharefiles + // Encrypt plain keyfile to multiple sharefiles $multiEncrypted = Crypt::multiKeyEncrypt( $plainKey, $publicKeys ); // Save sharekeys to user folders - Keymanager::setShareKeys( $rootView, $filePath, $multiEncrypted['keys'] ); + Keymanager::setShareKeys( $view, $filePath, $multiEncrypted['keys'] ); // Set encrypted keyfile as common varname $encKey = $multiEncrypted['data']; // Save keyfile for newly encrypted file in parallel directory tree - Keymanager::setFileKey( $rootView, $filePath, $userId, $encKey ); + Keymanager::setFileKey( $view, $filePath, $userId, $encKey ); // Replace plain content with encrypted content by reference $data = $encData; - + // Update the file cache with file info - \OC\Files\Filesystem::putFileInfo( $filePath, array( 'encrypted'=>true, 'size' => strlen($size), 'unencrypted_size' => $size), '' ); + \OC\Files\Filesystem::putFileInfo( $filePath, array( 'encrypted'=>true, 'size' => strlen($size), 'unencrypted_size' => $size), '' ); - // Re-enable proxy - our work is done + // Re-enable proxy - our work is done \OC_FileProxy::$enabled = $proxyStatus; } } - return true; + return true; + + } + + public function postFile_put_contents( $path, $length ) { + + $userId = \OCP\USER::getUser(); + $view = new \OC_FilesystemView( '/' ); + $util = new Util( $view, $userId ); + + // Check if recoveryAdmin is enabled for system and user + // TODO: Consider storing recoveryAdmin status for user in session + if ( + \OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' ) + && $util->recoveryEnabledForUser() + ) { + + // Get owner UID and filepath + list( $owner, $ownerPath ) = $util->getUidAndFilename( $path ); + + $recoveryAdminUid = \OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' ); + $usersSharing = \OCP\Share::getUsersSharingFile( $ownerPath, $owner,true, true, true ); + + // Check if file is already shared to recoveryAdmin + if ( ! in_array( $recoveryAdminUid, $usersSharing ) ) { + + $relPath = $util->stripFilesPath( $path ); + + // Get file info from filecache + $fileInfo = \OC\Files\Filesystem::getFileInfo( $path ); + + // Register share to recoveryAdmin with share API + // FIXME: Some of these vars aren't set + // FIXME: What should the permission number be to grant all rights? +// \OCP\Share::shareItem( $itemType, $itemSource, 0, $recoveryAdminUid, 17 ); + + } + + } + } /** diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 068f7148425..41d51fbf6fb 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -548,6 +548,7 @@ class Util { /** * @brief Format a path to be relative to the /user/files/ directory + * @note e.g. turns '/admin/files/test.txt' into 'test.txt' */ public function stripUserFilesPath( $path ) { @@ -560,6 +561,21 @@ class Util { } + /** + * @brief Format a path to be relative to the /user directory + * @note e.g. turns '/admin/files/test.txt' into 'files/test.txt' + */ + public function stripFilesPath( $path ) { + + $trimmed = ltrim( $path, '/' ); + $split = explode( '/', $trimmed ); + $sliced = array_slice( $split, 1 ); + $relPath = implode( '/', $sliced ); + + return $relPath; + + } + /** * @brief Format a shared path to be relative to the /user/files/ directory * @note Expects a path like /uid/files/Shared/filepath @@ -1142,16 +1158,16 @@ class Util { /** * @brief get shares parent. - * @param int $Id of the current share + * @param int $id of the current share * @return array of the parent */ - public static function getShareParent( $Id ) { + public static function getShareParent( $id ) { $query = \OC_DB::prepare( 'SELECT `file_target`, `item_type`' .' FROM `*PREFIX*share`' .' WHERE `id` = ?' ); - $result = $query->execute( array( $Id ) ); + $result = $query->execute( array( $id ) ); $row = $result->fetchRow(); -- cgit v1.2.3 From 92e28839ffe31c5173fe49481705db15a3a4acb2 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Thu, 9 May 2013 18:16:59 +0200 Subject: Improvements to code formatting & indentation --- apps/files_encryption/lib/util.php | 223 +++++++++++++++++++------------------ 1 file changed, 114 insertions(+), 109 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 41d51fbf6fb..04b1e66f58a 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -305,7 +305,6 @@ class Util { * @brief Find all files and their encryption status within a directory * @param string $directory The path of the parent directory to search * @return mixed false if 0 found, array on success. Keys: name, path - * @note $directory needs to be a path relative to OC data dir. e.g. * /admin/files NOT /backup OR /home/www/oc/data/admin/files */ @@ -444,10 +443,10 @@ class Util { return $text; } - /** - * @brief Check if a given path identifies an encrypted file - * @return true / false - */ + /** + * @brief Check if a given path identifies an encrypted file + * @return true / false + */ public function isEncryptedPath( $path ) { // Disable encryption proxy so data retreived is in its @@ -462,89 +461,94 @@ class Util { } - /** - * @brief get the file size of the unencrypted file - * @param $path absolute path - * @return bool - */ + /** + * @brief get the file size of the unencrypted file + * @param $path absolute path + * @return bool + */ - public function getFileSize($path) { - $result = 0; + public function getFileSize( $path ) { + + $result = 0; - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // Reformat path for use with OC_FSV - $pathSplit = explode( '/', $path ); - $pathRelative = implode( '/', array_slice( $pathSplit, 3 ) ); + // Reformat path for use with OC_FSV + $pathSplit = explode( '/', $path ); + $pathRelative = implode( '/', array_slice( $pathSplit, 3 ) ); - if ($pathSplit[2] == 'files' && $this->view->file_exists($path) && $this->isEncryptedPath($path)) { + if ($pathSplit[2] == 'files' && $this->view->file_exists($path) && $this->isEncryptedPath($path)) { - // get the size from filesystem - $fullPath = $this->view->getLocalFile($path); - $size = filesize($fullPath); + // get the size from filesystem + $fullPath = $this->view->getLocalFile($path); + $size = filesize($fullPath); - // calculate last chunk nr - $lastChunckNr = floor($size / 8192); + // calculate last chunk nr + $lastChunckNr = floor($size / 8192); - // open stream - $stream = fopen('crypt://' . $pathRelative, "r"); + // open stream + $stream = fopen('crypt://' . $pathRelative, "r"); - if(is_resource($stream)) { - // calculate last chunk position - $lastChunckPos = ($lastChunckNr * 8192); + if(is_resource($stream)) { + // calculate last chunk position + $lastChunckPos = ($lastChunckNr * 8192); - // seek to end - fseek($stream, $lastChunckPos); + // seek to end + fseek($stream, $lastChunckPos); - // get the content of the last chunk - $lastChunkContent = fread($stream, 8192); + // get the content of the last chunk + $lastChunkContent = fread($stream, 8192); - // calc the real file size with the size of the last chunk - $realSize = (($lastChunckNr * 6126) + strlen($lastChunkContent)); + // calc the real file size with the size of the last chunk + $realSize = (($lastChunckNr * 6126) + strlen($lastChunkContent)); - // store file size - $result = $realSize; - } - } + // store file size + $result = $realSize; + } + } - \OC_FileProxy::$enabled = $proxyStatus; + \OC_FileProxy::$enabled = $proxyStatus; - return $result; - } - /** - * @brief fix the file size of the encrypted file - * - * @param $path absolute path - * @return true / false if file is encrypted - */ + return $result; + } + + /** + * @brief fix the file size of the encrypted file + * @param $path absolute path + * @return true / false if file is encrypted + */ - public function fixFileSize($path) { - $result = false; + public function fixFileSize( $path ) { + + $result = false; - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - $realSize = $this->getFileSize($path); - if($realSize > 0) { - $cached = $this->view->getFileInfo($path); - $cached['encrypted'] = 1; + $realSize = $this->getFileSize( $path ); + + if ( $realSize > 0 ) { + + $cached = $this->view->getFileInfo( $path ); + $cached['encrypted'] = 1; - // set the size - $cached['unencrypted_size'] = $realSize; + // set the size + $cached['unencrypted_size'] = $realSize; - // put file info - $this->view->putFileInfo( $path, $cached ); + // put file info + $this->view->putFileInfo( $path, $cached ); - $result = true; - } + $result = true; + + } - \OC_FileProxy::$enabled = $proxyStatus; + \OC_FileProxy::$enabled = $proxyStatus; - return $result; - } + return $result; + } /** * @brief Format a path to be relative to the /user/files/ directory @@ -640,7 +644,7 @@ class Util { stream_copy_to_stream( $plainHandle1, $plainHandle2 ); // Close access to original file -// $this->view->fclose( $plainHandle1 ); // not implemented in view{} + // $this->view->fclose( $plainHandle1 ); // not implemented in view{} // Delete original plain file so we can rename enc file later $this->view->unlink( $rawPath ); @@ -1156,64 +1160,65 @@ class Util { } - /** - * @brief get shares parent. - * @param int $id of the current share - * @return array of the parent - */ - public static function getShareParent( $id ) { - - $query = \OC_DB::prepare( 'SELECT `file_target`, `item_type`' - .' FROM `*PREFIX*share`' - .' WHERE `id` = ?' ); + /** + * @brief get shares parent. + * @param int $id of the current share + * @return array of the parent + */ + public static function getShareParent( $id ) { - $result = $query->execute( array( $id ) ); + $query = \OC_DB::prepare( 'SELECT `file_target`, `item_type`' + .' FROM `*PREFIX*share`' + .' WHERE `id` = ?' ); - $row = $result->fetchRow(); + $result = $query->execute( array( $id ) ); - return $row; + $row = $result->fetchRow(); - } + return $row; - /** - * @brief get owner of the shared files. - * @param int $Id of a share - * @return owner - */ - public function getOwnerFromSharedFile($id) { - - $query = \OC_DB::prepare( 'SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1 ); - $source = $query->execute( array( $id ) )->fetchRow(); + } - if ( isset($source['parent'] ) ) { + /** + * @brief get owner of the shared files. + * @param int $Id of a share + * @return owner + */ + public function getOwnerFromSharedFile( $id ) { - $parent = $source['parent']; - - while ( isset( $parent ) ) { + $query = \OC_DB::prepare( 'SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1 ); + $source = $query->execute( array( $id ) )->fetchRow(); + + if ( isset($source['parent'] ) ) { - $query = \OC_DB::prepare( 'SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1 ); - $item = $query->execute( array( $parent ) )->fetchRow(); + $parent = $source['parent']; - if ( isset( $item['parent'] ) ) { + while ( isset( $parent ) ) { - $parent = $item['parent']; + $query = \OC_DB::prepare( 'SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1 ); + $item = $query->execute( array( $parent ) )->fetchRow(); + + if ( isset( $item['parent'] ) ) { + + $parent = $item['parent']; + + } else { + + $fileOwner = $item['uid_owner']; + + break; + + } + } - } else { + } else { - $fileOwner = $item['uid_owner']; - - break; + $fileOwner = $source['uid_owner']; - } } - - } else { - - $fileOwner = $source['uid_owner']; - - } return $fileOwner; + } } -- cgit v1.2.3 From 163fe6401609a9bdb4ee71127e4f6724b1804af0 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Thu, 9 May 2013 18:24:07 +0200 Subject: Fixes to code formatting and indentation --- apps/files_encryption/lib/keymanager.php | 166 ++++++++++++++++++------------- 1 file changed, 99 insertions(+), 67 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 51d4f8ffc04..6c2df6f8406 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -113,8 +113,8 @@ class Keymanager { \OC_FileProxy::$enabled = false; //here we need the currently logged in user, while userId can be a different user - $util = new Util($view, \OCP\User::getUser()); - list($owner, $filename) = $util->getUidAndFilename($path); + $util = new Util( $view, \OCP\User::getUser() ); + list( $owner, $filename ) = $util->getUidAndFilename( $path ); $basePath = '/' . $owner . '/files_encryption/keyfiles'; @@ -123,19 +123,26 @@ class Keymanager { if ( !$view->is_dir( $basePath . '/' . $targetPath ) ) { // create all parent folders - $info=pathinfo($basePath . '/' . $targetPath); - $keyfileFolderName=$view->getLocalFolder($info['dirname']); - if(!file_exists($keyfileFolderName)) { - mkdir($keyfileFolderName, 0750, true); + $info = pathinfo( $basePath . '/' . $targetPath ); + $keyfileFolderName = $view->getLocalFolder( $info['dirname'] ); + + if ( ! file_exists( $keyfileFolderName ) ) { + + mkdir( $keyfileFolderName, 0750, true ); + } } - // try reusing key file if part file - if(self::isPartialFilePath($targetPath)) { - $result = $view->file_put_contents( $basePath . '/' . self::fixPartialFilePath($targetPath) . '.key', $catfile ); - } else { - $result = $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); - } + // try reusing key file if part file + if ( self::isPartialFilePath( $targetPath ) ) { + + $result = $view->file_put_contents( $basePath . '/' . self::fixPartialFilePath( $targetPath ) . '.key', $catfile ); + + } else { + + $result = $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); + + } \OC_FileProxy::$enabled = $proxyStatus; @@ -143,37 +150,47 @@ class Keymanager { } - /** - * @brief Remove .path extension from a file path - * @param string $path Path that may identify a .part file - * @return string File path without .part extension - * @note this is needed for reusing keys - */ - public static function fixPartialFilePath($path) - { - if (preg_match('/\.part$/', $path)) { + /** + * @brief Remove .path extension from a file path + * @param string $path Path that may identify a .part file + * @return string File path without .part extension + * @note this is needed for reusing keys + */ + public static function fixPartialFilePath( $path ) { + + if (preg_match('/\.part$/', $path)) { - $newLength = strlen($path) - 5; - $fPath = substr($path, 0, $newLength); + $newLength = strlen($path) - 5; + $fPath = substr($path, 0, $newLength); - return $fPath; - } else { + return $fPath; + + } else { - return $path; + return $path; - } + } - } + } - public static function isPartialFilePath($path) - { - if (preg_match('/\.part$/', $path)) { - return true; - } else { - return false; - } + /** + * @brief Check if a path is a .part file + * @param string $path Path that may identify a .part file + * @return bool + */ + public static function isPartialFilePath( $path ) { + + if ( preg_match('/\.part$/', $path ) ) { + + return true; + + } else { + + return false; + + } - } + } /** * @brief retrieve keyfile for an encrypted file * @param \OC_FilesystemView $view @@ -186,21 +203,26 @@ class Keymanager { */ public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) { - // try reusing key file if part file - if(self::isPartialFilePath($filePath)) { - $result = self::getFileKey($view, $userId, self::fixPartialFilePath($filePath)); - if($result) { - return $result; - } - } + // try reusing key file if part file + if ( self::isPartialFilePath( $filePath ) ) { + + $result = self::getFileKey( $view, $userId, self::fixPartialFilePath( $filePath ) ); + + if ( $result ) { + + return $result; + + } + + } $util = new Util($view, \OCP\User::getUser()); list($owner, $filename) = $util->getUidAndFilename($filePath); $filePath_f = ltrim( $filename, '/' ); - $keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key'; + $keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key'; - $proxyStatus = \OC_FileProxy::$enabled; + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; if ( $view->file_exists( $keyfilePath ) ) { @@ -269,7 +291,7 @@ class Keymanager { $view = new \OC_FilesystemView( '/' . $user . '/files_encryption' ); - $proxyStatus = \OC_FileProxy::$enabled; + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; if ( !$view->file_exists( '' ) ) $view->mkdir( '' ); @@ -278,7 +300,8 @@ class Keymanager { \OC_FileProxy::$enabled = $proxyStatus; - return $result; + return $result; + } /** @@ -304,7 +327,7 @@ class Keymanager { $view = new \OC_FilesystemView( '/public-keys' ); - $proxyStatus = \OC_FileProxy::$enabled; + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; if ( !$view->file_exists( '' ) ) $view->mkdir( '' ); @@ -313,7 +336,7 @@ class Keymanager { \OC_FileProxy::$enabled = $proxyStatus; - return $result; + return $result; } @@ -330,28 +353,32 @@ class Keymanager { */ public static function setShareKey( \OC_FilesystemView $view, $path, $userId, $shareKey ) { - //here we need the currently logged in user, while userId can be a different user + // Here we need the currently logged in user, while userId can be a different user $util = new Util( $view, \OCP\User::getUser() ); - list($owner, $filename) = $util->getUidAndFilename($path); + list( $owner, $filename ) = $util->getUidAndFilename( $path ); $basePath = '/' . $owner . '/files_encryption/share-keys'; $shareKeyPath = self::keySetPreparation( $view, $filename, $basePath, $owner ); - // try reusing key file if part file - if(self::isPartialFilePath($shareKeyPath)) { - $writePath = $basePath . '/' . self::fixPartialFilePath($shareKeyPath) . '.' . $userId . '.shareKey'; - } else { - $writePath = $basePath . '/' . $shareKeyPath . '.' . $userId . '.shareKey'; - } + // try reusing key file if part file + if(self::isPartialFilePath($shareKeyPath)) { + + $writePath = $basePath . '/' . self::fixPartialFilePath($shareKeyPath) . '.' . $userId . '.shareKey'; + + } else { + + $writePath = $basePath . '/' . $shareKeyPath . '.' . $userId . '.shareKey'; + + } - $proxyStatus = \OC_FileProxy::$enabled; + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; $result = $view->file_put_contents( $writePath, $shareKey ); - \OC_FileProxy::$enabled = $proxyStatus; + \OC_FileProxy::$enabled = $proxyStatus; if ( is_int( $result ) @@ -407,15 +434,20 @@ class Keymanager { */ public static function getShareKey( \OC_FilesystemView $view, $userId, $filePath ) { - // try reusing key file if part file - if(self::isPartialFilePath($filePath)) { - $result = self::getShareKey($view, $userId, self::fixPartialFilePath($filePath)); - if($result) { - return $result; - } - } + // try reusing key file if part file + if(self::isPartialFilePath($filePath)) { + + $result = self::getShareKey($view, $userId, self::fixPartialFilePath($filePath)); + + if($result) { + + return $result; + + } + + } - $proxyStatus = \OC_FileProxy::$enabled; + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; //here we need the currently logged in user, while userId can be a different user -- cgit v1.2.3 From e25aa78cafda9d922d70c1a1223009df5da93786 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Thu, 9 May 2013 19:36:18 +0200 Subject: added helper class and moved hook registration to it --- apps/files_encryption/appinfo/app.php | 21 +++++------ apps/files_encryption/lib/helper.php | 71 +++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 11 deletions(-) create mode 100755 apps/files_encryption/lib/helper.php (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index 7f01aaeebeb..b611eb798f3 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -8,23 +8,21 @@ OC::$CLASSPATH['OCA\Encryption\Stream'] = 'files_encryption/lib/stream.php'; OC::$CLASSPATH['OCA\Encryption\Proxy'] = 'files_encryption/lib/proxy.php'; OC::$CLASSPATH['OCA\Encryption\Session'] = 'files_encryption/lib/session.php'; OC::$CLASSPATH['OCA\Encryption\Capabilities'] = 'files_encryption/lib/capabilities.php'; +OC::$CLASSPATH['OCA\Encryption\Helper'] = 'files_encryption/lib/helper.php'; OC_FileProxy::register( new OCA\Encryption\Proxy() ); -// User-related hooks -OCP\Util::connectHook( 'OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login' ); -OCP\Util::connectHook( 'OC_User', 'pre_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase' ); +// User related hooks +OCA\Encryption\Helper::registerUserHooks(); -// Sharing-related hooks -OCP\Util::connectHook( 'OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared' ); -OCP\Util::connectHook( 'OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare' ); -OCP\Util::connectHook( 'OCP\Share', 'post_unshareAll', 'OCA\Encryption\Hooks', 'postUnshareAll' ); +// Sharing related hooks +OCA\Encryption\Helper::registerShareHooks(); -// Webdav-related hooks -OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfileFromClient' ); +// Webdav related hooks +OCA\Encryption\Helper::registerWebdavHooks(); -// filesystem hooks -OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename'); +// Filesystem related hooks +OCA\Encryption\Helper::registerFilesystemHooks(); stream_wrapper_register( 'crypt', 'OCA\Encryption\Stream' ); @@ -52,3 +50,4 @@ if ( // Register settings scripts OCP\App::registerAdmin( 'files_encryption', 'settings-admin' ); OCP\App::registerPersonal( 'files_encryption', 'settings-personal' ); + diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php new file mode 100755 index 00000000000..b294a71ec1b --- /dev/null +++ b/apps/files_encryption/lib/helper.php @@ -0,0 +1,71 @@ + + * + * 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 . + * + */ + +namespace OCA\Encryption; + +/** + * @brief Class to manage registration of hooks an various helper methods + */ +class Helper { + + /** + * @brief register share related hooks + * + */ + public static function registerShareHooks() { + + \OCP\Util::connectHook( 'OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared' ); + \OCP\Util::connectHook( 'OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare' ); + \OCP\Util::connectHook( 'OCP\Share', 'post_unshareAll', 'OCA\Encryption\Hooks', 'postUnshareAll' ); + } + + /** + * @brief register user related hooks + * + */ + public static function registerUserHooks() { + + \OCP\Util::connectHook( 'OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login' ); + \OCP\Util::connectHook( 'OC_User', 'pre_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase' ); + } + + /** + * @brief register webdav related hooks + * + */ + public static function registerWebdavHooks() { + + \OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfileFromClient' ); + } + + /** + * @brief register filesystem related hooks + * + */ + public static function registerFilesystemHooks() { + + \OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename'); + } + + +} \ No newline at end of file -- cgit v1.2.3 From e88595638c787e04d1cd6c2df2aabf82ba4729d1 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Sat, 11 May 2013 00:23:30 +0200 Subject: fix for webdav --- apps/files_encryption/lib/proxy.php | 2 +- apps/files_encryption/lib/stream.php | 2 +- apps/files_encryption/lib/util.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index ae36b9fe09f..3f8b8571252 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -492,7 +492,7 @@ class Proxy extends \OC_FileProxy { if($fixSize > 0) { $size = $fixSize; - $fileInfo['encrypted'] = 1; + $fileInfo['encrypted'] = true; $fileInfo['unencrypted_size'] = $size; // put file info diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index c2b13b00b24..33b3255e2af 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -519,7 +519,7 @@ class Stream { } // set encryption data - $fileInfo['encrypted'] = 1; + $fileInfo['encrypted'] = true; $fileInfo['size'] = $this->size; $fileInfo['unencrypted_size'] = $this->unencryptedSize; diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 04b1e66f58a..ae8c7ffd575 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -94,7 +94,7 @@ class Util { // Integration testing: //// TODO: test new encryption with versioning - //// TODO: test new encryption with sharing + //// DONE: test new encryption with sharing //// TODO: test new encryption with proxies @@ -533,7 +533,7 @@ class Util { if ( $realSize > 0 ) { $cached = $this->view->getFileInfo( $path ); - $cached['encrypted'] = 1; + $cached['encrypted'] = true; // set the size $cached['unencrypted_size'] = $realSize; -- cgit v1.2.3 From a6ef25ba08e9f026892a2715af479f0ff1299cce Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Mon, 13 May 2013 14:28:45 +0200 Subject: use preShare hook only to check if all pub keys are available and the postShare hook to finaly update the shareKeys if the file was shared successfully --- apps/files_encryption/hooks/hooks.php | 130 +++++++++++++++------------------- apps/files_encryption/lib/helper.php | 1 + apps/files_encryption/lib/proxy.php | 38 ---------- 3 files changed, 57 insertions(+), 112 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 2d48198939b..e3890ce1d15 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -179,11 +179,40 @@ class Hooks { } } - + + /* + * @brief check if files can be encrypted to every user. + */ + public static function preShared($params) { + + $users = array(); + $view = new \OC\Files\View('/public-keys/'); + + switch ($params['shareType']) { + case \OCP\Share::SHARE_TYPE_USER: + $users[] = $params['shareWith']; + break; + case \OCP\Share::SHARE_TYPE_GROUP: + $users = \OC_Group::usersInGroup($params['shareWith']); + break; + } + + foreach ($users as $user) { + if (!$view->file_exists($user . '.public.key')) { + // Set flag var 'run' to notify emitting + // script that hook execution failed + $params['run']->run = false; + // TODO: Make sure files_sharing provides user + // feedback on failed share + break; + } + } + } + /** * @brief */ - public static function preShared( $params ) { + public static function postShared($params) { // NOTE: $params has keys: // [itemType] => file @@ -203,29 +232,28 @@ class Hooks { // [token] => // [run] => whether emitting script should continue to run // TODO: Should other kinds of item be encrypted too? - - if ( $params['itemType'] === 'file' || $params['itemType'] === 'folder' ) { - $view = new \OC_FilesystemView( '/' ); + if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') { + + $view = new \OC_FilesystemView('/'); $session = new Session($view); $userId = \OCP\User::getUser(); $util = new Util($view, $userId); - $path = $util->fileIdToPath( $params['itemSource'] ); + $path = $util->fileIdToPath($params['itemSource']); //if parent is set, then this is a re-share action - if( $params['parent'] ) { + if ($params['parent']) { // get the parent from current share - $parent = $util->getShareParent( $params['parent'] ); + $parent = $util->getShareParent($params['parent']); // if parent is file the it is an 1:1 share - if($parent['item_type'] === 'file') { - - // prefix path with Shared - $path = '/Shared'.$parent['file_target']; + if ($parent['item_type'] === 'file') { + // prefix path with Shared + $path = '/Shared' . $parent['file_target']; } else { - + // NOTE: parent is folder but shared was a file! // we try to rebuild the missing path // some examples we face here @@ -237,38 +265,29 @@ class Hooks { // so our path should be // /Shared/subfolder1/subsubfolder1/somefile.txt // while user3 is sharing - - if ( $params['itemType'] === 'file' ) { + + if ($params['itemType'] === 'file') { // get target path - $targetPath = $util->fileIdToPath( $params['fileSource'] ); - $targetPathSplit = array_reverse( explode( '/', $targetPath ) ); + $targetPath = $util->fileIdToPath($params['fileSource']); + $targetPathSplit = array_reverse(explode('/', $targetPath)); // init values $path = ''; - $sharedPart = ltrim( $parent['file_target'], '/' ); + $sharedPart = ltrim($parent['file_target'], '/'); // rebuild path - foreach ( $targetPathSplit as $pathPart ) { - - if ( $pathPart !== $sharedPart ) { - + foreach ($targetPathSplit as $pathPart) { + if ($pathPart !== $sharedPart) { $path = '/' . $pathPart . $path; - } else { - break; - } - } - // prefix path with Shared - $path = '/Shared'.$parent['file_target'].$path; - + $path = '/Shared' . $parent['file_target'] . $path; } else { - // prefix path with Shared - $path = '/Shared'.$parent['file_target'].$params['fileTarget']; + $path = '/Shared' . $parent['file_target'] . $params['fileTarget']; } } } @@ -276,52 +295,15 @@ class Hooks { $sharingEnabled = \OCP\Share::isEnabled(); // if a folder was shared, get a list if all (sub-)folders - if ( $params['itemType'] === 'folder' ) { - - $allFiles = $util->getAllFiles( $path ); - + if ($params['itemType'] === 'folder') { + $allFiles = $util->getAllFiles($path); } else { - - $allFiles = array( $path ); - + $allFiles = array($path); } - - // Set array for collecting paths which can't be shared - $failed = array(); - - foreach ( $allFiles as $path ) { - - $usersSharing = $util->getSharingUsersArray( $sharingEnabled, $path ); - // check if we share to a group - if($params['shareType'] === \OCP\Share::SHARE_TYPE_GROUP) { - $usersSharing[] = reset(\OC_Group::usersInGroup($params['shareWith'])); - // check if we share with link - } else if($params['shareType'] === \OCP\Share::SHARE_TYPE_LINK) { - $usersSharing[] = 'owncloud'; - } else { - // Because this is a pre_share hook, the user - // being shared to is not yet included; add them - $usersSharing[] = $params['shareWith']; - } - - - // Attempt to set shareKey - if ( ! $util->setSharedFileKeyfiles( $session, $usersSharing, $path ) ) { - - $failed[] = $path; - } - } - - // If some attempts to set keyfiles failed - if ( ! empty( $failed ) ) { - - // Set flag var 'run' to notify emitting - // script that hook execution failed - $params['run']->run = false; - // TODO: Make sure files_sharing provides user - // feedback on failed share - + foreach ($allFiles as $path) { + $usersSharing = $util->getSharingUsersArray($sharingEnabled, $path); + $util->setSharedFileKeyfiles( $session, $usersSharing, $path ); } } } diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php index b294a71ec1b..9b8d9ffc5b1 100755 --- a/apps/files_encryption/lib/helper.php +++ b/apps/files_encryption/lib/helper.php @@ -35,6 +35,7 @@ class Helper { public static function registerShareHooks() { \OCP\Util::connectHook( 'OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared' ); + \OCP\Util::connectHook( 'OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared' ); \OCP\Util::connectHook( 'OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare' ); \OCP\Util::connectHook( 'OCP\Share', 'post_unshareAll', 'OCA\Encryption\Hooks', 'postUnshareAll' ); } diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 3f8b8571252..36d05d7e0fe 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -164,45 +164,7 @@ class Proxy extends \OC_FileProxy { return true; } - - public function postFile_put_contents( $path, $length ) { - - $userId = \OCP\USER::getUser(); - $view = new \OC_FilesystemView( '/' ); - $util = new Util( $view, $userId ); - - // Check if recoveryAdmin is enabled for system and user - // TODO: Consider storing recoveryAdmin status for user in session - if ( - \OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' ) - && $util->recoveryEnabledForUser() - ) { - - // Get owner UID and filepath - list( $owner, $ownerPath ) = $util->getUidAndFilename( $path ); - - $recoveryAdminUid = \OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' ); - $usersSharing = \OCP\Share::getUsersSharingFile( $ownerPath, $owner,true, true, true ); - // Check if file is already shared to recoveryAdmin - if ( ! in_array( $recoveryAdminUid, $usersSharing ) ) { - - $relPath = $util->stripFilesPath( $path ); - - // Get file info from filecache - $fileInfo = \OC\Files\Filesystem::getFileInfo( $path ); - - // Register share to recoveryAdmin with share API - // FIXME: Some of these vars aren't set - // FIXME: What should the permission number be to grant all rights? -// \OCP\Share::shareItem( $itemType, $itemSource, 0, $recoveryAdminUid, 17 ); - - } - - } - - } - /** * @param string $path Path of file from which has been read * @param string $data Data that has been read from file -- cgit v1.2.3 From d1e2e47592515264bf06fc0d48645e430cddc394 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Mon, 13 May 2013 15:15:35 +0200 Subject: generate random key name for share key to avoid name conflicts --- apps/files_encryption/hooks/hooks.php | 4 +-- apps/files_encryption/lib/session.php | 45 ++++++++++++++---------- apps/files_encryption/lib/util.php | 9 +++-- lib/public/share.php | 65 ++++++++++++++++++----------------- 4 files changed, 69 insertions(+), 54 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index e3890ce1d15..676507b5236 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -365,9 +365,9 @@ class Hooks { $userIds = \OC_Group::usersInGroup($params['shareWith']); - } else { + } else if ( $params['shareType'] == \OCP\Share::SHARE_TYPE_LINK ){ - $userIds = array( $params['shareWith'] ); + $userIds = array( $util->getPublicShareKeyId() ); } diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index 22453131db7..920f0b6a9a3 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -45,10 +45,17 @@ class Session { $this->view->mkdir( 'owncloud_private_key' ); } + + $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); + + if ($publicShareKeyId === null) { + $publicShareKeyId = substr(md5(time()),0,8); + \OC_Appconfig::setValue('files_encryption', 'publicShareKeyId', $publicShareKeyId); + } if ( - ! $this->view->file_exists( "/public-keys/owncloud.public.key" ) - || ! $this->view->file_exists( "/owncloud_private_key/owncloud.private.key" ) + ! $this->view->file_exists( "/public-keys/".$publicShareKeyId.".public.key" ) + || ! $this->view->file_exists( "/owncloud_private_key/".$publicShareKeyId.".private.key" ) ) { //FIXME: Bug: for some reason file_exists is returning @@ -57,23 +64,23 @@ class Session { // our app.php is being executed 18 times per page load // , causing 18 new keypairs and huge performance hit. -// $keypair = Crypt::createKeypair(); -// -// \OC_FileProxy::$enabled = false; -// -// // Save public key -// -// if (!$view->is_dir('/public-keys')) { -// $view->mkdir('/public-keys'); -// } -// -// $this->view->file_put_contents( '/public-keys/owncloud.public.key', $keypair['publicKey'] ); -// -// // Encrypt private key empthy passphrase -// $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], '' ); -// -// // Save private key -// $this->view->file_put_contents( '/owncloud_private_key/owncloud.private.key', $encryptedPrivateKey ); + $keypair = Crypt::createKeypair(); + + \OC_FileProxy::$enabled = false; + + // Save public key + + if (!$view->is_dir('/public-keys')) { + $view->mkdir('/public-keys'); + } + + $this->view->file_put_contents( '/public-keys/'.$publicShareKeyId.'.public.key', $keypair['publicKey'] ); + + // Encrypt private key empthy passphrase + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], '' ); + + // Save private key + $this->view->file_put_contents( '/owncloud_private_key/'.$publicShareKeyId.'.private.key', $encryptedPrivateKey ); \OC_FileProxy::$enabled = true; diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index ae8c7ffd575..8162ae0a367 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -108,6 +108,7 @@ class Util { private $shareKeysPath; // Dir containing env keys for shared files private $publicKeyPath; // Path to user's public key private $privateKeyPath; // Path to user's private key + private $publicShareKeyId; public function __construct( \OC_FilesystemView $view, $userId, $client = false ) { @@ -123,7 +124,7 @@ class Util { $this->shareKeysPath = $this->encryptionDir . '/' . 'share-keys'; $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key $this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key - + $this->publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); } public function ready() { @@ -211,6 +212,10 @@ class Util { return true; } + + public function getPublicShareKeyId() { + return $this->publicShareKeyId; + } /** * @brief Check whether pwd recovery is enabled for a given user @@ -792,7 +797,7 @@ class Util { // Check that the user is encryption capable, or is the // public system user 'ownCloud' (for public shares) if ( - $user == 'owncloud' + $user == $this->publicShareKeyId or $util->ready() ) { diff --git a/lib/public/share.php b/lib/public/share.php index 418c0028ee5..b9cf05bbf7f 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -133,17 +133,17 @@ class Share { * @note $path needs to be relative to user data dir, e.g. 'file.txt' * not '/admin/data/file.txt' */ - public static function getUsersSharingFile( $path, $user, $includeOwner = false, $removeDuplicates = true ) { + public static function getUsersSharingFile($path, $user, $includeOwner = false, $removeDuplicates = true) { $path_parts = explode(DIRECTORY_SEPARATOR, trim($path, DIRECTORY_SEPARATOR)); $path = ''; $shares = array(); - $view = new \OC\Files\View('/'.$user.'/files/'); + $view = new \OC\Files\View('/' . $user . '/files/'); foreach ($path_parts as $p) { - $path .= '/'.$p; + $path .= '/' . $p; $meta = $view->getFileInfo(\OC_Filesystem::normalizePath($path)); $source = $meta['fileid']; - + // Fetch all shares of this file path from DB $query = \OC_DB::prepare( 'SELECT share_with @@ -152,14 +152,14 @@ class Share { WHERE item_source = ? AND share_type = ?' ); - - $result = $query->execute( array( $source, self::SHARE_TYPE_USER ) ); - if ( \OC_DB::isError( $result ) ) { - \OC_Log::write( 'OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR ); + $result = $query->execute(array($source, self::SHARE_TYPE_USER)); + + if (\OC_DB::isError($result)) { + \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR); } - while( $row = $result->fetchRow() ) { + while ($row = $result->fetchRow()) { $shares[] = $row['share_with']; } @@ -172,44 +172,47 @@ class Share { WHERE item_source = ? AND share_type = ?' ); - - $result = $query->execute( array( $source, self::SHARE_TYPE_GROUP ) ); - if ( \OC_DB::isError( $result ) ) { - \OC_Log::write( 'OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR ); + $result = $query->execute(array($source, self::SHARE_TYPE_GROUP)); + + if (\OC_DB::isError($result)) { + \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR); } - while( $row = $result->fetchRow() ) { + while ($row = $result->fetchRow()) { $usersInGroup = \OC_Group::usersInGroup($row['share_with']); $shares = array_merge($shares, $usersInGroup); } - - //check for public link shares - $query = \OC_DB::prepare( - 'SELECT share_with + + $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); + + if ($publicShareKeyId) { + //check for public link shares + $query = \OC_DB::prepare( + 'SELECT share_with FROM `*PREFIX*share` WHERE item_source = ? AND share_type = ?' - ); - - $result = $query->execute( array( $source, self::SHARE_TYPE_LINK ) ); - - if ( \OC_DB::isError( $result ) ) { - \OC_Log::write( 'OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR ); - } - - if ($result->fetchRow()) { - $shares[] = "owncloud"; + ); + + $result = $query->execute(array($source, self::SHARE_TYPE_LINK)); + + if (\OC_DB::isError($result)) { + \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR); + } + + if ($result->fetchRow()) { + $shares[] = $publicShareKeyId; + } } } // Include owner in list of users, if requested - if ( $includeOwner ) { + if ($includeOwner) { $shares[] = $user; } - - return array_unique($shares); + return array_unique($shares); } /** -- cgit v1.2.3 From 517efdf952526ce0f0a03107874baca18742c49b Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Mon, 13 May 2013 17:26:21 +0200 Subject: don't create a recovery user, only generate recovery key similar to the public link share key --- apps/files_encryption/ajax/adminrecovery.php | 122 ++++++++++----------- apps/files_encryption/js/settings-admin.js | 9 +- apps/files_encryption/lib/session.php | 10 +- apps/files_encryption/lib/util.php | 4 +- apps/files_encryption/templates/settings-admin.php | 17 +-- 5 files changed, 63 insertions(+), 99 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/ajax/adminrecovery.php b/apps/files_encryption/ajax/adminrecovery.php index c3c19943c0d..6a056dc7b3d 100644 --- a/apps/files_encryption/ajax/adminrecovery.php +++ b/apps/files_encryption/ajax/adminrecovery.php @@ -1,4 +1,5 @@ * This file is licensed under the Affero General Public License version 3 or later. @@ -6,87 +7,78 @@ * * @brief Script to handle admin settings for encrypted key recovery */ - use OCA\Encryption; \OCP\JSON::checkAdminUser(); -\OCP\JSON::checkAppEnabled( 'files_encryption' ); +\OCP\JSON::checkAppEnabled('files_encryption'); \OCP\JSON::callCheck(); -$return = $doSetup = false; +$return = false; // Enable recoveryAdmin -if ( - isset( $_POST['adminEnableRecovery'] ) - && 1 == $_POST['adminEnableRecovery'] -// && isset( $_POST['recoveryPassword'] ) -// && ! empty ( $_POST['recoveryPassword'] ) + +if ( + isset($_POST['adminEnableRecovery']) + && 1 == $_POST['adminEnableRecovery'] ) { - // TODO: Let the admin set this themselves - $recoveryAdminUid = 'recoveryAdmin'; - - // If desired recoveryAdmin UID is already in use - if ( ! \OC_User::userExists( $recoveryAdminUid ) ) { - - // Create new recoveryAdmin user - \OC_User::createUser( $recoveryAdminUid, $_POST['recoveryPassword'] ); - - // Make recovery user an administrator - \OC_Group::addToGroup ( $recoveryAdminUid, 'admin' ); - - $doSetup = true; - - } else { - - // Get list of admin users - $admins = OC_Group::usersInGroup( 'admin' ); - - // If the existing recoveryAdmin UID is an admin - if ( in_array( $recoveryAdminUid, $admins ) ) { - - // The desired recoveryAdmi UID pre-exists and can be used - $doSetup = true; - - // If the recoveryAdmin UID exists but doesn't have admin rights - } else { - - $return = false; - - } - + $view = new \OC\Files\View('/'); + + $recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); + + if ($recoveryKeyId === null) { + $recoveryKeyId = 'recovery_' . substr(md5(time()), 0, 8); + \OC_Appconfig::setValue('files_encryption', 'recoveryKeyId', $recoveryKeyId); } - - // Setup recoveryAdmin user for encryption - if ( $doSetup ) { - - $view = new \OC_FilesystemView( '/' ); - $util = new \OCA\Encryption\Util( $view, $recoveryAdminUid ); - - // Ensure recoveryAdmin is ready for encryption (has usable keypair etc.) - $util->setupServerSide( $_POST['recoveryPassword'] ); - - // Store the UID in the DB - OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminUid', $recoveryAdminUid ); - - $return = true; - + + if (!$view->is_dir('/owncloud_private_key')) { + $view->mkdir('/owncloud_private_key'); } - + + if ( + (!$view->file_exists("/public-keys/" . $recoveryKeyId . ".public.key") + || !$view->file_exists("/owncloud_private_key/" . $recoveryKeyId . ".private.key")) + && isset($_POST['recoveryPassword']) + && !empty($_POST['recoveryPassword']) + ) { + + $keypair = \OCA\Encryption\Crypt::createKeypair(); + + \OC_FileProxy::$enabled = false; + + // Save public key + + if (!$view->is_dir('/public-keys')) { + $view->mkdir('/public-keys'); + } + + $view->file_put_contents('/public-keys/' . $recoveryKeyId . '.public.key', $keypair['publicKey']); + + // Encrypt private key empthy passphrase + $encryptedPrivateKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($keypair['privateKey'], $_POST['recoveryPassword']); + + // Save private key + $view->file_put_contents('/owncloud_private_key/' . $recoveryKeyId . '.private.key', $encryptedPrivateKey); + + \OC_FileProxy::$enabled = true; + + } + // Set recoveryAdmin as enabled - OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminEnabled', 1 ); + OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); + + $return = true; // Disable recoveryAdmin -} elseif ( - isset( $_POST['adminEnableRecovery'] ) - && 0 == $_POST['adminEnableRecovery'] +} elseif ( + isset($_POST['adminEnableRecovery']) + && 0 == $_POST['adminEnableRecovery'] ) { - - // Set recoveryAdmin as enabled - OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminEnabled', 0 ); - - $return = true; + // Set recoveryAdmin as enabled + OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 0); + + $return = true; } // Return success or failure diff --git a/apps/files_encryption/js/settings-admin.js b/apps/files_encryption/js/settings-admin.js index 8e9c8c22306..9cdb7aca68a 100644 --- a/apps/files_encryption/js/settings-admin.js +++ b/apps/files_encryption/js/settings-admin.js @@ -7,13 +7,6 @@ $(document).ready(function(){ - // Trigger ajax on filetype blacklist change - $('#encryption_blacklist').multiSelect({ - oncheck:blackListChange, - onuncheck:blackListChange, - createText:'...' - }); - // Trigger ajax on recoveryAdmin status change $( 'input:radio[name="adminEnableRecovery"]' ).change( function() { @@ -24,7 +17,7 @@ $(document).ready(function(){ if ( '' == recoveryPassword ) { // FIXME: add proper OC notification - alert( 'You must set a recovery account password first' ); + alert( 'You must set a recovery account password first' ); } else { diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index 920f0b6a9a3..5444d0215ca 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -49,7 +49,7 @@ class Session { $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); if ($publicShareKeyId === null) { - $publicShareKeyId = substr(md5(time()),0,8); + $publicShareKeyId = 'pubShare_'.substr(md5(time()),0,8); \OC_Appconfig::setValue('files_encryption', 'publicShareKeyId', $publicShareKeyId); } @@ -57,13 +57,7 @@ class Session { ! $this->view->file_exists( "/public-keys/".$publicShareKeyId.".public.key" ) || ! $this->view->file_exists( "/owncloud_private_key/".$publicShareKeyId.".private.key" ) ) { - - //FIXME: Bug: for some reason file_exists is returning - // false in above if statement, and causing new keys - // to be generated on each page load. At last check - // our app.php is being executed 18 times per page load - // , causing 18 new keypairs and huge performance hit. - + $keypair = Crypt::createKeypair(); \OC_FileProxy::$enabled = false; diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 8162ae0a367..732f5fece85 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -958,10 +958,10 @@ class Util { if ( $recoveryEnabled ) { // Find recoveryAdmin user ID - $recoveryAdminUid = \OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminUid' ); + $recoveryKeyId = \OC_Appconfig::getValue( 'files_encryption', 'recoveryKeyId' ); // Add recoveryAdmin to list of users sharing - $userIds[] = $recoveryAdminUid; + $userIds[] = $recoveryKeyId; } diff --git a/apps/files_encryption/templates/settings-admin.php b/apps/files_encryption/templates/settings-admin.php index 863f1dfa9a5..be7beecf696 100644 --- a/apps/files_encryption/templates/settings-admin.php +++ b/apps/files_encryption/templates/settings-admin.php @@ -4,25 +4,10 @@

t( 'Encryption' )); ?>
- - t( "Exclude the following file types from encryption:" )); ?> -
- -

- - t( "Enable encryption passwords recovery account (allow sharing to recovery account):" )); ?> + t( "Enable encryption passwords recovery key (allow sharing to recovery key):" )); ?>
-
- t( "To perform a recovery log in using the 'recoveryAdmin' account and the specified password" )); ?>
-- cgit v1.2.3 From aa3eb6bb5be9979c31f402201241cf127573541e Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Mon, 13 May 2013 17:40:57 +0200 Subject: don't handle public share keys in lib/public/share.php but in apps/files_encryption/lib/util.php instead --- apps/files_encryption/lib/util.php | 9 ++++++++- lib/public/share.php | 27 ++++++++++++--------------- 2 files changed, 20 insertions(+), 16 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 732f5fece85..2a64680599f 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -109,6 +109,7 @@ class Util { private $publicKeyPath; // Path to user's public key private $privateKeyPath; // Path to user's private key private $publicShareKeyId; + private $recoveryKeyId; public function __construct( \OC_FilesystemView $view, $userId, $client = false ) { @@ -125,6 +126,7 @@ class Util { $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key $this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key $this->publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); + $this->recoveryKeyId = \OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); } public function ready() { @@ -798,6 +800,7 @@ class Util { // public system user 'ownCloud' (for public shares) if ( $user == $this->publicShareKeyId + or $user == $this->recoveryKeyId or $util->ready() ) { @@ -949,7 +952,11 @@ class Util { if ( $sharingEnabled ) { // Find out who, if anyone, is sharing the file - $userIds = \OCP\Share::getUsersSharingFile( $ownerPath, $owner,true, true, true ); + $result = \OCP\Share::getUsersSharingFile( $ownerPath, $owner,true, true, true ); + $userIds = $result['users']; + if ( $result['public'] ) { + $userIds[] = $this->publicShareKeyId; + } } diff --git a/lib/public/share.php b/lib/public/share.php index b9cf05bbf7f..10400e34c50 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -138,6 +138,7 @@ class Share { $path_parts = explode(DIRECTORY_SEPARATOR, trim($path, DIRECTORY_SEPARATOR)); $path = ''; $shares = array(); + $publicShare = false; $view = new \OC\Files\View('/' . $user . '/files/'); foreach ($path_parts as $p) { $path .= '/' . $p; @@ -184,27 +185,23 @@ class Share { $shares = array_merge($shares, $usersInGroup); } - $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); - - if ($publicShareKeyId) { - //check for public link shares - $query = \OC_DB::prepare( - 'SELECT share_with + //check for public link shares + $query = \OC_DB::prepare( + 'SELECT share_with FROM `*PREFIX*share` WHERE item_source = ? AND share_type = ?' - ); + ); - $result = $query->execute(array($source, self::SHARE_TYPE_LINK)); + $result = $query->execute(array($source, self::SHARE_TYPE_LINK)); - if (\OC_DB::isError($result)) { - \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR); - } + if (\OC_DB::isError($result)) { + \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result), \OC_Log::ERROR); + } - if ($result->fetchRow()) { - $shares[] = $publicShareKeyId; - } + if ($result->fetchRow()) { + $publicShare = true; } } // Include owner in list of users, if requested @@ -212,7 +209,7 @@ class Share { $shares[] = $user; } - return array_unique($shares); + return array("users" => array_unique($shares), "public" => $publicShare); } /** -- cgit v1.2.3 From 61ed347d26872bc62465be4df595da3391ea84bb Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Mon, 13 May 2013 21:24:59 +0200 Subject: added handling for public file access via files_sharing link --- apps/files_encryption/lib/keymanager.php | 2 +- apps/files_encryption/lib/session.php | 22 ++++- apps/files_encryption/lib/stream.php | 16 ++-- apps/files_encryption/lib/util.php | 144 ++++++++++++++++++++----------- 4 files changed, 120 insertions(+), 64 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 6c2df6f8406..8ee7820b169 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -455,7 +455,7 @@ class Keymanager { list($owner, $filename) = $util->getUidAndFilename($filePath); - $shareKeyPath = '/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey'; + $shareKeyPath = \OC\Files\Filesystem::normalizePath('/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey'); if ( $view->file_exists( $shareKeyPath ) ) { $result = $view->file_get_contents( $shareKeyPath ); diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index 5444d0215ca..f02315f95df 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -59,9 +59,11 @@ class Session { ) { $keypair = Crypt::createKeypair(); - - \OC_FileProxy::$enabled = false; - + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + // Save public key if (!$view->is_dir('/public-keys')) { @@ -76,9 +78,21 @@ class Session { // Save private key $this->view->file_put_contents( '/owncloud_private_key/'.$publicShareKeyId.'.private.key', $encryptedPrivateKey ); - \OC_FileProxy::$enabled = true; + \OC_FileProxy::$enabled = $proxyStatus; } + + if(\OCP\USER::getUser() === false) { + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $encryptedKey = $this->view->file_get_contents( '/owncloud_private_key/'.$publicShareKeyId.'.private.key' ); + $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, '' ); + $this->setPrivateKey($privateKey); + + \OC_FileProxy::$enabled = $proxyStatus; + } } /** diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 33b3255e2af..3149b460b62 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -72,20 +72,20 @@ class Stream { private $rootView; // a fsview object set to '/' public function stream_open( $path, $mode, $options, &$opened_path ) { - - $this->userId = \OCP\User::getUser(); - - if ( ! isset( $this->rootView ) ) { + if ( ! isset( $this->rootView ) ) { $this->rootView = new \OC_FilesystemView( '/' ); - } - // Strip identifier text from path, this gives us the path relative to data//files - $this->relPath = str_replace( 'crypt://', '', $path ); + $util = new Util( $this->rootView, \OCP\USER::getUser()); + + $this->userId = $util->getUserId(); + + // Strip identifier text from path, this gives us the path relative to data//files + $this->relPath = \OC\Files\Filesystem::normalizePath(str_replace( 'crypt://', '', $path )); // rawPath is relative to the data directory - $this->rawPath = $this->userId . '/files/' . $this->relPath; + $this->rawPath = $util->getUserFilesDir() . $this->relPath; if ( dirname( $this->rawPath ) == 'streams' diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 2a64680599f..213bbd1d210 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -110,23 +110,47 @@ class Util { private $privateKeyPath; // Path to user's private key private $publicShareKeyId; private $recoveryKeyId; + private $isPublic; public function __construct( \OC_FilesystemView $view, $userId, $client = false ) { - + $this->view = $view; $this->userId = $userId; $this->client = $client; - $this->userDir = '/' . $this->userId; - $this->fileFolderName = 'files'; - $this->userFilesDir = '/' . $this->userId . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable? - $this->publicKeyDir = '/' . 'public-keys'; - $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption'; - $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; - $this->shareKeysPath = $this->encryptionDir . '/' . 'share-keys'; - $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key - $this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key - $this->publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); - $this->recoveryKeyId = \OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); + $this->isPublic = false; + + $this->publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); + $this->recoveryKeyId = \OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); + + // if we are anonymous/public + if($this->userId === false) { + $this->userId = $this->publicShareKeyId; + + // only handle for files_sharing app + if($GLOBALS['app'] === 'files_sharing') { + $this->userDir = '/' . $GLOBALS['fileOwner']; + $this->fileFolderName = 'files'; + $this->userFilesDir = '/' . $GLOBALS['fileOwner'] . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable? + $this->publicKeyDir = '/' . 'public-keys'; + $this->encryptionDir = '/' . $GLOBALS['fileOwner'] . '/' . 'files_encryption'; + $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; + $this->shareKeysPath = $this->encryptionDir . '/' . 'share-keys'; + $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key + $this->privateKeyPath = '/owncloud_private_key/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key + $this->isPublic = true; + } + + } else { + $this->userDir = '/' . $this->userId; + $this->fileFolderName = 'files'; + $this->userFilesDir = '/' . $this->userId . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable? + $this->publicKeyDir = '/' . 'public-keys'; + $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption'; + $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; + $this->shareKeysPath = $this->encryptionDir . '/' . 'share-keys'; + $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key + $this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key + } } public function ready() { @@ -1069,46 +1093,54 @@ class Util { $view = new \OC\Files\View($this->userFilesDir); $fileOwnerUid = $view->getOwner( $path ); - - // Check that UID is valid - if ( ! \OCP\User::userExists( $fileOwnerUid ) ) { - - throw new \Exception( 'Could not find owner (UID = "' . var_export( $fileOwnerUid, 1 ) . '") of file "' . $path . '"' ); - - } - // NOTE: Bah, this dependency should be elsewhere - \OC\Files\Filesystem::initMountPoints( $fileOwnerUid ); - - // If the file owner is the currently logged in user - if ( $fileOwnerUid == $this->userId ) { - - // Assume the path supplied is correct - $filename = $path; - - } else { - - $info = $view->getFileInfo( $path ); - $ownerView = new \OC\Files\View( '/' . $fileOwnerUid . '/files' ); - - // Fetch real file path from DB - $filename = $ownerView->getPath( $info['fileid'] ); // TODO: Check that this returns a path without including the user data dir - - } - - // Make path relative for use by $view - $relpath = \OC\Files\Filesystem::normalizePath($fileOwnerUid . '/' . $this->fileFolderName . '/' . $filename); - - // Check that the filename we're using is working - if ( $this->view->file_exists( $relpath ) ) { - - return array ( $fileOwnerUid, $filename ); - - } else { - - return false; - - } + // handle public access + if($fileOwnerUid === false && $this->isPublic) { + $filename = $view->getPath( $GLOBALS['fileSource'] ); + $fileOwnerUid = $GLOBALS['fileOwner']; + + return array ( $fileOwnerUid, $filename ); + } else { + + // Check that UID is valid + if ( ! \OCP\User::userExists( $fileOwnerUid ) ) { + throw new \Exception( 'Could not find owner (UID = "' . var_export( $fileOwnerUid, 1 ) . '") of file "' . $path . '"' ); + } + + // NOTE: Bah, this dependency should be elsewhere + \OC\Files\Filesystem::initMountPoints( $fileOwnerUid ); + + // If the file owner is the currently logged in user + if ( $fileOwnerUid == $this->userId ) { + + // Assume the path supplied is correct + $filename = $path; + + } else { + + $info = $view->getFileInfo( $path ); + $ownerView = new \OC\Files\View( '/' . $fileOwnerUid . '/files' ); + + // Fetch real file path from DB + $filename = $ownerView->getPath( $info['fileid'] ); // TODO: Check that this returns a path without including the user data dir + + } + + // Make path relative for use by $view + $relpath = \OC\Files\Filesystem::normalizePath($fileOwnerUid . '/' . $this->fileFolderName . '/' . $filename); + + // Check that the filename we're using is working + if ( $this->view->file_exists( $relpath ) ) { + + return array ( $fileOwnerUid, $filename ); + + } else { + + return false; + + } + } + } @@ -1233,4 +1265,14 @@ class Util { } + public function getUserId() + { + return $this->userId; + } + + public function getUserFilesDir() + { + return $this->userFilesDir; + } + } -- cgit v1.2.3 From b2d021b2a5a603505c6c0e607472ee4e91962afe Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Mon, 13 May 2013 22:34:11 +0200 Subject: added post_createUser hook --- apps/files_encryption/hooks/hooks.php | 30 ++++++++++++++++++------------ apps/files_encryption/lib/helper.php | 20 ++++++++++++++++++++ 2 files changed, 38 insertions(+), 12 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 71a0fc9268b..ebaa9c51452 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -47,17 +47,11 @@ class Hooks { $view = new \OC_FilesystemView( '/' ); $util = new Util( $view, $params['uid'] ); - - // Check files_encryption infrastructure is ready for action - if ( ! $util->ready() ) { - - \OC_Log::write( 'Encryption library', 'User account "' . $params['uid'] . '" is not ready for encryption; configuration started', \OC_Log::DEBUG ); - - if(!$util->setupServerSide( $params['password'] )) { - return false; - } - } + // setup user, if user not ready force relogin + if(Helper::setupUser($util, $params['password']) === false) { + return false; + } \OC_FileProxy::$enabled = false; @@ -120,8 +114,20 @@ class Hooks { return true; } - - /** + + /** + * @brief setup encryption backend upon user created + * @note This method should never be called for users using client side encryption + */ + public static function postCreateUser( $params ) { + $view = new \OC_FilesystemView( '/' ); + + $util = new Util( $view, $params['uid'] ); + + Helper::setupUser($util, $params['password']); + } + + /** * @brief Change a user's encryption passphrase * @param array $params keys: uid, password */ diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php index 9b8d9ffc5b1..3a5b2f78ce8 100755 --- a/apps/files_encryption/lib/helper.php +++ b/apps/files_encryption/lib/helper.php @@ -48,6 +48,7 @@ class Helper { \OCP\Util::connectHook( 'OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login' ); \OCP\Util::connectHook( 'OC_User', 'pre_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase' ); + \OCP\Util::connectHook( 'OC_User', 'post_createUser', 'OCA\Encryption\Hooks', 'postCreateUser' ); } /** @@ -68,5 +69,24 @@ class Helper { \OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename'); } + /** + * @brief setup user for files_encryption + * + * @param Util $util + * @param string $password + * @return bool + */ + public static function setupUser($util, $password) { + // Check files_encryption infrastructure is ready for action + if ( ! $util->ready() ) { + \OC_Log::write( 'Encryption library', 'User account "' . $util->getUserId() . '" is not ready for encryption; configuration started', \OC_Log::DEBUG ); + + if(!$util->setupServerSide( $password )) { + return false; + } + } + + return true; + } } \ No newline at end of file -- cgit v1.2.3 From a4e9e2fc792f6300d93febd83a8b826c80bbcdc1 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Mon, 13 May 2013 22:49:27 +0200 Subject: added post_deleteUser hook for cleanup public key --- apps/files_encryption/hooks/hooks.php | 19 +++++++++++++++++++ apps/files_encryption/lib/helper.php | 1 + 2 files changed, 20 insertions(+) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index ebaa9c51452..134b038e7e4 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -127,6 +127,25 @@ class Hooks { Helper::setupUser($util, $params['password']); } + /** + * @brief cleanup encryption backend upon user deleted + * @note This method should never be called for users using client side encryption + */ + public static function postDeleteUser( $params ) { + $view = new \OC_FilesystemView( '/' ); + + // cleanup public key + $publicKey = '/public-keys/' . $params['uid'] . '.public.key'; + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $view->unlink($publicKey); + + \OC_FileProxy::$enabled = $proxyStatus; + } + /** * @brief Change a user's encryption passphrase * @param array $params keys: uid, password diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php index 3a5b2f78ce8..783cebeee5b 100755 --- a/apps/files_encryption/lib/helper.php +++ b/apps/files_encryption/lib/helper.php @@ -49,6 +49,7 @@ class Helper { \OCP\Util::connectHook( 'OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login' ); \OCP\Util::connectHook( 'OC_User', 'pre_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase' ); \OCP\Util::connectHook( 'OC_User', 'post_createUser', 'OCA\Encryption\Hooks', 'postCreateUser' ); + \OCP\Util::connectHook( 'OC_User', 'post_deleteUser', 'OCA\Encryption\Hooks', 'postDeleteUser' ); } /** -- cgit v1.2.3 From 81ae4cb5d07c1a7bf40a283bdb7e52c33dc243c6 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Tue, 14 May 2013 00:00:20 +0200 Subject: added test for public shared file via link --- apps/files_encryption/lib/util.php | 2 +- apps/files_encryption/tests/share.php | 88 +++++++++++++++++++++++++++++++---- 2 files changed, 79 insertions(+), 11 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 213bbd1d210..8f20481db6c 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -1096,7 +1096,7 @@ class Util { // handle public access if($fileOwnerUid === false && $this->isPublic) { - $filename = $view->getPath( $GLOBALS['fileSource'] ); + $filename = $this->fileIdToPath( $GLOBALS['fileSource'] ); $fileOwnerUid = $GLOBALS['fileOwner']; return array ( $fileOwnerUid, $filename ); diff --git a/apps/files_encryption/tests/share.php b/apps/files_encryption/tests/share.php index ca7209e1afd..850985c9f9f 100755 --- a/apps/files_encryption/tests/share.php +++ b/apps/files_encryption/tests/share.php @@ -136,10 +136,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase $this->loginHelper('user1'); // get file contents - $retreivedCryptedFile = $this->view->file_get_contents('/user1/files/Shared/' . $this->filename); + $retrievedCryptedFile = $this->view->file_get_contents('/user1/files/Shared/' . $this->filename); // check if data is the same as we previously written - $this->assertEquals($this->dataShort, $retreivedCryptedFile); + $this->assertEquals($this->dataShort, $retrievedCryptedFile); // cleanup if ($withTeardown) { @@ -184,10 +184,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase $this->loginHelper('user2'); // get file contents - $retreivedCryptedFile = $this->view->file_get_contents('/user2/files/Shared/' . $this->filename); + $retrievedCryptedFile = $this->view->file_get_contents('/user2/files/Shared/' . $this->filename); // check if data is the same as previously written - $this->assertEquals($this->dataShort, $retreivedCryptedFile); + $this->assertEquals($this->dataShort, $retrievedCryptedFile); // cleanup if ($withTeardown) { @@ -260,10 +260,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase $this->loginHelper('user1'); // get file contents - $retreivedCryptedFile = $this->view->file_get_contents('/user1/files/Shared' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); + $retrievedCryptedFile = $this->view->file_get_contents('/user1/files/Shared' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); // check if data is the same - $this->assertEquals($this->dataShort, $retreivedCryptedFile); + $this->assertEquals($this->dataShort, $retrievedCryptedFile); // cleanup if ($withTeardown) { @@ -320,10 +320,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase $this->loginHelper('user2'); // get file contents - $retreivedCryptedFile = $this->view->file_get_contents('/user2/files/Shared' . $this->subfolder . $this->subsubfolder . '/' . $this->filename); + $retrievedCryptedFile = $this->view->file_get_contents('/user2/files/Shared' . $this->subfolder . $this->subsubfolder . '/' . $this->filename); // check if data is the same - $this->assertEquals($this->dataShort, $retreivedCryptedFile); + $this->assertEquals($this->dataShort, $retrievedCryptedFile); // get the file info $fileInfo = $this->view->getFileInfo('/user2/files/Shared' . $this->subfolder . $this->subsubfolder . '/' . $this->filename); @@ -344,10 +344,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase $this->loginHelper('user3'); // get file contents - $retreivedCryptedFile = $this->view->file_get_contents('/user3/files/Shared/' . $this->filename); + $retrievedCryptedFile = $this->view->file_get_contents('/user3/files/Shared/' . $this->filename); // check if data is the same - $this->assertEquals($this->dataShort, $retreivedCryptedFile); + $this->assertEquals($this->dataShort, $retrievedCryptedFile); // cleanup if ($withTeardown) { @@ -387,6 +387,74 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase } } + function testPublicShareFile() + { + // login as admin + $this->loginHelper('admin'); + + // save file with content + $cryptedFile = file_put_contents('crypt://' . $this->filename, $this->dataShort); + + // test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); + + // disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + // get the file info from previous created file + $fileInfo = $this->view->getFileInfo('/admin/files/' . $this->filename); + + // check if we have a valid file info + $this->assertTrue(is_array($fileInfo)); + + // check if the unencrypted file size is stored + $this->assertGreaterThan(0, $fileInfo['unencrypted_size']); + + // re-enable the file proxy + \OC_FileProxy::$enabled = $proxyStatus; + + // share the file + \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null, false); + + // login as admin + $this->loginHelper('admin'); + + $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); + + // check if share key for public exists + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $publicShareKeyId . '.shareKey')); + + // some hacking to simulate public link + $GLOBALS['app'] = 'files_sharing'; + $GLOBALS['fileOwner'] = 'admin'; + $GLOBALS['fileSource'] = $fileInfo['fileid']; + \OC_User::setUserId(''); + + // get file contents + $retrievedCryptedFile = file_get_contents('crypt://' . $this->filename); + + // check if data is the same as we previously written + $this->assertEquals($this->dataShort, $retrievedCryptedFile); + + // tear down + + // login as admin + $this->loginHelper('admin'); + + // unshare the file + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null); + + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $publicShareKeyId . '.shareKey')); + + // cleanup + $this->view->unlink('/admin/files/' . $this->filename); + + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey')); + } + function loginHelper($user, $create = false) { if ($create) { -- cgit v1.2.3 From 517105660d334b21b2e4b83d4c00704d9a5d275d Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Tue, 14 May 2013 20:11:07 +0200 Subject: fix for public link share --- apps/files_encryption/lib/util.php | 2 +- apps/files_encryption/tests/share.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 8f20481db6c..0233804160d 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -1096,7 +1096,7 @@ class Util { // handle public access if($fileOwnerUid === false && $this->isPublic) { - $filename = $this->fileIdToPath( $GLOBALS['fileSource'] ); + $filename = $path; $fileOwnerUid = $GLOBALS['fileOwner']; return array ( $fileOwnerUid, $filename ); diff --git a/apps/files_encryption/tests/share.php b/apps/files_encryption/tests/share.php index 850985c9f9f..b8433821d3b 100755 --- a/apps/files_encryption/tests/share.php +++ b/apps/files_encryption/tests/share.php @@ -428,7 +428,6 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase // some hacking to simulate public link $GLOBALS['app'] = 'files_sharing'; $GLOBALS['fileOwner'] = 'admin'; - $GLOBALS['fileSource'] = $fileInfo['fileid']; \OC_User::setUserId(''); // get file contents -- cgit v1.2.3 From 84c56a5d56eddfb9e5d0356575902253eb266da1 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Tue, 14 May 2013 21:29:24 +0200 Subject: fix for zero size files --- apps/files_encryption/lib/stream.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 3149b460b62..db7d2ad6173 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -477,9 +477,9 @@ class Stream { if ( $this->meta['mode']!='r' - and $this->meta['mode']!='rb' + and $this->meta['mode']!='rb' + and $this->size > 0 ) { - // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; -- cgit v1.2.3 From 0a7aa6e8cdbf96c3a54ea0a897eb5dfb8cd37c01 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Tue, 14 May 2013 22:32:39 +0200 Subject: fix for Allowed memory size of xx bytes exhausted while reading big files --- apps/files_encryption/lib/util.php | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 0233804160d..19c9cd72a19 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -480,13 +480,20 @@ class Util { */ public function isEncryptedPath( $path ) { - // Disable encryption proxy so data retreived is in its + // Disable encryption proxy so data retrieved is in its // original form + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - - $data = $this->view->file_get_contents( $path ); - - \OC_FileProxy::$enabled = true; + + // we only need 24 byte from the last chunk + $data = ''; + $handle = $this->view->fopen( $path, 'r' ); + if(!fseek($handle, -24, SEEK_END)) { + $data = fgets($handle); + } + + // re-enable proxy + \OC_FileProxy::$enabled = $proxyStatus; return Crypt::isCatfileContent( $data ); -- cgit v1.2.3 From ddedf201062c99f4dfce64b2dde8c912d8305491 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Wed, 15 May 2013 02:34:36 +0200 Subject: prevent of infinite loop with FileProxy --- apps/files_encryption/lib/stream.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index db7d2ad6173..ab967835082 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -509,15 +509,15 @@ class Stream { // Save the sharekeys Keymanager::setShareKeys( $view, $this->relPath, $this->encKeyfiles['keys'] ); - // Re-enable proxy - our work is done - \OC_FileProxy::$enabled = $proxyStatus; - // get file info $fileInfo = $view->getFileInfo($this->rawPath); if(!is_array($fileInfo)) { $fileInfo = array(); } + // Re-enable proxy - our work is done + \OC_FileProxy::$enabled = $proxyStatus; + // set encryption data $fileInfo['encrypted'] = true; $fileInfo['size'] = $this->size; -- cgit v1.2.3 From 499fe6ca8e28d559ad8aba7724766c111c65290a Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Wed, 15 May 2013 02:36:23 +0200 Subject: disabled FileProxy in Keymanager::getPrivateKey --- apps/files_encryption/lib/keymanager.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 8ee7820b169..74462a0d1ed 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -38,9 +38,14 @@ class Keymanager { public static function getPrivateKey( \OC_FilesystemView $view, $user ) { $path = '/' . $user . '/' . 'files_encryption' . '/' . $user.'.private.key'; - + + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + $key = $view->file_get_contents( $path ); - + + \OC_FileProxy::$enabled = $proxyStatus; + return $key; } -- cgit v1.2.3 From 5b160edebba2a10de83b09a8010a811321dd6370 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Wed, 15 May 2013 14:02:13 +0200 Subject: check if the user knows the correct recovery password before changing the recovery key settings --- .gitignore | 1 + apps/files_encryption/ajax/adminrecovery.php | 63 +++++++++++++++++++++------- apps/files_encryption/hooks/hooks.php | 3 +- apps/files_encryption/js/settings-admin.js | 6 ++- apps/files_encryption/lib/crypt.php | 10 +++-- 5 files changed, 63 insertions(+), 20 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/.gitignore b/.gitignore index b57dd3d2058..bc0c1d53a55 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,4 @@ data-autotest /tests/coverage* /tests/autoconfig* /tests/autotest* +/l10n/.tx/ \ No newline at end of file diff --git a/apps/files_encryption/ajax/adminrecovery.php b/apps/files_encryption/ajax/adminrecovery.php index 6a056dc7b3d..520c7156c89 100644 --- a/apps/files_encryption/ajax/adminrecovery.php +++ b/apps/files_encryption/ajax/adminrecovery.php @@ -15,16 +15,37 @@ use OCA\Encryption; $return = false; +function checkPassword($view, $password, $recoveryKeyId) { + $pathKey = '/owncloud_private_key/'. $recoveryKeyId . ".private.key"; + $pathControlData = '/control-file/controlfile.enc'; + + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $recoveryKey = $view->file_get_contents( $pathKey ); + + $decryptedRecoveryKey = \OCA\Encryption\Crypt::symmetricDecryptFileContent($recoveryKey, $password); + + $controlData = $view->file_get_contents($pathControlData); + $decryptedControlData = \OCA\Encryption\Crypt::keyDecrypt($controlData, $decryptedRecoveryKey); + + \OC_FileProxy::$enabled = $proxyStatus; + + if ($decryptedControlData === 'ownCloud') { + return true; + } else { + return false; + } +} + + // Enable recoveryAdmin -if ( - isset($_POST['adminEnableRecovery']) - && 1 == $_POST['adminEnableRecovery'] -) { +$recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); - $view = new \OC\Files\View('/'); +if (isset($_POST['adminEnableRecovery']) && $_POST['adminEnableRecovery'] == 1){ - $recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); + $view = new \OC\Files\View('/'); if ($recoveryKeyId === null) { $recoveryKeyId = 'recovery_' . substr(md5(time()), 0, 8); @@ -38,8 +59,6 @@ if ( if ( (!$view->file_exists("/public-keys/" . $recoveryKeyId . ".public.key") || !$view->file_exists("/owncloud_private_key/" . $recoveryKeyId . ".private.key")) - && isset($_POST['recoveryPassword']) - && !empty($_POST['recoveryPassword']) ) { $keypair = \OCA\Encryption\Crypt::createKeypair(); @@ -60,25 +79,39 @@ if ( // Save private key $view->file_put_contents('/owncloud_private_key/' . $recoveryKeyId . '.private.key', $encryptedPrivateKey); + // create control file which let us check later on if the entered password was correct. + $encryptedControlData = \OCA\Encryption\Crypt::keyEncrypt("ownCloud", $keypair['publicKey']); + if (!$view->is_dir('/control-file')) { + $view->mkdir('/control-file'); + } + $view->file_put_contents('/control-file/controlfile.enc', $encryptedControlData); + \OC_FileProxy::$enabled = true; - } + // Set recoveryAdmin as enabled + OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); - // Set recoveryAdmin as enabled - OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); + $return = true; - $return = true; + } else { // get recovery key and check the password + $return = checkPassword($view, $_POST['recoveryPassword'] ,$recoveryKeyId); + if ($return) { + OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); + } + } // Disable recoveryAdmin } elseif ( isset($_POST['adminEnableRecovery']) && 0 == $_POST['adminEnableRecovery'] ) { + $view = new \OC\Files\View('/'); + $return = checkPassword($view, $_POST['recoveryPassword'], $recoveryKeyId); - // Set recoveryAdmin as enabled + if ($return) { + // Set recoveryAdmin as disabled OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 0); - - $return = true; + } } // Return success or failure diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 31175d1c346..ed254fd8d8b 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -59,7 +59,8 @@ class Hooks { \OC_FileProxy::$enabled = true; - $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $params['password'] ); + //$privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $params['password'] ); + $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, "helloworld" ); $session = new Session( $view ); diff --git a/apps/files_encryption/js/settings-admin.js b/apps/files_encryption/js/settings-admin.js index 2fffcf77b32..fa353901c3f 100644 --- a/apps/files_encryption/js/settings-admin.js +++ b/apps/files_encryption/js/settings-admin.js @@ -25,12 +25,16 @@ $(document).ready(function(){ function() { var recoveryStatus = $( this ).val(); + var oldStatus = (1+parseInt(recoveryStatus)) % 2; var recoveryPassword = $( '#recoveryPassword' ).val(); $.post( OC.filePath( 'files_encryption', 'ajax', 'adminrecovery.php' ) , { adminEnableRecovery: recoveryStatus, recoveryPassword: recoveryPassword } , function( data ) { - alert( data ); + if (data.status == "error") { + alert("Couldn't switch recovery key mode, please check your recovery key password!"); + $('input:radio[name="adminEnableRecovery"][value="'+oldStatus.toString()+'"]').attr("checked", "true"); + } } ); } diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index f92930c2cbd..5267ba81f57 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -217,7 +217,7 @@ class Crypt { * @returns decrypted file */ public static function decrypt( $encryptedContent, $iv, $passphrase ) { - + if ( $plainContent = openssl_decrypt( $encryptedContent, 'AES-128-CFB', $passphrase, false, $iv ) ) { return $plainContent; @@ -463,9 +463,13 @@ class Crypt { */ public static function keyDecrypt( $encryptedContent, $privatekey ) { - openssl_private_decrypt( $encryptedContent, $plainContent, $privatekey ); + $result = @openssl_private_decrypt( $encryptedContent, $plainContent, $privatekey ); - return $plainContent; + if ( $result ) { + return $plainContent; + } + + return $result; } -- cgit v1.2.3 From 64d94c540aeaba67e2f779b2551c72a80334aa3e Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Wed, 15 May 2013 16:12:20 +0200 Subject: enable admin to change the recovery password --- apps/files_encryption/ajax/adminrecovery.php | 31 ++---------- apps/files_encryption/js/settings-admin.js | 59 ++++++++++++++++++++++ apps/files_encryption/lib/util.php | 28 ++++++++++ apps/files_encryption/settings-personal.php | 1 + apps/files_encryption/templates/settings-admin.php | 27 +++++++++- 5 files changed, 118 insertions(+), 28 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/ajax/adminrecovery.php b/apps/files_encryption/ajax/adminrecovery.php index 520c7156c89..0ab449709c3 100644 --- a/apps/files_encryption/ajax/adminrecovery.php +++ b/apps/files_encryption/ajax/adminrecovery.php @@ -15,30 +15,6 @@ use OCA\Encryption; $return = false; -function checkPassword($view, $password, $recoveryKeyId) { - $pathKey = '/owncloud_private_key/'. $recoveryKeyId . ".private.key"; - $pathControlData = '/control-file/controlfile.enc'; - - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - - $recoveryKey = $view->file_get_contents( $pathKey ); - - $decryptedRecoveryKey = \OCA\Encryption\Crypt::symmetricDecryptFileContent($recoveryKey, $password); - - $controlData = $view->file_get_contents($pathControlData); - $decryptedControlData = \OCA\Encryption\Crypt::keyDecrypt($controlData, $decryptedRecoveryKey); - - \OC_FileProxy::$enabled = $proxyStatus; - - if ($decryptedControlData === 'ownCloud') { - return true; - } else { - return false; - } -} - - // Enable recoveryAdmin $recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); @@ -94,7 +70,8 @@ if (isset($_POST['adminEnableRecovery']) && $_POST['adminEnableRecovery'] == 1){ $return = true; } else { // get recovery key and check the password - $return = checkPassword($view, $_POST['recoveryPassword'] ,$recoveryKeyId); + $util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \OCP\User::getUser()); + $return = $util->checkRecoveryPassword($_POST['recoveryPassword']); if ($return) { OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); } @@ -105,8 +82,8 @@ if (isset($_POST['adminEnableRecovery']) && $_POST['adminEnableRecovery'] == 1){ isset($_POST['adminEnableRecovery']) && 0 == $_POST['adminEnableRecovery'] ) { - $view = new \OC\Files\View('/'); - $return = checkPassword($view, $_POST['recoveryPassword'], $recoveryKeyId); + $util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \OCP\User::getUser()); + $return = $util->checkRecoveryPassword($_POST['recoveryPassword']); if ($return) { // Set recoveryAdmin as disabled diff --git a/apps/files_encryption/js/settings-admin.js b/apps/files_encryption/js/settings-admin.js index fa353901c3f..9bc6ab6433c 100644 --- a/apps/files_encryption/js/settings-admin.js +++ b/apps/files_encryption/js/settings-admin.js @@ -5,6 +5,27 @@ * See the COPYING-README file. */ +OC.msg={ + startSaving:function(selector){ + $(selector) + .html( t('settings', 'Saving...') ) + .removeClass('success') + .removeClass('error') + .stop(true, true) + .show(); + }, + finishedSaving:function(selector, data){ + if( data.status === "success" ){ + $(selector).html( data.data.message ) + .addClass('success') + .stop(true, true) + .delay(3000) + .fadeOut(900); + }else{ + $(selector).html( data.data.message ).addClass('error'); + } + } +}; $(document).ready(function(){ // Trigger ajax on recoveryAdmin status change @@ -34,10 +55,48 @@ $(document).ready(function(){ if (data.status == "error") { alert("Couldn't switch recovery key mode, please check your recovery key password!"); $('input:radio[name="adminEnableRecovery"][value="'+oldStatus.toString()+'"]').attr("checked", "true"); + } else { + if (recoveryStatus == "0") { + $('button:button[name="submitChangeRecoveryKey"]').attr("disabled", "true"); + $('input:password[name="changeRecoveryPassword"]').attr("disabled", "true"); + $('input:password[name="changeRecoveryPassword"]').val(""); + } else { + $('input:password[name="changeRecoveryPassword"]').removeAttr("disabled"); + } } } ); } ); + + // change password + + $('input:password[name="changeRecoveryPassword"]').keyup(function(event) { + var oldRecoveryPassword = $('input:password[id="oldRecoveryPassword"]').val(); + var newRecoveryPassword = $('input:password[id="newRecoveryPassword"]').val(); + if (newRecoveryPassword != '' && oldRecoveryPassword != '' ) { + $('button:button[name="submitChangeRecoveryKey"]').removeAttr("disabled"); + } else { + $('button:button[name="submitChangeRecoveryKey"]').attr("disabled", "true"); + } + }); + + + $('button:button[name="submitChangeRecoveryKey"]').click(function() { + var oldRecoveryPassword = $('input:password[id="oldRecoveryPassword"]').val(); + var newRecoveryPassword = $('input:password[id="newRecoveryPassword"]').val(); + OC.msg.startSaving('#encryption .msg'); + $.post( + OC.filePath( 'files_encryption', 'ajax', 'changeRecoveryPassword.php' ) + , { oldPassword: oldRecoveryPassword, newPassword: newRecoveryPassword } + , function( data ) { + if (data.status == "error") { + OC.msg.finishedSaving('#encryption .msg', data); + } else { + OC.msg.finishedSaving('#encryption .msg', data); + } + } + ); + }); }) \ No newline at end of file diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 19c9cd72a19..6cb4ccb8085 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -1282,4 +1282,32 @@ class Util { return $this->userFilesDir; } + public function checkRecoveryPassword($password) { + + $pathKey = '/owncloud_private_key/' . $this->recoveryKeyId . ".private.key"; + $pathControlData = '/control-file/controlfile.enc'; + + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $recoveryKey = $this->view->file_get_contents($pathKey); + + $decryptedRecoveryKey = Crypt::symmetricDecryptFileContent($recoveryKey, $password); + + $controlData = $this->view->file_get_contents($pathControlData); + $decryptedControlData = Crypt::keyDecrypt($controlData, $decryptedRecoveryKey); + + \OC_FileProxy::$enabled = $proxyStatus; + + if ($decryptedControlData === 'ownCloud') { + return true; + } + + return false; + } + + public function getRecoveryKeyId() { + return $this->recoveryKeyId; + } + } diff --git a/apps/files_encryption/settings-personal.php b/apps/files_encryption/settings-personal.php index 46efb61b029..90edc0eae24 100644 --- a/apps/files_encryption/settings-personal.php +++ b/apps/files_encryption/settings-personal.php @@ -32,6 +32,7 @@ $recoveryAdminEnabled = OC_Appconfig::getValue( 'files_encryption', 'recoveryAdm $recoveryEnabledForUser = $util->recoveryEnabledForUser(); \OCP\Util::addscript( 'files_encryption', 'settings-personal' ); +\OCP\Util::addScript( 'settings', 'personal' ); $tmpl->assign( 'recoveryEnabled', $recoveryAdminEnabled ); $tmpl->assign( 'recoveryEnabledForUser', $recoveryEnabledForUser ); diff --git a/apps/files_encryption/templates/settings-admin.php b/apps/files_encryption/templates/settings-admin.php index 95c1b66681c..18fea1845f4 100644 --- a/apps/files_encryption/templates/settings-admin.php +++ b/apps/files_encryption/templates/settings-admin.php @@ -10,7 +10,7 @@

- +
/> t( "Disabled" )); ?>

+

+

+ t( "Change encryption passwords recovery key:" )); ?> +

+ /> + +
+ /> + +
+ + +

-- cgit v1.2.3 From 57c0a7ed693fec6ef487b71a514202b24dd70df2 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Wed, 15 May 2013 17:56:45 +0200 Subject: add recovery key to all files if the user enabled the feature and removes them again on disable --- apps/files_encryption/ajax/userrecovery.php | 6 ++++ apps/files_encryption/lib/util.php | 34 ++++++++++++++++++++++ .../templates/settings-personal.php | 3 +- 3 files changed, 42 insertions(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/ajax/userrecovery.php b/apps/files_encryption/ajax/userrecovery.php index 85a799011d7..1f42b376e42 100644 --- a/apps/files_encryption/ajax/userrecovery.php +++ b/apps/files_encryption/ajax/userrecovery.php @@ -24,6 +24,12 @@ if ( // Save recovery preference to DB $return = $util->setRecoveryForUser( $_POST['userEnableRecovery'] ); + + if ($_POST['userEnableRecovery'] == "1") { + $util->addRecoveryKeys(); + } else { + $util->removeRecoveryKeys(); + } } else { diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 6cb4ccb8085..6eee1ada8a8 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -1310,4 +1310,38 @@ class Util { return $this->recoveryKeyId; } + /** + * @brief add recovery key to all encrypted files + */ + public function addRecoveryKeys($path = '/') { + $dirContent = $this->view->getDirectoryContent($this->keyfilesPath.$path); + foreach ($dirContent as $item) { + $filePath = substr($item['path'], 25); + if ($item['type'] == 'dir') { + $this->addRecoveryKey($filePath.'/'); + } else { + $session = new Session(new \OC_FilesystemView('/')); + $sharingEnabled = \OCP\Share::isEnabled(); + $file = substr($filePath, 0, -4); + $usersSharing = $this->getSharingUsersArray($sharingEnabled, $file); + $this->setSharedFileKeyfiles( $session, $usersSharing, $file ); + } + } + } + + /** + * @brief remove recovery key to all encrypted files + */ + public function removeRecoveryKeys($path = '/') { + $dirContent = $this->view->getDirectoryContent($this->keyfilesPath.$path); + foreach ($dirContent as $item) { + $filePath = substr($item['path'], 25); + if ($item['type'] == 'dir') { + $this->removeRecoveryKeys($filePath.'/'); + } else { + $file = substr($filePath, 0, -4); + $this->view->unlink($this->shareKeysPath.'/'.$file.'.'.$this->recoveryKeyId.'.shareKey'); + } + } + } } diff --git a/apps/files_encryption/templates/settings-personal.php b/apps/files_encryption/templates/settings-personal.php index 00f567ecb26..33989416d33 100644 --- a/apps/files_encryption/templates/settings-personal.php +++ b/apps/files_encryption/templates/settings-personal.php @@ -48,6 +48,7 @@


+ -- cgit v1.2.3 From ec2e193a4413fa2d02ab6d127b1697294330e2bf Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Wed, 15 May 2013 21:01:03 +0200 Subject: removed unused code --- apps/files_encryption/hooks/hooks.php | 38 ----------------------------------- apps/files_encryption/lib/helper.php | 3 +-- 2 files changed, 1 insertion(+), 40 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 16e9f9177d7..8f03087e568 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -169,33 +169,6 @@ class Hooks { } } - - /** - * @brief update the encryption key of the file uploaded by the client - */ - public static function updateKeyfile( $params ) { - - if ( Crypt::mode() == 'client' ) { - - if ( isset( $params['properties']['key'] ) ) { - - $view = new \OC_FilesystemView( '/' ); - $userId = \OCP\User::getUser(); - - Keymanager::setFileKey( $view, $params['path'], $userId, $params['properties']['key'] ); - - } else { - - \OC_Log::write( - 'Encryption library', "Client side encryption is enabled but the client doesn't provide a encryption key for the file!" - , \OC_Log::ERROR - ); - - } - - } - - } /* * @brief check if files can be encrypted to every user. @@ -426,17 +399,6 @@ class Hooks { } /** - * @brief - */ - public static function postUnshareAll( $params ) { - - // NOTE: It appears that this is never called for files, so - // we may not need to implement it - - } - - - /** * @brief after a file is renamed, rename its keyfile and share-keys also fix the file size and fix also the sharing * @param array with oldpath and newpath * diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php index 783cebeee5b..6d5aae4e8b5 100755 --- a/apps/files_encryption/lib/helper.php +++ b/apps/files_encryption/lib/helper.php @@ -37,7 +37,6 @@ class Helper { \OCP\Util::connectHook( 'OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared' ); \OCP\Util::connectHook( 'OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared' ); \OCP\Util::connectHook( 'OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare' ); - \OCP\Util::connectHook( 'OCP\Share', 'post_unshareAll', 'OCA\Encryption\Hooks', 'postUnshareAll' ); } /** @@ -58,7 +57,7 @@ class Helper { */ public static function registerWebdavHooks() { - \OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfileFromClient' ); + } /** -- cgit v1.2.3 From c0c4fe5fd3cd575656ed30b4464bb6bc3c6d4f40 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Thu, 16 May 2013 00:31:17 +0200 Subject: fix if file is not yet created --- apps/files_encryption/lib/proxy.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 36d05d7e0fe..1d60770b4d7 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -131,8 +131,13 @@ class Proxy extends \OC_FileProxy { $encData = Crypt::symmetricEncryptFileContent( $data, $plainKey ); $sharingEnabled = \OCP\Share::isEnabled(); - - $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $filePath, $userId ); + + // if file exists try to get sharing users + if($view->file_exists($path)) { + $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $filePath, $userId ); + } else { + $uniqueUserIds[] = $userId; + } // Fetch public keys for all users who will share the file $publicKeys = Keymanager::getPublicKeys( $view, $uniqueUserIds ); -- cgit v1.2.3 From c651950a17cf1381a832e172191e4f4cc172569b Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Thu, 16 May 2013 00:34:45 +0200 Subject: fix for re-share and removed check if file exists because we are sometime into a pre_put_contents hook --- apps/files_encryption/hooks/hooks.php | 3 ++- apps/files_encryption/lib/util.php | 33 ++++++++++++++++++++------------- 2 files changed, 22 insertions(+), 14 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 8f03087e568..f843c7027d5 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -231,8 +231,9 @@ class Hooks { $util = new Util($view, $userId); $path = $util->fileIdToPath($params['itemSource']); + $share = $util->getParentFromShare($params['id']); //if parent is set, then this is a re-share action - if ($params['parent']) { + if ($share['parent'] != null) { // get the parent from current share $parent = $util->getShareParent($params['parent']); diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 6eee1ada8a8..91d86cc8558 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -1133,19 +1133,7 @@ class Util { } - // Make path relative for use by $view - $relpath = \OC\Files\Filesystem::normalizePath($fileOwnerUid . '/' . $this->fileFolderName . '/' . $filename); - - // Check that the filename we're using is working - if ( $this->view->file_exists( $relpath ) ) { - - return array ( $fileOwnerUid, $filename ); - - } else { - - return false; - - } + return array ( $fileOwnerUid, $filename ); } @@ -1230,6 +1218,25 @@ class Util { } + /** + * @brief get shares parent. + * @param int $id of the current share + * @return array of the parent + */ + public static function getParentFromShare( $id ) { + + $query = \OC_DB::prepare( 'SELECT `parent`' + .' FROM `*PREFIX*share`' + .' WHERE `id` = ?' ); + + $result = $query->execute( array( $id ) ); + + $row = $result->fetchRow(); + + return $row; + + } + /** * @brief get owner of the shared files. * @param int $Id of a share -- cgit v1.2.3 From 9d1e60325c6f478484ff8f70ff3cd13d9d7d4913 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Thu, 16 May 2013 14:53:04 +0200 Subject: allow admin to recover users files in case of password lost --- apps/files_encryption/hooks/hooks.php | 73 +++++++++++++++++++------- apps/files_encryption/js/settings-admin.js | 2 +- apps/files_encryption/lib/helper.php | 2 +- apps/files_encryption/lib/util.php | 84 +++++++++++++++++++++++++++++- lib/user.php | 7 +-- settings/ajax/changepassword.php | 5 +- settings/css/settings.css | 2 + settings/js/users.js | 4 +- settings/templates/personal.php | 2 +- settings/templates/users.php | 5 ++ settings/users.php | 3 ++ 11 files changed, 159 insertions(+), 30 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index f843c7027d5..0af0845d7c1 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -142,32 +142,67 @@ class Hooks { * @brief Change a user's encryption passphrase * @param array $params keys: uid, password */ - public static function setPassphrase( $params ) { - + public static function setPassphrase($params) { + // Only attempt to change passphrase if server-side encryption // is in use (client-side encryption does not have access to // the necessary keys) - if ( Crypt::mode() == 'server' ) { + if (Crypt::mode() == 'server') { - $view = new \OC_FilesystemView( '/' ); + if ($params['uid'] == \OCP\User::getUser()) { - $session = new Session($view); - - // Get existing decrypted private key - $privateKey = $session->getPrivateKey(); - - // Encrypt private key with new user pwd as passphrase - $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $privateKey, $params['password'] ); - - // Save private key - Keymanager::setPrivateKey( $encryptedPrivateKey ); - - // NOTE: Session does not need to be updated as the - // private key has not changed, only the passphrase - // used to decrypt it has changed + $view = new \OC_FilesystemView('/'); + + $session = new Session($view); + + // Get existing decrypted private key + $privateKey = $session->getPrivateKey(); + + // Encrypt private key with new user pwd as passphrase + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($privateKey, $params['password']); + + // Save private key + Keymanager::setPrivateKey($encryptedPrivateKey); + + // NOTE: Session does not need to be updated as the + // private key has not changed, only the passphrase + // used to decrypt it has changed + + } else { // admin changed the password for a different user, create new keys and reencrypt file keys + + $user = $params['uid']; + $recoveryPassword = $params['recoveryPassword']; + $newUserPassword = $params['password']; + + $view = new \OC_FilesystemView('/'); + + // make sure that the users home is mounted + \OC\Files\Filesystem::initMountPoints($user); + + $keypair = Crypt::createKeypair(); + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + // Save public key + $view->file_put_contents( '/public-keys/'.$user.'.public.key', $keypair['publicKey'] ); + + // Encrypt private key empthy passphrase + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], $newUserPassword ); + + // Save private key + $view->file_put_contents( '/'.$user.'/files_encryption/'.$user.'.private.key', $encryptedPrivateKey ); + + if ( $recoveryPassword ) { // if recovery key is set we can re-encrypt the key files + $util = new Util($view, $user); + $util->recoverUsersFiles($recoveryPassword); + } + + \OC_FileProxy::$enabled = $proxyStatus; + } } - } /* diff --git a/apps/files_encryption/js/settings-admin.js b/apps/files_encryption/js/settings-admin.js index 9bc6ab6433c..dbae42b011c 100644 --- a/apps/files_encryption/js/settings-admin.js +++ b/apps/files_encryption/js/settings-admin.js @@ -69,7 +69,7 @@ $(document).ready(function(){ } ); - // change password + // change recovery password $('input:password[name="changeRecoveryPassword"]').keyup(function(event) { var oldRecoveryPassword = $('input:password[id="oldRecoveryPassword"]').val(); diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php index 6d5aae4e8b5..86d860465e6 100755 --- a/apps/files_encryption/lib/helper.php +++ b/apps/files_encryption/lib/helper.php @@ -46,7 +46,7 @@ class Helper { public static function registerUserHooks() { \OCP\Util::connectHook( 'OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login' ); - \OCP\Util::connectHook( 'OC_User', 'pre_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase' ); + \OCP\Util::connectHook( 'OC_User', 'post_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase' ); \OCP\Util::connectHook( 'OC_User', 'post_createUser', 'OCA\Encryption\Hooks', 'postCreateUser' ); \OCP\Util::connectHook( 'OC_User', 'post_deleteUser', 'OCA\Encryption\Hooks', 'postDeleteUser' ); } diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 91d86cc8558..fab807b0141 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -929,7 +929,7 @@ class Util { // Get the current users's private key for decrypting existing keyfile $privateKey = $session->getPrivateKey(); - + $fileOwner = \OC\Files\Filesystem::getOwner( $filePath ); // Decrypt keyfile @@ -1336,7 +1336,7 @@ class Util { } } - /** + /** * @brief remove recovery key to all encrypted files */ public function removeRecoveryKeys($path = '/') { @@ -1351,4 +1351,84 @@ class Util { } } } + + /** + * @brief decrypt given file with recovery key and encrypt it again to the owner and his new key + * @param type $file + * @param type $privateKey recovery key to decrypt the file + */ + private function recoverFile($file, $privateKey) { + + $sharingEnabled = \OCP\Share::isEnabled(); + + // Find out who, if anyone, is sharing the file + if ($sharingEnabled) { + $result = \OCP\Share::getUsersSharingFile($file, $this->userId, true, true, true); + $userIds = $result['users']; + $userIds[] = $this->recoveryKeyId; + if ($result['public']) { + $userIds[] = $this->publicShareKeyId; + } + } else { + $userIds = array($this->userId, $this->recoveryKeyId); + } + $filteredUids = $this->filterShareReadyUsers($userIds); + + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + //decrypt file key + $encKeyfile = $this->view->file_get_contents($this->keyfilesPath.$file.".key"); + $shareKey = $this->view->file_get_contents($this->shareKeysPath.$file.".".$this->recoveryKeyId.".shareKey"); + $plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + // encrypt file key again to all users, this time with the new public key for the recovered use + $userPubKeys = Keymanager::getPublicKeys($this->view, $filteredUids['ready']); + $multiEncKey = Crypt::multiKeyEncrypt($plainKeyfile, $userPubKeys); + + // write new keys to filesystem TDOO! + $this->view->file_put_contents($this->keyfilesPath.$file.'.key', $multiEncKey['data']); + foreach ($multiEncKey['keys'] as $userId => $shareKey) { + $shareKeyPath = $this->shareKeysPath.$file.'.'.$userId.'.shareKey'; + $this->view->file_put_contents($shareKeyPath, $shareKey); + } + + // Return proxy to original status + \OC_FileProxy::$enabled = $proxyStatus; + } + + /** + * @brief collect all files and recover them one by one + * @param type $path to look for files keys + * @param type $privateKey private recovery key which is used to decrypt the files + */ + private function recoverAllFiles($path, $privateKey) { + $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path); + foreach ($dirContent as $item) { + $filePath = substr($item['path'], 25); + if ($item['type'] == 'dir') { + $this->addRecoveryKey($filePath . '/', $privateKey); + } else { + $file = substr($filePath, 0, -4); + $this->recoverFile($file, $privateKey); + } + } + } + + /** + * @brief recover users files in case of password lost + * @param type $recoveryPassword + */ + public function recoverUsersFiles($recoveryPassword) { + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $encryptedKey = $this->view->file_get_contents( '/owncloud_private_key/'.$this->recoveryKeyId.'.private.key' ); + $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $recoveryPassword ); + + \OC_FileProxy::$enabled = $proxyStatus; + + $this->recoverAllFiles('/', $privateKey); + } } diff --git a/lib/user.php b/lib/user.php index 226b716188d..833e8866592 100644 --- a/lib/user.php +++ b/lib/user.php @@ -393,13 +393,14 @@ class OC_User { * @brief Set password * @param $uid The username * @param $password The new password + * @param $recoveryPassword for the encryption app to reset encryption keys * @returns true/false * * Change the password of a user */ - public static function setPassword( $uid, $password ) { + public static function setPassword( $uid, $password, $recoveryPassword = null ) { $run = true; - OC_Hook::emit( "OC_User", "pre_setPassword", array( "run" => &$run, "uid" => $uid, "password" => $password )); + OC_Hook::emit( "OC_User", "pre_setPassword", array( "run" => &$run, "uid" => $uid, "password" => $password, "recoveryPassword" => $recoveryPassword )); if( $run ) { $success = false; @@ -412,7 +413,7 @@ class OC_User { } // invalidate all login cookies OC_Preferences::deleteApp($uid, 'login_token'); - OC_Hook::emit( "OC_User", "post_setPassword", array( "uid" => $uid, "password" => $password )); + OC_Hook::emit( "OC_User", "post_setPassword", array( "uid" => $uid, "password" => $password, "recoveryPassword" => $recoveryPassword )); return $success; } else{ diff --git a/settings/ajax/changepassword.php b/settings/ajax/changepassword.php index 4f16bff63d5..fe63f27a6e2 100644 --- a/settings/ajax/changepassword.php +++ b/settings/ajax/changepassword.php @@ -8,8 +8,9 @@ OC_JSON::checkLoggedIn(); OC_APP::loadApps(); $username = isset($_POST["username"]) ? $_POST["username"] : OC_User::getUser(); -$password = isset($_POST["newpassword"]) ? $_POST["newpassword"] : null; +$password = isset($_POST["password"]) ? $_POST["password"] : null; $oldPassword=isset($_POST["oldpassword"])?$_POST["oldpassword"]:''; +$recoveryPassword=isset($_POST["recoveryPassword"])?$_POST["recoveryPassword"]:null; $userstatus = null; if(OC_User::isAdminUser(OC_User::getUser())) { @@ -28,7 +29,7 @@ if(is_null($userstatus)) { } // Return Success story -if(!is_null($password) && OC_User::setPassword( $username, $password )) { +if(!is_null($password) && OC_User::setPassword( $username, $password, $recoveryPassword )) { OC_JSON::success(array("data" => array( "username" => $username ))); } else{ diff --git a/settings/css/settings.css b/settings/css/settings.css index 46a0bbe7c32..950e8929012 100644 --- a/settings/css/settings.css +++ b/settings/css/settings.css @@ -45,6 +45,8 @@ table:not(.nostyle) { width:100%; } #rightcontent { padding-left: 1em; } div.quota { float:right; display:block; position:absolute; right:25em; top:-1px; } div.quota-select-wrapper { position: relative; } +div.recoveryPassword { left:50em; display:block; position:absolute; top:-1px; } +input#recoveryPassword {width:15em;} select.quota { position:absolute; left:0; top:0; width:10em; } select.quota-user { position:relative; left:0; top:0; width:10em; } div.quota>span { position:absolute; right:0; white-space:nowrap; top:.7em; color:#888; text-shadow:0 1px 0 #fff; } diff --git a/settings/js/users.js b/settings/js/users.js index 690c9ad0464..9bd7f31f0b2 100644 --- a/settings/js/users.js +++ b/settings/js/users.js @@ -351,9 +351,11 @@ $(document).ready(function () { input.keypress(function (event) { if (event.keyCode == 13) { if ($(this).val().length > 0) { + var recoveryPasswordVal = $('input:password[id="recoveryPassword"]').val(); + console.log("RECOVERY PASSWD: " + recoveryPasswordVal); $.post( OC.filePath('settings', 'ajax', 'changepassword.php'), - {username: uid, password: $(this).val()}, + {username: uid, password: $(this).val(), recoveryPassword: recoveryPasswordVal}, function (result) { } ); diff --git a/settings/templates/personal.php b/settings/templates/personal.php index cfb45e99c4d..da812e8ed9a 100644 --- a/settings/templates/personal.php +++ b/settings/templates/personal.php @@ -38,7 +38,7 @@ if($_['passwordChangeSupported']) {
t('Your password was changed');?>
t('Unable to change your password');?>
- diff --git a/settings/templates/users.php b/settings/templates/users.php index e86dd46efbe..a6df85983dd 100644 --- a/settings/templates/users.php +++ b/settings/templates/users.php @@ -29,6 +29,11 @@ $_['subadmingroups'] = array_flip($items); + +
+ +
+
t('Default Storage'));?> diff --git a/settings/users.php b/settings/users.php index 94e6d0a9a10..e5c8a7aaa8d 100644 --- a/settings/users.php +++ b/settings/users.php @@ -20,6 +20,8 @@ $users = array(); $groups = array(); $isadmin = OC_User::isAdminUser(OC_User::getUser()); +$recoveryAdminEnabled = OC_App::isEnabled('files_encryption') && + OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' ); if($isadmin) { $accessiblegroups = OC_Group::getGroups(); @@ -77,4 +79,5 @@ $tmpl->assign( 'numofgroups', count($accessiblegroups)); $tmpl->assign( 'quota_preset', $quotaPreset); $tmpl->assign( 'default_quota', $defaultQuota); $tmpl->assign( 'defaultQuotaIsUserDefined', $defaultQuotaIsUserDefined); +$tmpl->assign( 'recoveryAdminEnabled', $recoveryAdminEnabled); $tmpl->printPage(); -- cgit v1.2.3 From d40d6aa3581fdacfc10532cfcfc2dc20835817d1 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Thu, 16 May 2013 22:39:09 +0200 Subject: fix typo in addRecoveryKeys --- apps/files_encryption/lib/util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index fab807b0141..038ec78bbdb 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -1325,7 +1325,7 @@ class Util { foreach ($dirContent as $item) { $filePath = substr($item['path'], 25); if ($item['type'] == 'dir') { - $this->addRecoveryKey($filePath.'/'); + $this->addRecoveryKeys($filePath.'/'); } else { $session = new Session(new \OC_FilesystemView('/')); $sharingEnabled = \OCP\Share::isEnabled(); -- cgit v1.2.3 From 3793e4d2d6729f01a83c56d8f123226134f8c626 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Thu, 16 May 2013 22:57:55 +0200 Subject: fix for recover files in subfolder --- apps/files_encryption/lib/util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 038ec78bbdb..7acb3ce2dc3 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -1406,7 +1406,7 @@ class Util { foreach ($dirContent as $item) { $filePath = substr($item['path'], 25); if ($item['type'] == 'dir') { - $this->addRecoveryKey($filePath . '/', $privateKey); + $this->recoverAllFiles($filePath . '/', $privateKey); } else { $file = substr($filePath, 0, -4); $this->recoverFile($file, $privateKey); -- cgit v1.2.3 From 42b4963dd010830d1a99666052ee2bfc7295249a Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Fri, 17 May 2013 00:58:41 +0200 Subject: moved enable and disable recovery to Helper class for unit tests --- apps/files_encryption/ajax/adminrecovery.php | 64 +------------------ apps/files_encryption/lib/helper.php | 92 ++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 62 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/ajax/adminrecovery.php b/apps/files_encryption/ajax/adminrecovery.php index 0ab449709c3..dc13bc57c11 100644 --- a/apps/files_encryption/ajax/adminrecovery.php +++ b/apps/files_encryption/ajax/adminrecovery.php @@ -21,74 +21,14 @@ $recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); if (isset($_POST['adminEnableRecovery']) && $_POST['adminEnableRecovery'] == 1){ - $view = new \OC\Files\View('/'); - - if ($recoveryKeyId === null) { - $recoveryKeyId = 'recovery_' . substr(md5(time()), 0, 8); - \OC_Appconfig::setValue('files_encryption', 'recoveryKeyId', $recoveryKeyId); - } - - if (!$view->is_dir('/owncloud_private_key')) { - $view->mkdir('/owncloud_private_key'); - } - - if ( - (!$view->file_exists("/public-keys/" . $recoveryKeyId . ".public.key") - || !$view->file_exists("/owncloud_private_key/" . $recoveryKeyId . ".private.key")) - ) { - - $keypair = \OCA\Encryption\Crypt::createKeypair(); - - \OC_FileProxy::$enabled = false; - - // Save public key - - if (!$view->is_dir('/public-keys')) { - $view->mkdir('/public-keys'); - } - - $view->file_put_contents('/public-keys/' . $recoveryKeyId . '.public.key', $keypair['publicKey']); - - // Encrypt private key empthy passphrase - $encryptedPrivateKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($keypair['privateKey'], $_POST['recoveryPassword']); - - // Save private key - $view->file_put_contents('/owncloud_private_key/' . $recoveryKeyId . '.private.key', $encryptedPrivateKey); - - // create control file which let us check later on if the entered password was correct. - $encryptedControlData = \OCA\Encryption\Crypt::keyEncrypt("ownCloud", $keypair['publicKey']); - if (!$view->is_dir('/control-file')) { - $view->mkdir('/control-file'); - } - $view->file_put_contents('/control-file/controlfile.enc', $encryptedControlData); - - \OC_FileProxy::$enabled = true; - - // Set recoveryAdmin as enabled - OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); - - $return = true; - - } else { // get recovery key and check the password - $util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \OCP\User::getUser()); - $return = $util->checkRecoveryPassword($_POST['recoveryPassword']); - if ($return) { - OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); - } - } + $return = \Helper::adminEnableRecovery($recoveryKeyId, $_POST['recoveryPassword']); // Disable recoveryAdmin } elseif ( isset($_POST['adminEnableRecovery']) && 0 == $_POST['adminEnableRecovery'] ) { - $util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \OCP\User::getUser()); - $return = $util->checkRecoveryPassword($_POST['recoveryPassword']); - - if ($return) { - // Set recoveryAdmin as disabled - OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 0); - } + $return = \Helper::adminDisableRecovery($_POST['recoveryPassword']); } // Return success or failure diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php index 86d860465e6..a04c65e251f 100755 --- a/apps/files_encryption/lib/helper.php +++ b/apps/files_encryption/lib/helper.php @@ -26,6 +26,10 @@ namespace OCA\Encryption; /** * @brief Class to manage registration of hooks an various helper methods */ +/** + * Class Helper + * @package OCA\Encryption + */ class Helper { /** @@ -89,4 +93,92 @@ class Helper { return true; } + + /** + * @brief enable recovery + * + * @param $recoveryKeyId + * @param $recoveryPassword + * @internal param \OCA\Encryption\Util $util + * @internal param string $password + * @return bool + */ + public static function adminEnableRecovery($recoveryKeyId, $recoveryPassword) { + $view = new \OC\Files\View('/'); + + if ($recoveryKeyId === null) { + $recoveryKeyId = 'recovery_' . substr(md5(time()), 0, 8); + \OC_Appconfig::setValue('files_encryption', 'recoveryKeyId', $recoveryKeyId); + } + + if (!$view->is_dir('/owncloud_private_key')) { + $view->mkdir('/owncloud_private_key'); + } + + if ( + (!$view->file_exists("/public-keys/" . $recoveryKeyId . ".public.key") + || !$view->file_exists("/owncloud_private_key/" . $recoveryKeyId . ".private.key")) + ) { + + $keypair = \OCA\Encryption\Crypt::createKeypair(); + + \OC_FileProxy::$enabled = false; + + // Save public key + + if (!$view->is_dir('/public-keys')) { + $view->mkdir('/public-keys'); + } + + $view->file_put_contents('/public-keys/' . $recoveryKeyId . '.public.key', $keypair['publicKey']); + + // Encrypt private key empthy passphrase + $encryptedPrivateKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($keypair['privateKey'], $recoveryPassword); + + // Save private key + $view->file_put_contents('/owncloud_private_key/' . $recoveryKeyId . '.private.key', $encryptedPrivateKey); + + // create control file which let us check later on if the entered password was correct. + $encryptedControlData = \OCA\Encryption\Crypt::keyEncrypt("ownCloud", $keypair['publicKey']); + if (!$view->is_dir('/control-file')) { + $view->mkdir('/control-file'); + } + $view->file_put_contents('/control-file/controlfile.enc', $encryptedControlData); + + \OC_FileProxy::$enabled = true; + + // Set recoveryAdmin as enabled + \OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); + + $return = true; + + } else { // get recovery key and check the password + $util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \OCP\User::getUser()); + $return = $util->checkRecoveryPassword($_POST['recoveryPassword']); + if ($return) { + \OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); + } + } + + return $return; + } + + + /** + * @brief disable recovery + * + * @param $recoveryPassword + * @return bool + */ + public static function adminDisableRecovery($recoveryPassword) { + $util = new Util(new \OC_FilesystemView('/'), \OCP\User::getUser()); + $return = $util->checkRecoveryPassword($recoveryPassword); + + if ($return) { + // Set recoveryAdmin as disabled + \OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 0); + } + + return $return; + } } \ No newline at end of file -- cgit v1.2.3 From ca6a77d39b738aeead0bbbfdfdf2a06382431f6f Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Fri, 17 May 2013 11:15:36 +0200 Subject: upgrade from old encryption to the new one needs to generate share keys too --- apps/files_encryption/hooks/hooks.php | 5 +++-- apps/files_encryption/lib/crypt.php | 32 +++++++++++++++++++++++++------- apps/files_encryption/lib/util.php | 15 +++++++++------ 3 files changed, 37 insertions(+), 15 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 0af0845d7c1..a91bd9183f5 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -97,9 +97,10 @@ class Hooks { ); } - + + // DISABLED JUST FOR TESTING PURPOSE, ACTIVATE AGAIN! // Register successful migration in DB - $util->setMigrationStatus( 1 ); + //$util->setMigrationStatus( 1 ); } diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 5267ba81f57..74f8a1ffa3b 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -479,15 +479,33 @@ class Crypt { * keys: data, key * @note this method is a wrapper for combining other crypt class methods */ - public static function keyEncryptKeyfile( $plainContent, $publicKey ) { - + public static function keyEncryptKeyfile( $plainContent, $publicKey, $path ) { + + $user = \OCP\User::getUser(); + $view = new \OC_FilesystemView('/'); + $util = new Util($view, $user); + // Encrypt plain data, generate keyfile & encrypted file $cryptedData = self::symmetricEncryptFileContentKeyfile( $plainContent ); // Encrypt keyfile - $cryptedKey = self::keyEncrypt( $cryptedData['key'], $publicKey ); - - return array( 'data' => $cryptedData['encrypted'], 'key' => $cryptedKey ); + + $sharingEnabled = \OCP\Share::isEnabled(); + + // if file exists try to get sharing users + if($view->file_exists($path)) { + $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $path, $user ); + } else { + $uniqueUserIds[] = $user; + } + + // Fetch public keys for all users who will share the file + $publicKeys = Keymanager::getPublicKeys( $view, $uniqueUserIds ); + + // Encrypt plain keyfile to multiple sharefiles + $multiEncrypted = Crypt::multiKeyEncrypt( $cryptedData['key'], $publicKeys ); + + return array( 'data' => $cryptedData['encrypted'], 'filekey' => $multiEncrypted['data'], 'sharekeys' => $multiEncrypted['keys'] ); } @@ -725,11 +743,11 @@ class Crypt { } - public static function legacyKeyRecryptKeyfile( $legacyEncryptedContent, $legacyPassphrase, $publicKey, $newPassphrase ) { + public static function legacyKeyRecryptKeyfile( $legacyEncryptedContent, $legacyPassphrase, $publicKey, $newPassphrase, $path ) { $decrypted = self::legacyDecrypt( $legacyEncryptedContent, $legacyPassphrase ); - $recrypted = self::keyEncryptKeyfile( $decrypted, $publicKey ); + $recrypted = self::keyEncryptKeyfile( $decrypted, $publicKey, $path ); return $recrypted; diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index fab807b0141..5a6583465e0 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -714,16 +714,19 @@ class Util { // Fetch data from file $legacyData = $this->view->file_get_contents( $legacyFile['path'] ); - + // Recrypt data, generate catfile - $recrypted = Crypt::legacyKeyRecryptKeyfile( $legacyData, $legacyPassphrase, $publicKey, $newPassphrase ); + $recrypted = Crypt::legacyKeyRecryptKeyfile( $legacyData, $legacyPassphrase, $publicKey, $newPassphrase, $legacyFile['path'] ); - $relPath = $legacyFile['path']; - $rawPath = $this->userId . '/files/' . $plainFile['path']; + $rawPath = $legacyFile['path']; + $relPath = $this->stripUserFilesPath($rawPath); // Save keyfile - Keymanager::setFileKey( $this->view, $relPath, $this->userId, $recrypted['key'] ); - + Keymanager::setFileKey( $this->view, $relPath, $this->userId, $recrypted['filekey'] ); + + // Save sharekeys to user folders + Keymanager::setShareKeys( $this->view, $relPath, $recrypted['sharekeys'] ); + // Overwrite the existing file with the encrypted one $this->view->file_put_contents( $rawPath, $recrypted['data'] ); -- cgit v1.2.3 From 93771f735b2347eb851941a414220af7b6ccd066 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Fri, 17 May 2013 14:13:05 +0200 Subject: gremove unused code --- apps/files_encryption/lib/crypt.php | 68 +++----------------- apps/files_encryption/lib/util.php | 113 ++++++++++++++++++---------------- apps/files_encryption/tests/crypt.php | 41 ------------ 3 files changed, 68 insertions(+), 154 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 74f8a1ffa3b..708d1719d73 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -472,61 +472,7 @@ class Crypt { return $result; } - - /** - * @brief Encrypts content symmetrically and generates keyfile asymmetrically - * @returns array containing catfile and new keyfile. - * keys: data, key - * @note this method is a wrapper for combining other crypt class methods - */ - public static function keyEncryptKeyfile( $plainContent, $publicKey, $path ) { - - $user = \OCP\User::getUser(); - $view = new \OC_FilesystemView('/'); - $util = new Util($view, $user); - - // Encrypt plain data, generate keyfile & encrypted file - $cryptedData = self::symmetricEncryptFileContentKeyfile( $plainContent ); - - // Encrypt keyfile - - $sharingEnabled = \OCP\Share::isEnabled(); - - // if file exists try to get sharing users - if($view->file_exists($path)) { - $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $path, $user ); - } else { - $uniqueUserIds[] = $user; - } - - // Fetch public keys for all users who will share the file - $publicKeys = Keymanager::getPublicKeys( $view, $uniqueUserIds ); - - // Encrypt plain keyfile to multiple sharefiles - $multiEncrypted = Crypt::multiKeyEncrypt( $cryptedData['key'], $publicKeys ); - - return array( 'data' => $cryptedData['encrypted'], 'filekey' => $multiEncrypted['data'], 'sharekeys' => $multiEncrypted['keys'] ); - - } - - /** - * @brief Takes catfile, keyfile, and private key, and - * performs decryption - * @returns decrypted content - * @note this method is a wrapper for combining other crypt class methods - */ - public static function keyDecryptKeyfile( $catfile, $keyfile, $privateKey ) { - - // Decrypt the keyfile with the user's private key - $decryptedKeyfile = self::keyDecrypt( $keyfile, $privateKey ); - // Decrypt the catfile symmetrically using the decrypted keyfile - $decryptedData = self::symmetricDecryptFileContent( $catfile, $decryptedKeyfile ); - - return $decryptedData; - - } - /** * @brief Symmetrically encrypt a file by combining encrypted component data blocks */ @@ -743,13 +689,17 @@ class Crypt { } - public static function legacyKeyRecryptKeyfile( $legacyEncryptedContent, $legacyPassphrase, $publicKey, $newPassphrase, $path ) { + public static function legacyKeyRecryptKeyfile( $legacyEncryptedContent, $legacyPassphrase, $publicKeys, $newPassphrase, $path ) { $decrypted = self::legacyDecrypt( $legacyEncryptedContent, $legacyPassphrase ); - - $recrypted = self::keyEncryptKeyfile( $decrypted, $publicKey, $path ); - - return $recrypted; + + // Encrypt plain data, generate keyfile & encrypted file + $cryptedData = self::symmetricEncryptFileContentKeyfile( $decrypted ); + + // Encrypt plain keyfile to multiple sharefiles + $multiEncrypted = Crypt::multiKeyEncrypt( $cryptedData['key'], $publicKeys ); + + return array( 'data' => $cryptedData['encrypted'], 'filekey' => $multiEncrypted['data'], 'sharekeys' => $multiEncrypted['keys'] ); } diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index b312b502c14..a2dee1ca71f 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -656,103 +656,108 @@ class Util { * @param string $dirPath the directory whose files will be encrypted * @note Encryption is recursive */ - public function encryptAll( $publicKey, $dirPath, $legacyPassphrase = null, $newPassphrase = null ) { - - if ( $found = $this->findEncFiles( $dirPath ) ) { - + public function encryptAll($publicKey, $dirPath, $legacyPassphrase = null, $newPassphrase = null) { + + if ($found = $this->findEncFiles($dirPath)) { + // Disable proxy to prevent file being encrypted twice \OC_FileProxy::$enabled = false; - + // Encrypt unencrypted files - foreach ( $found['plain'] as $plainFile ) { - + foreach ($found['plain'] as $plainFile) { + //relative to data//file $relPath = $plainFile['path']; - + //relative to /data - $rawPath = $this->userId . '/files/' . $plainFile['path']; - + $rawPath = $this->userId . '/files/' . $plainFile['path']; + // Open plain file handle for binary reading - $plainHandle1 = $this->view->fopen( $rawPath, 'rb' ); - + $plainHandle1 = $this->view->fopen($rawPath, 'rb'); + // 2nd handle for moving plain file - view->rename() doesn't work, this is a workaround - $plainHandle2 = $this->view->fopen( $rawPath . '.plaintmp', 'wb' ); - + $plainHandle2 = $this->view->fopen($rawPath . '.plaintmp', 'wb'); + // Move plain file to a temporary location - stream_copy_to_stream( $plainHandle1, $plainHandle2 ); - + stream_copy_to_stream($plainHandle1, $plainHandle2); + // Close access to original file // $this->view->fclose( $plainHandle1 ); // not implemented in view{} - // Delete original plain file so we can rename enc file later - $this->view->unlink( $rawPath ); - + $this->view->unlink($rawPath); + // Open enc file handle for binary writing, with same filename as original plain file - $encHandle = fopen( 'crypt://' . $relPath, 'wb' ); - + $encHandle = fopen('crypt://' . $relPath, 'wb'); + // Save data from plain stream to new encrypted file via enc stream // NOTE: Stream{} will be invoked for handling // the encryption, and should handle all keys // and their generation etc. automatically - $size = stream_copy_to_stream( $plainHandle2, $encHandle ); - + $size = stream_copy_to_stream($plainHandle2, $encHandle); + // Delete temporary plain copy of file - $this->view->unlink( $rawPath . '.plaintmp' ); - + $this->view->unlink($rawPath . '.plaintmp'); + // Add the file to the cache - \OC\Files\Filesystem::putFileInfo( $plainFile['path'], array( 'encrypted'=>true, 'size' => $size ), '' ); - + \OC\Files\Filesystem::putFileInfo($plainFile['path'], array('encrypted' => true, 'size' => $size), ''); } - + // Encrypt legacy encrypted files - if ( - ! empty( $legacyPassphrase ) - && ! empty( $newPassphrase ) + if ( + !empty($legacyPassphrase) + && !empty($newPassphrase) ) { - - foreach ( $found['legacy'] as $legacyFile ) { - + + foreach ($found['legacy'] as $legacyFile) { + // Fetch data from file - $legacyData = $this->view->file_get_contents( $legacyFile['path'] ); + $legacyData = $this->view->file_get_contents($legacyFile['path']); + + $sharingEnabled = \OCP\Share::isEnabled(); + + // if file exists try to get sharing users + if ($view->file_exists($legacyFile['path'])) { + $uniqueUserIds = $util->getSharingUsersArray($sharingEnabled, $legacyFile['path'], $this->userId); + } else { + $uniqueUserIds[] = $this->userId; + } + + // Fetch public keys for all users who will share the file + $publicKeys = Keymanager::getPublicKeys($this->view, $uniqueUserIds); // Recrypt data, generate catfile - $recrypted = Crypt::legacyKeyRecryptKeyfile( $legacyData, $legacyPassphrase, $publicKey, $newPassphrase, $legacyFile['path'] ); - + $recrypted = Crypt::legacyKeyRecryptKeyfile($legacyData, $legacyPassphrase, $publicKey, $newPassphrase, $legacyFile['path'], $publicKeys); + $rawPath = $legacyFile['path']; $relPath = $this->stripUserFilesPath($rawPath); - + // Save keyfile - Keymanager::setFileKey( $this->view, $relPath, $this->userId, $recrypted['filekey'] ); + Keymanager::setFileKey($this->view, $relPath, $this->userId, $recrypted['filekey']); // Save sharekeys to user folders - Keymanager::setShareKeys( $this->view, $relPath, $recrypted['sharekeys'] ); + Keymanager::setShareKeys($this->view, $relPath, $recrypted['sharekeys']); // Overwrite the existing file with the encrypted one - $this->view->file_put_contents( $rawPath, $recrypted['data'] ); - - $size = strlen( $recrypted['data'] ); - + $this->view->file_put_contents($rawPath, $recrypted['data']); + + $size = strlen($recrypted['data']); + // Add the file to the cache - \OC\Files\Filesystem::putFileInfo( $rawPath, array( 'encrypted'=>true, 'size' => $size ), '' ); - + \OC\Files\Filesystem::putFileInfo($rawPath, array('encrypted' => true, 'size' => $size), ''); } - } - + \OC_FileProxy::$enabled = true; - + // If files were found, return true return true; - } else { - + // If no files were found, return false return false; - } - } - + /** * @brief Return important encryption related paths * @param string $pathName Name of the directory to return the path of diff --git a/apps/files_encryption/tests/crypt.php b/apps/files_encryption/tests/crypt.php index bfb5ca0ec8b..69fd99d9a82 100755 --- a/apps/files_encryption/tests/crypt.php +++ b/apps/files_encryption/tests/crypt.php @@ -513,48 +513,7 @@ class Test_Crypt extends \PHPUnit_Framework_TestCase { $this->assertEquals( $this->dataUrl, $decrypt ); } - - // What is the point of this test? It doesn't use keyEncryptKeyfile() - function testKeyEncryptKeyfile() { - - # TODO: Don't repeat encryption from previous tests, use PHPUnit test interdependency instead - - // Generate keypair - $pair1 = Encryption\Crypt::createKeypair(); - - // Encrypt plain data, generate keyfile & encrypted file - $cryptedData = Encryption\Crypt::symmetricEncryptFileContentKeyfile( $this->dataUrl ); - - // Encrypt keyfile - $cryptedKey = Encryption\Crypt::keyEncrypt( $cryptedData['key'], $pair1['publicKey'] ); - - // Decrypt keyfile - $decryptKey = Encryption\Crypt::keyDecrypt( $cryptedKey, $pair1['privateKey'] ); - - // Decrypt encrypted file - $decryptData = Encryption\Crypt::symmetricDecryptFileContent( $cryptedData['encrypted'], $decryptKey ); - - $this->assertEquals( $this->dataUrl, $decryptData ); - - } - - /** - * @brief test functionality of keyEncryptKeyfile() and - * keyDecryptKeyfile() - */ - function testKeyDecryptKeyfile() { - - $encrypted = Encryption\Crypt::keyEncryptKeyfile( $this->dataShort, $this->genPublicKey ); - - $this->assertNotEquals( $encrypted['data'], $this->dataShort ); - $decrypted = Encryption\Crypt::keyDecryptKeyfile( $encrypted['data'], $encrypted['key'], $this->genPrivateKey ); - - $this->assertEquals( $decrypted, $this->dataShort ); - - } - - /** * @brief test encryption using legacy blowfish method */ -- cgit v1.2.3 From 002445e23d8dcefe2545f22e6914d7cfa7ebbbd1 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Fri, 17 May 2013 14:49:54 +0200 Subject: some typo fixed --- 3rdparty | 1 - apps/files_encryption/lib/util.php | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) delete mode 160000 3rdparty (limited to 'apps/files_encryption/lib') diff --git a/3rdparty b/3rdparty deleted file mode 160000 index 2d59ac4f7bd..00000000000 --- a/3rdparty +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2d59ac4f7bd354d9ea7ebea05f863d9f50ccb6ee diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index a2dee1ca71f..f1042ed759a 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -716,8 +716,8 @@ class Util { $sharingEnabled = \OCP\Share::isEnabled(); // if file exists try to get sharing users - if ($view->file_exists($legacyFile['path'])) { - $uniqueUserIds = $util->getSharingUsersArray($sharingEnabled, $legacyFile['path'], $this->userId); + if ($this->view->file_exists($legacyFile['path'])) { + $uniqueUserIds = $this->getSharingUsersArray($sharingEnabled, $legacyFile['path'], $this->userId); } else { $uniqueUserIds[] = $this->userId; } @@ -726,7 +726,7 @@ class Util { $publicKeys = Keymanager::getPublicKeys($this->view, $uniqueUserIds); // Recrypt data, generate catfile - $recrypted = Crypt::legacyKeyRecryptKeyfile($legacyData, $legacyPassphrase, $publicKey, $newPassphrase, $legacyFile['path'], $publicKeys); + $recrypted = Crypt::legacyKeyRecryptKeyfile($legacyData, $legacyPassphrase, $publicKeys, $newPassphrase, $legacyFile['path']); $rawPath = $legacyFile['path']; $relPath = $this->stripUserFilesPath($rawPath); -- cgit v1.2.3 From eaa61b8539bcd1f428d8fad1d67894e8cb4f271a Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Fri, 17 May 2013 17:29:32 +0200 Subject: fix migration to new encryption --- apps/files_encryption/ajax/encryptall.php | 40 ------------------------------- apps/files_encryption/hooks/hooks.php | 2 +- apps/files_encryption/lib/crypt.php | 21 ++++++++++++---- apps/files_encryption/lib/util.php | 3 +-- 4 files changed, 18 insertions(+), 48 deletions(-) delete mode 100644 apps/files_encryption/ajax/encryptall.php (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/ajax/encryptall.php b/apps/files_encryption/ajax/encryptall.php deleted file mode 100644 index ce613ca4435..00000000000 --- a/apps/files_encryption/ajax/encryptall.php +++ /dev/null @@ -1,40 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or later. - * See the COPYING-README file. - * - * @brief Script to handle manual trigger of \OCA\Encryption\Util{}->encryptAll() - */ - -use OCA\Encryption; - -\OCP\JSON::checkAppEnabled( 'files_encryption' ); -\OCP\JSON::callCheck(); - -$return = false; - -if ( - isset( $_POST['encryptAll'] ) - && ! empty( $_POST['userPassword'] ) -) { - - $view = new \OC_FilesystemView( '' ); - $userId = \OCP\User::getUser(); - $util = new \OCA\Encryption\Util( $view, $userId ); - $session = new \OCA\Encryption\Session( $view ); - $publicKey = \OCA\Encryption\Keymanager::getPublicKey( $view, $userId ); - $path = '/' . $userId . '/' . 'files'; - - $util->encryptAll( $publicKey, $path, $session->getLegacyKey(), $_POST['userPassword'] ); - - $return = true; - -} else { - - $return = false; - -} - -// Return success or failure -( $return ) ? \OCP\JSON::success() : \OCP\JSON::error(); \ No newline at end of file diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 76a19ff968c..72334559b8c 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -88,7 +88,7 @@ class Hooks { // This serves to upgrade old versions of the encryption // app (see appinfo/spec.txt) if ( - $util->encryptAll( $publicKey, '/' . $params['uid'] . '/' . 'files', $session->getLegacyKey(), $params['password'] ) + $util->encryptAll( '/' . $params['uid'] . '/' . 'files', $session->getLegacyKey(), $params['password'] ) ) { \OC_Log::write( diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 708d1719d73..56dacc94b0c 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -169,7 +169,7 @@ class Crypt { * @return true / false */ public static function isLegacyEncryptedContent( $data, $relPath ) { - + // Fetch all file metadata from DB $metadata = \OC\Files\Filesystem::getFileInfo( $relPath, '' ); @@ -683,15 +683,26 @@ class Crypt { $decrypted = $bf->decrypt( $content ); - $trimmed = rtrim( $decrypted, "\0" ); - - return $trimmed; + return $decrypted; } + + private static function legacyBlockDecrypt($data, $key='',$maxLength=0) { + $result = ''; + while (strlen($data)) { + $result.=self::legacyDecrypt(substr($data, 0, 8192), $key); + $data = substr($data, 8192); + } + if ($maxLength > 0) { + return substr($result, 0, $maxLength); + } else { + return rtrim($result, "\0"); + } + } public static function legacyKeyRecryptKeyfile( $legacyEncryptedContent, $legacyPassphrase, $publicKeys, $newPassphrase, $path ) { - $decrypted = self::legacyDecrypt( $legacyEncryptedContent, $legacyPassphrase ); + $decrypted = self::legacyBlockDecrypt( $legacyEncryptedContent, $legacyPassphrase ); // Encrypt plain data, generate keyfile & encrypted file $cryptedData = self::symmetricEncryptFileContentKeyfile( $decrypted ); diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index f1042ed759a..9588db8d647 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -652,11 +652,10 @@ class Util { /** * @brief Encrypt all files in a directory - * @param string $publicKey the public key to encrypt files with * @param string $dirPath the directory whose files will be encrypted * @note Encryption is recursive */ - public function encryptAll($publicKey, $dirPath, $legacyPassphrase = null, $newPassphrase = null) { + public function encryptAll($dirPath, $legacyPassphrase = null, $newPassphrase = null) { if ($found = $this->findEncFiles($dirPath)) { -- cgit v1.2.3 From cea9208ceccda86a33ec294926d39adecb962ed2 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Fri, 17 May 2013 21:59:53 +0200 Subject: fix broken legacy tests --- apps/files_encryption/lib/crypt.php | 4 ++-- apps/files_encryption/tests/crypt.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 56dacc94b0c..046b4601b06 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -652,7 +652,7 @@ class Crypt { return $legacyEncKey; } - + /** * @brief encrypts content using legacy blowfish system * @param $content the cleartext message you want to encrypt @@ -683,7 +683,7 @@ class Crypt { $decrypted = $bf->decrypt( $content ); - return $decrypted; + return rtrim($decrypted, "\0");; } diff --git a/apps/files_encryption/tests/crypt.php b/apps/files_encryption/tests/crypt.php index 69fd99d9a82..9737eefb96c 100755 --- a/apps/files_encryption/tests/crypt.php +++ b/apps/files_encryption/tests/crypt.php @@ -595,7 +595,7 @@ class Test_Crypt extends \PHPUnit_Framework_TestCase { */ function testLegacyKeyRecryptKeyfileEncrypt( $crypted ) { - $recrypted = Encryption\Crypt::LegacyKeyRecryptKeyfile( $crypted, $this->pass, $this->genPublicKey, $this->pass ); + $recrypted = Encryption\Crypt::LegacyKeyRecryptKeyfile( $crypted, $this->pass, array($this->genPublicKey), $this->pass, ''); $this->assertNotEquals( $this->dataLong, $recrypted['data'] ); -- cgit v1.2.3 From 3aa48616a6cc960896d8a17e7854a71ee6f308a7 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Fri, 17 May 2013 22:44:45 +0200 Subject: remove unused code --- apps/files_encryption/lib/crypt.php | 123 +++--------------------------------- 1 file changed, 9 insertions(+), 114 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 046b4601b06..ba588819d06 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -155,7 +155,7 @@ class Crypt { // TODO: Use DI to get \OC\Files\Filesystem out of here // Fetch all file metadata from DB - $metadata = \OC\Files\Filesystem::getFileInfo( $path, '' ); + $metadata = \OC\Files\Filesystem::getFileInfo( $path); // Return encryption status return isset( $metadata['encrypted'] ) and ( bool )$metadata['encrypted']; @@ -474,78 +474,9 @@ class Crypt { } /** - * @brief Symmetrically encrypt a file by combining encrypted component data blocks - */ - public static function symmetricBlockEncryptFileContent( $plainContent, $key ) { - - $crypted = ''; - - $remaining = $plainContent; - - $testarray = array(); - - while( strlen( $remaining ) ) { - - //echo "\n\n\$block = ".substr( $remaining, 0, 6126 ); - - // Encrypt a chunk of unencrypted data and add it to the rest - $block = self::symmetricEncryptFileContent( substr( $remaining, 0, 6126 ), $key ); - - $padded = self::addPadding( $block ); - - $crypted .= $block; - - $testarray[] = $block; - - // Remove the data already encrypted from remaining unencrypted data - $remaining = substr( $remaining, 6126 ); - - } - - //echo "hags "; - - //echo "\n\n\n\$crypted = $crypted\n\n\n"; - - //print_r($testarray); - - return $crypted; - - } - - - /** - * @brief Symmetrically decrypt a file by combining encrypted component data blocks - */ - public static function symmetricBlockDecryptFileContent( $crypted, $key ) { - - $decrypted = ''; - - $remaining = $crypted; - - $testarray = array(); - - while( strlen( $remaining ) ) { - - $testarray[] = substr( $remaining, 0, 8192 ); - - // Decrypt a chunk of unencrypted data and add it to the rest - $decrypted .= self::symmetricDecryptFileContent( $remaining, $key ); - - // Remove the data already encrypted from remaining unencrypted data - $remaining = substr( $remaining, 8192 ); - - } - - //echo "\n\n\$testarray = "; print_r($testarray); - - return $decrypted; - - } - - /** - * @brief Generates a pseudo random initialisation vector - * @return String $iv generated IV - */ + * @brief Generates a pseudo random initialisation vector + * @return String $iv generated IV + */ public static function generateIv() { if ( $random = openssl_random_pseudo_bytes( 12, $strong ) ) { @@ -571,10 +502,10 @@ class Crypt { } - /** - * @brief Generate a pseudo random 1024kb ASCII key - * @returns $key Generated key - */ + /** + * @brief Generate a pseudo random 1024kb ASCII key + * @returns $key Generated key + */ public static function generateKey() { // Generate key @@ -597,29 +528,6 @@ class Crypt { } - public static function changekeypasscode( $oldPassword, $newPassword ) { - - if ( \OCP\User::isLoggedIn() ) { - - $key = Keymanager::getPrivateKey( $user, $view ); - - if ( ( $key = Crypt::symmetricDecryptFileContent($key,$oldpasswd) ) ) { - - if ( ( $key = Crypt::symmetricEncryptFileContent( $key, $newpasswd ) ) ) { - - Keymanager::setPrivateKey( $key ); - - return true; - } - - } - - } - - return false; - - } - /** * @brief Get the blowfish encryption handeler for a key * @param $key string (optional) @@ -713,18 +621,5 @@ class Crypt { return array( 'data' => $cryptedData['encrypted'], 'filekey' => $multiEncrypted['data'], 'sharekeys' => $multiEncrypted['keys'] ); } - - /** - * @brief Re-encryptes a legacy blowfish encrypted file using AES with integrated IV - * @param $legacyContent the legacy encrypted content to re-encrypt - * @returns cleartext content - * - * This function decrypts an content - */ - public static function legacyRecrypt( $legacyContent, $legacyPassphrase, $newPassphrase ) { - - // TODO: write me - - } - + } \ No newline at end of file -- cgit v1.2.3 From 681252669a237a2383bcdc05892e368785103ad2 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Sat, 18 May 2013 22:10:00 +0200 Subject: changed migrationStatus to migration_status for pgsql --- apps/files_encryption/appinfo/database.xml | 2 +- apps/files_encryption/lib/util.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/appinfo/database.xml b/apps/files_encryption/appinfo/database.xml index 64c9ef65fa8..1935a4df6ad 100644 --- a/apps/files_encryption/appinfo/database.xml +++ b/apps/files_encryption/appinfo/database.xml @@ -28,7 +28,7 @@ Whether encryption key recovery is enabled - migrationStatus + migration_status boolean true 0 diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 9588db8d647..4e32cf6da14 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -1033,7 +1033,7 @@ class Util { $sql = 'UPDATE *PREFIX*encryption SET - migrationStatus = ? + migration_status = ? WHERE uid = ?'; @@ -1062,7 +1062,7 @@ class Util { public function getMigrationStatus() { $sql = 'SELECT - migrationStatus + migration_status FROM `*PREFIX*encryption` WHERE @@ -1078,7 +1078,7 @@ class Util { while( $row = $result->fetchRow() ) { - $migrationStatus[] = $row['migrationStatus']; + $migrationStatus[] = $row['migration_status']; } -- cgit v1.2.3 From ddda2a1f795122518d13b8654ab4a738d6fa526f Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Sun, 19 May 2013 07:04:31 +0200 Subject: changed database column 'recovery' to 'recovery_enabled' because recovery is a pgsql keyword more info about pgsql keywords http://www.postgresql.org/docs/9.1/static/sql-keywords-appendix.html --- apps/files_encryption/appinfo/database.xml | 2 +- apps/files_encryption/lib/util.php | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/appinfo/database.xml b/apps/files_encryption/appinfo/database.xml index 1935a4df6ad..ca149f0c69d 100644 --- a/apps/files_encryption/appinfo/database.xml +++ b/apps/files_encryption/appinfo/database.xml @@ -21,7 +21,7 @@ What client-side / server-side configuration is used - recovery + recovery_enabled boolean true 0 diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 4e32cf6da14..82f789c5202 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -228,7 +228,7 @@ class Util { if ( false === $this->recoveryEnabledForUser() ) { // create database configuration - $sql = 'INSERT INTO `*PREFIX*encryption` (`uid`,`mode`,`recovery`) VALUES (?,?,?)'; + $sql = 'INSERT INTO `*PREFIX*encryption` (`uid`,`mode`,`recovery_enabled`) VALUES (?,?,?)'; $args = array( $this->userId, 'server-side', 0); $query = \OCP\DB::prepare( $sql ); $query->execute( $args ); @@ -252,7 +252,7 @@ class Util { public function recoveryEnabledForUser() { $sql = 'SELECT - recovery + recovery_enabled FROM `*PREFIX*encryption` WHERE @@ -268,7 +268,7 @@ class Util { while( $row = $result->fetchRow() ) { - $recoveryEnabled[] = $row['recovery']; + $recoveryEnabled[] = $row['recovery_enabled']; } @@ -299,7 +299,7 @@ class Util { if ( false === $recoveryStatus ) { $sql = 'INSERT INTO `*PREFIX*encryption` - (`uid`,`mode`,`recovery`) + (`uid`,`mode`,`recovery_enabled`) VALUES (?,?,?)'; $args = array( $this->userId, 'server-side', $enabled ); @@ -310,7 +310,7 @@ class Util { $sql = 'UPDATE *PREFIX*encryption SET - recovery = ? + recovery_enabled = ? WHERE uid = ?'; -- cgit v1.2.3 From 5d572c344925e4599741ada08b70e48c88fb9011 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Sun, 19 May 2013 22:31:00 +0200 Subject: update phpdoc --- apps/files_encryption/lib/keymanager.php | 6 ++++-- apps/files_encryption/lib/session.php | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 74462a0d1ed..b422ff099b1 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -28,10 +28,12 @@ namespace OCA\Encryption; * @note Where a method requires a view object, it's root must be '/' */ class Keymanager { - + /** * @brief retrieve the ENCRYPTED private key from a user - * + * + * @param \OC_FilesystemView $view + * @param string $user * @return string private key or false (hopefully) * @note the key returned by this method must be decrypted before use */ diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index f02315f95df..8d604dc721e 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -97,8 +97,8 @@ class Session { /** * @brief Sets user private key to session + * @param string $privateKey * @return bool - * */ public function setPrivateKey( $privateKey ) { -- cgit v1.2.3 From 3b850a2524471030da27227cba18b31ffc998aa4 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Mon, 20 May 2013 01:24:36 +0200 Subject: reformat code added and changed phpdoc --- apps/files_encryption/lib/crypt.php | 827 +++++++++--------- apps/files_encryption/lib/helper.php | 134 +-- apps/files_encryption/lib/keymanager.php | 517 +++++------ apps/files_encryption/lib/proxy.php | 677 ++++++++------- apps/files_encryption/lib/session.php | 167 ++-- apps/files_encryption/lib/stream.php | 562 ++++++------ apps/files_encryption/lib/util.php | 1294 +++++++++++++++------------- apps/files_encryption/tests/crypt.php | 911 ++++++++++---------- apps/files_encryption/tests/keymanager.php | 147 ++-- apps/files_encryption/tests/share.php | 640 +++++++------- apps/files_encryption/tests/util.php | 192 +++-- 11 files changed, 3154 insertions(+), 2914 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index ba588819d06..783c19d2542 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -4,8 +4,8 @@ * ownCloud * * @author Sam Tuke, Frank Karlitschek, Robin Appelman - * @copyright 2012 Sam Tuke samtuke@owncloud.com, - * Robin Appelman icewind@owncloud.com, Frank Karlitschek + * @copyright 2012 Sam Tuke samtuke@owncloud.com, + * Robin Appelman icewind@owncloud.com, Frank Karlitschek * frank@owncloud.org * * This library is free software; you can redistribute it and/or @@ -27,505 +27,532 @@ namespace OCA\Encryption; require_once 'Crypt_Blowfish/Blowfish.php'; -// Todo: -// - Add a setting "Don´t encrypt files larger than xx because of performance" -// - Don't use a password directly as encryption key. but a key which is -// stored on the server and encrypted with the user password. -> change pass -// faster - /** * Class for common cryptography functionality */ -class Crypt { +class Crypt +{ /** * @brief return encryption mode client or server side encryption - * @param string user name (use system wide setting if name=null) + * @param string $user name (use system wide setting if name=null) * @return string 'client' or 'server' */ - public static function mode( $user = null ) { + public static function mode($user = null) + { return 'server'; - + } - - /** - * @brief Create a new encryption keypair - * @return array publicKey, privatekey - */ - public static function createKeypair() { - + + /** + * @brief Create a new encryption keypair + * @return array publicKey, privatekey + */ + public static function createKeypair() + { + $res = openssl_pkey_new(array('private_key_bits' => 4096)); // Get private key - openssl_pkey_export( $res, $privateKey ); + openssl_pkey_export($res, $privateKey); // Get public key - $publicKey = openssl_pkey_get_details( $res ); - + $publicKey = openssl_pkey_get_details($res); + $publicKey = $publicKey['key']; - - return( array( 'publicKey' => $publicKey, 'privateKey' => $privateKey ) ); - + + return (array('publicKey' => $publicKey, 'privateKey' => $privateKey)); + } - - /** - * @brief Add arbitrary padding to encrypted data - * @param string $data data to be padded - * @return padded data - * @note In order to end up with data exactly 8192 bytes long we must - * add two letters. It is impossible to achieve exactly 8192 length - * blocks with encryption alone, hence padding is added to achieve the - * required length. - */ - public static function addPadding( $data ) { - + + /** + * @brief Add arbitrary padding to encrypted data + * @param string $data data to be padded + * @return string padded data + * @note In order to end up with data exactly 8192 bytes long we must + * add two letters. It is impossible to achieve exactly 8192 length + * blocks with encryption alone, hence padding is added to achieve the + * required length. + */ + public static function addPadding($data) + { + $padded = $data . 'xx'; - + return $padded; - + } - - /** - * @brief Remove arbitrary padding to encrypted data - * @param string $padded padded data to remove padding from - * @return unpadded data on success, false on error - */ - public static function removePadding( $padded ) { - - if ( substr( $padded, -2 ) == 'xx' ) { - - $data = substr( $padded, 0, -2 ); - + + /** + * @brief Remove arbitrary padding to encrypted data + * @param string $padded padded data to remove padding from + * @return string unpadded data on success, false on error + */ + public static function removePadding($padded) + { + + if (substr($padded, -2) == 'xx') { + + $data = substr($padded, 0, -2); + return $data; - + } else { - + // TODO: log the fact that unpadded data was submitted for removal of padding return false; - + } - + } - - /** - * @brief Check if a file's contents contains an IV and is symmetrically encrypted - * @return true / false - * @note see also OCA\Encryption\Util->isEncryptedPath() - */ - public static function isCatfileContent( $content ) { - - if ( !$content ) { - + + /** + * @brief Check if a file's contents contains an IV and is symmetrically encrypted + * @param $content + * @return boolean + * @note see also OCA\Encryption\Util->isEncryptedPath() + */ + public static function isCatfileContent($content) + { + + if (!$content) { + return false; - + } - - $noPadding = self::removePadding( $content ); - + + $noPadding = self::removePadding($content); + // Fetch encryption metadata from end of file - $meta = substr( $noPadding, -22 ); - + $meta = substr($noPadding, -22); + // Fetch IV from end of file - $iv = substr( $meta, -16 ); - + $iv = substr($meta, -16); + // Fetch identifier from start of metadata - $identifier = substr( $meta, 0, 6 ); - - if ( $identifier == '00iv00') { - + $identifier = substr($meta, 0, 6); + + if ($identifier == '00iv00') { + return true; - + } else { - + return false; - + } - + } - + /** * Check if a file is encrypted according to database file cache * @param string $path * @return bool */ - public static function isEncryptedMeta( $path ) { - + public static function isEncryptedMeta($path) + { + // TODO: Use DI to get \OC\Files\Filesystem out of here - + // Fetch all file metadata from DB - $metadata = \OC\Files\Filesystem::getFileInfo( $path); - + $metadata = \OC\Files\Filesystem::getFileInfo($path); + // Return encryption status - return isset( $metadata['encrypted'] ) and ( bool )$metadata['encrypted']; - + return isset($metadata['encrypted']) and ( bool )$metadata['encrypted']; + } - - /** - * @brief Check if a file is encrypted via legacy system - * @param string $relPath The path of the file, relative to user/data; - * e.g. filename or /Docs/filename, NOT admin/files/filename - * @return true / false - */ - public static function isLegacyEncryptedContent( $data, $relPath ) { + + /** + * @brief Check if a file is encrypted via legacy system + * @param $data + * @param string $relPath The path of the file, relative to user/data; + * e.g. filename or /Docs/filename, NOT admin/files/filename + * @return boolean + */ + public static function isLegacyEncryptedContent($data, $relPath) + { // Fetch all file metadata from DB - $metadata = \OC\Files\Filesystem::getFileInfo( $relPath, '' ); - + $metadata = \OC\Files\Filesystem::getFileInfo($relPath, ''); + // If a file is flagged with encryption in DB, but isn't a // valid content + IV combination, it's probably using the // legacy encryption system - if ( - isset( $metadata['encrypted'] ) - and $metadata['encrypted'] === true - and ! self::isCatfileContent( $data ) + if ( + isset($metadata['encrypted']) + and $metadata['encrypted'] === true + and !self::isCatfileContent($data) ) { - + return true; - + } else { - + return false; - + } - + } - - /** - * @brief Symmetrically encrypt a string - * @returns encrypted file - */ - public static function encrypt( $plainContent, $iv, $passphrase = '' ) { - - if ( $encryptedContent = openssl_encrypt( $plainContent, 'AES-128-CFB', $passphrase, false, $iv ) ) { + + /** + * @brief Symmetrically encrypt a string + * @return string encrypted file content + */ + public static function encrypt($plainContent, $iv, $passphrase = '') + { + + if ($encryptedContent = openssl_encrypt($plainContent, 'AES-128-CFB', $passphrase, false, $iv)) { return $encryptedContent; - + } else { - - \OC_Log::write( 'Encryption library', 'Encryption (symmetric) of content failed', \OC_Log::ERROR ); - + + \OC_Log::write('Encryption library', 'Encryption (symmetric) of content failed', \OC_Log::ERROR); + return false; - + } - + } - - /** - * @brief Symmetrically decrypt a string - * @returns decrypted file - */ - public static function decrypt( $encryptedContent, $iv, $passphrase ) { - - if ( $plainContent = openssl_decrypt( $encryptedContent, 'AES-128-CFB', $passphrase, false, $iv ) ) { + + /** + * @brief Symmetrically decrypt a string + * @return string decrypted file content + */ + public static function decrypt($encryptedContent, $iv, $passphrase) + { + + if ($plainContent = openssl_decrypt($encryptedContent, 'AES-128-CFB', $passphrase, false, $iv)) { return $plainContent; - - + + } else { - - throw new \Exception( 'Encryption library: Decryption (symmetric) of content failed' ); - + + throw new \Exception('Encryption library: Decryption (symmetric) of content failed'); + return false; - + } - + } - - /** - * @brief Concatenate encrypted data with its IV and padding - * @param string $content content to be concatenated - * @param string $iv IV to be concatenated - * @returns string concatenated content - */ - public static function concatIv ( $content, $iv ) { - + + /** + * @brief Concatenate encrypted data with its IV and padding + * @param string $content content to be concatenated + * @param string $iv IV to be concatenated + * @returns string concatenated content + */ + public static function concatIv($content, $iv) + { + $combined = $content . '00iv00' . $iv; - + return $combined; - + } - - /** - * @brief Split concatenated data and IV into respective parts - * @param string $catFile concatenated data to be split - * @returns array keys: encrypted, iv - */ - public static function splitIv ( $catFile ) { - + + /** + * @brief Split concatenated data and IV into respective parts + * @param string $catFile concatenated data to be split + * @returns array keys: encrypted, iv + */ + public static function splitIv($catFile) + { + // Fetch encryption metadata from end of file - $meta = substr( $catFile, -22 ); - + $meta = substr($catFile, -22); + // Fetch IV from end of file - $iv = substr( $meta, -16 ); - + $iv = substr($meta, -16); + // Remove IV and IV identifier text to expose encrypted content - $encrypted = substr( $catFile, 0, -22 ); - + $encrypted = substr($catFile, 0, -22); + $split = array( 'encrypted' => $encrypted - , 'iv' => $iv + , 'iv' => $iv ); - + return $split; - + } - - /** - * @brief Symmetrically encrypts a string and returns keyfile content - * @param $plainContent content to be encrypted in keyfile - * @returns encrypted content combined with IV - * @note IV need not be specified, as it will be stored in the returned keyfile - * and remain accessible therein. - */ - public static function symmetricEncryptFileContent( $plainContent, $passphrase = '' ) { - - if ( !$plainContent ) { - + + /** + * @brief Symmetrically encrypts a string and returns keyfile content + * @param string $plainContent content to be encrypted in keyfile + * @param string $passphrase + * @return bool|string + * @return string encrypted content combined with IV + * @note IV need not be specified, as it will be stored in the returned keyfile + * and remain accessible therein. + */ + public static function symmetricEncryptFileContent($plainContent, $passphrase = '') + { + + if (!$plainContent) { + return false; - + } - + $iv = self::generateIv(); - - if ( $encryptedContent = self::encrypt( $plainContent, $iv, $passphrase ) ) { - - // Combine content to encrypt with IV identifier and actual IV - $catfile = self::concatIv( $encryptedContent, $iv ); - - $padded = self::addPadding( $catfile ); - - return $padded; - + + if ($encryptedContent = self::encrypt($plainContent, $iv, $passphrase)) { + + // Combine content to encrypt with IV identifier and actual IV + $catfile = self::concatIv($encryptedContent, $iv); + + $padded = self::addPadding($catfile); + + return $padded; + } else { - - \OC_Log::write( 'Encryption library', 'Encryption (symmetric) of keyfile content failed', \OC_Log::ERROR ); - + + \OC_Log::write('Encryption library', 'Encryption (symmetric) of keyfile content failed', \OC_Log::ERROR); + return false; - + } - + } /** - * @brief Symmetrically decrypts keyfile content - * @param string $source - * @param string $target - * @param string $key the decryption key - * @returns decrypted content - * - * This function decrypts a file - */ - public static function symmetricDecryptFileContent( $keyfileContent, $passphrase = '' ) { - - if ( !$keyfileContent ) { - - throw new \Exception( 'Encryption library: no data provided for decryption' ); - + * @brief Symmetrically decrypts keyfile content + * @param $keyfileContent + * @param string $passphrase + * @throws \Exception + * @return bool|string + * @internal param string $source + * @internal param string $target + * @internal param string $key the decryption key + * @returns string decrypted content + * + * This function decrypts a file + */ + public static function symmetricDecryptFileContent($keyfileContent, $passphrase = '') + { + + if (!$keyfileContent) { + + throw new \Exception('Encryption library: no data provided for decryption'); + } - + // Remove padding - $noPadding = self::removePadding( $keyfileContent ); - + $noPadding = self::removePadding($keyfileContent); + // Split into enc data and catfile - $catfile = self::splitIv( $noPadding ); - - if ( $plainContent = self::decrypt( $catfile['encrypted'], $catfile['iv'], $passphrase ) ) { - + $catfile = self::splitIv($noPadding); + + if ($plainContent = self::decrypt($catfile['encrypted'], $catfile['iv'], $passphrase)) { + return $plainContent; - + } - + } - + /** - * @brief Creates symmetric keyfile content using a generated key - * @param string $plainContent content to be encrypted - * @returns array keys: key, encrypted - * @note symmetricDecryptFileContent() can be used to decrypt files created using this method - * - * This function decrypts a file - */ - public static function symmetricEncryptFileContentKeyfile( $plainContent ) { - + * @brief Creates symmetric keyfile content using a generated key + * @param string $plainContent content to be encrypted + * @returns array keys: key, encrypted + * @note symmetricDecryptFileContent() can be used to decrypt files created using this method + * + * This function decrypts a file + */ + public static function symmetricEncryptFileContentKeyfile($plainContent) + { + $key = self::generateKey(); - - if( $encryptedContent = self::symmetricEncryptFileContent( $plainContent, $key ) ) { - + + if ($encryptedContent = self::symmetricEncryptFileContent($plainContent, $key)) { + return array( 'key' => $key - , 'encrypted' => $encryptedContent + , 'encrypted' => $encryptedContent ); - + } else { - + return false; - + } - + } - + /** - * @brief Create asymmetrically encrypted keyfile content using a generated key - * @param string $plainContent content to be encrypted - * @param array $publicKeys array keys must be the userId of corresponding user - * @returns array keys: keys (array, key = userId), data - * @note symmetricDecryptFileContent() can decrypt files created using this method - */ - public static function multiKeyEncrypt( $plainContent, array $publicKeys ) { - + * @brief Create asymmetrically encrypted keyfile content using a generated key + * @param string $plainContent content to be encrypted + * @param array $publicKeys array keys must be the userId of corresponding user + * @returns array keys: keys (array, key = userId), data + * @note symmetricDecryptFileContent() can decrypt files created using this method + */ + public static function multiKeyEncrypt($plainContent, array $publicKeys) + { + // openssl_seal returns false without errors if $plainContent // is empty, so trigger our own error - if ( empty( $plainContent ) ) { - - trigger_error( "Cannot mutliKeyEncrypt empty plain content" ); - throw new \Exception( 'Cannot mutliKeyEncrypt empty plain content' ); - + if (empty($plainContent)) { + + trigger_error("Cannot mutliKeyEncrypt empty plain content"); + throw new \Exception('Cannot mutliKeyEncrypt empty plain content'); + } - + // Set empty vars to be set by openssl by reference $sealed = ''; $shareKeys = array(); - - if( openssl_seal( $plainContent, $sealed, $shareKeys, $publicKeys ) ) { - + + if (openssl_seal($plainContent, $sealed, $shareKeys, $publicKeys)) { + $i = 0; - + // Ensure each shareKey is labelled with its // corresponding userId - foreach ( $publicKeys as $userId => $publicKey ) { - + foreach ($publicKeys as $userId => $publicKey) { + $mappedShareKeys[$userId] = $shareKeys[$i]; $i++; - + } - + return array( 'keys' => $mappedShareKeys - , 'data' => $sealed + , 'data' => $sealed ); - + } else { - + return false; - + } - + } - + /** - * @brief Asymmetrically encrypt a file using multiple public keys - * @param string $plainContent content to be encrypted - * @returns string $plainContent decrypted string - * @note symmetricDecryptFileContent() can be used to decrypt files created using this method - * - * This function decrypts a file - */ - public static function multiKeyDecrypt( $encryptedContent, $shareKey, $privateKey ) { - - if ( !$encryptedContent ) { - + * @brief Asymmetrically encrypt a file using multiple public keys + * @param $encryptedContent + * @param $shareKey + * @param $privateKey + * @return bool + * @internal param string $plainContent content to be encrypted + * @returns string $plainContent decrypted string + * @note symmetricDecryptFileContent() can be used to decrypt files created using this method + * + * This function decrypts a file + */ + public static function multiKeyDecrypt($encryptedContent, $shareKey, $privateKey) + { + + if (!$encryptedContent) { + return false; - + } - - if ( openssl_open( $encryptedContent, $plainContent, $shareKey, $privateKey ) ) { - + + if (openssl_open($encryptedContent, $plainContent, $shareKey, $privateKey)) { + return $plainContent; - + } else { - - \OC_Log::write( 'Encryption library', 'Decryption (asymmetric) of sealed content failed', \OC_Log::ERROR ); - + + \OC_Log::write('Encryption library', 'Decryption (asymmetric) of sealed content failed', \OC_Log::ERROR); + return false; - + } - + } - - /** - * @brief Asymetrically encrypt a string using a public key - * @returns encrypted file - */ - public static function keyEncrypt( $plainContent, $publicKey ) { - - openssl_public_encrypt( $plainContent, $encryptedContent, $publicKey ); - + + /** + * @brief Asymetrically encrypt a string using a public key + * @return string encrypted file + */ + public static function keyEncrypt($plainContent, $publicKey) + { + + openssl_public_encrypt($plainContent, $encryptedContent, $publicKey); + return $encryptedContent; - + } - - /** - * @brief Asymetrically decrypt a file using a private key - * @returns decrypted file - */ - public static function keyDecrypt( $encryptedContent, $privatekey ) { - - $result = @openssl_private_decrypt( $encryptedContent, $plainContent, $privatekey ); - - if ( $result ) { + + /** + * @brief Asymetrically decrypt a file using a private key + * @return string decrypted file + */ + public static function keyDecrypt($encryptedContent, $privatekey) + { + + $result = @openssl_private_decrypt($encryptedContent, $plainContent, $privatekey); + + if ($result) { return $plainContent; } return $result; - + } - + /** * @brief Generates a pseudo random initialisation vector * @return String $iv generated IV */ - public static function generateIv() { - - if ( $random = openssl_random_pseudo_bytes( 12, $strong ) ) { - - if ( !$strong ) { - + public static function generateIv() + { + + if ($random = openssl_random_pseudo_bytes(12, $strong)) { + + if (!$strong) { + // If OpenSSL indicates randomness is insecure, log error - \OC_Log::write( 'Encryption library', 'Insecure symmetric key was generated using openssl_random_pseudo_bytes()', \OC_Log::WARN ); - + \OC_Log::write('Encryption library', 'Insecure symmetric key was generated using openssl_random_pseudo_bytes()', \OC_Log::WARN); + } - + // We encode the iv purely for string manipulation // purposes - it gets decoded before use - $iv = base64_encode( $random ); - + $iv = base64_encode($random); + return $iv; - + } else { - - throw new Exception( 'Generating IV failed' ); - + + throw new \Exception('Generating IV failed'); + } - + } - + /** * @brief Generate a pseudo random 1024kb ASCII key * @returns $key Generated key */ - public static function generateKey() { - + public static function generateKey() + { + // Generate key - if ( $key = base64_encode( openssl_random_pseudo_bytes( 183, $strong ) ) ) { - - if ( !$strong ) { - + if ($key = base64_encode(openssl_random_pseudo_bytes(183, $strong))) { + + if (!$strong) { + // If OpenSSL indicates randomness is insecure, log error - throw new Exception ( 'Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()' ); - + throw new \Exception('Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()'); + } - + return $key; - + } else { - + return false; - + } - + } /** @@ -535,70 +562,89 @@ class Crypt { * * if the key is left out, the default handeler will be used */ - public static function getBlowfish( $key = '' ) { - - if ( $key ) { - - return new \Crypt_Blowfish( $key ); - + public static function getBlowfish($key = '') + { + + if ($key) { + + return new \Crypt_Blowfish($key); + } else { - + return false; - + } - + } - - public static function legacyCreateKey( $passphrase ) { - + + /** + * @param $passphrase + * @return mixed + */ + public static function legacyCreateKey($passphrase) + { + // Generate a random integer - $key = mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ); + $key = mt_rand(10000, 99999) . mt_rand(10000, 99999) . mt_rand(10000, 99999) . mt_rand(10000, 99999); // Encrypt the key with the passphrase - $legacyEncKey = self::legacyEncrypt( $key, $passphrase ); + $legacyEncKey = self::legacyEncrypt($key, $passphrase); return $legacyEncKey; - + } /** * @brief encrypts content using legacy blowfish system - * @param $content the cleartext message you want to encrypt - * @param $key the encryption key (optional) - * @returns encrypted content + * @param string $content the cleartext message you want to encrypt + * @param string $passphrase + * @return + * @internal param \OCA\Encryption\the $key encryption key (optional) + * @returns string encrypted content * * This function encrypts an content */ - public static function legacyEncrypt( $content, $passphrase = '' ) { - - $bf = self::getBlowfish( $passphrase ); - - return $bf->encrypt( $content ); - + public static function legacyEncrypt($content, $passphrase = '') + { + + $bf = self::getBlowfish($passphrase); + + return $bf->encrypt($content); + } - + /** - * @brief decrypts content using legacy blowfish system - * @param $content the cleartext message you want to decrypt - * @param $key the encryption key (optional) - * @returns cleartext content - * - * This function decrypts an content - */ - public static function legacyDecrypt( $content, $passphrase = '' ) { - - $bf = self::getBlowfish( $passphrase ); - - $decrypted = $bf->decrypt( $content ); - + * @brief decrypts content using legacy blowfish system + * @param string $content the cleartext message you want to decrypt + * @param string $passphrase + * @return string + * @internal param \OCA\Encryption\the $key encryption key (optional) + * @return string cleartext content + * + * This function decrypts an content + */ + public static function legacyDecrypt($content, $passphrase = '') + { + + $bf = self::getBlowfish($passphrase); + + $decrypted = $bf->decrypt($content); + return rtrim($decrypted, "\0");; - + } - private static function legacyBlockDecrypt($data, $key='',$maxLength=0) { + /** + * @param $data + * @param string $key + * @param int $maxLength + * @return string + */ + private static function legacyBlockDecrypt($data, $key = '', $maxLength = 0) + { $result = ''; while (strlen($data)) { - $result.=self::legacyDecrypt(substr($data, 0, 8192), $key); + $result .= self::legacyDecrypt(substr($data, 0, 8192), $key); $data = substr($data, 8192); } if ($maxLength > 0) { @@ -607,19 +653,28 @@ class Crypt { return rtrim($result, "\0"); } } - - public static function legacyKeyRecryptKeyfile( $legacyEncryptedContent, $legacyPassphrase, $publicKeys, $newPassphrase, $path ) { - - $decrypted = self::legacyBlockDecrypt( $legacyEncryptedContent, $legacyPassphrase ); + + /** + * @param $legacyEncryptedContent + * @param $legacyPassphrase + * @param $publicKeys + * @param $newPassphrase + * @param $path + * @return array + */ + public static function legacyKeyRecryptKeyfile($legacyEncryptedContent, $legacyPassphrase, $publicKeys, $newPassphrase, $path) + { + + $decrypted = self::legacyBlockDecrypt($legacyEncryptedContent, $legacyPassphrase); // Encrypt plain data, generate keyfile & encrypted file - $cryptedData = self::symmetricEncryptFileContentKeyfile( $decrypted ); + $cryptedData = self::symmetricEncryptFileContentKeyfile($decrypted); // Encrypt plain keyfile to multiple sharefiles - $multiEncrypted = Crypt::multiKeyEncrypt( $cryptedData['key'], $publicKeys ); + $multiEncrypted = Crypt::multiKeyEncrypt($cryptedData['key'], $publicKeys); + + return array('data' => $cryptedData['encrypted'], 'filekey' => $multiEncrypted['data'], 'sharekeys' => $multiEncrypted['keys']); - return array( 'data' => $cryptedData['encrypted'], 'filekey' => $multiEncrypted['data'], 'sharekeys' => $multiEncrypted['keys'] ); - } } \ No newline at end of file diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php index a04c65e251f..c57f0bc0092 100755 --- a/apps/files_encryption/lib/helper.php +++ b/apps/files_encryption/lib/helper.php @@ -23,76 +23,82 @@ namespace OCA\Encryption; -/** - * @brief Class to manage registration of hooks an various helper methods - */ + /** + * @brief Class to manage registration of hooks an various helper methods + */ /** * Class Helper * @package OCA\Encryption */ -class Helper { - +class Helper +{ + /** * @brief register share related hooks - * + * + */ + public static function registerShareHooks() + { + + \OCP\Util::connectHook('OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared'); + \OCP\Util::connectHook('OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared'); + \OCP\Util::connectHook('OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare'); + } + + /** + * @brief register user related hooks + * */ - public static function registerShareHooks() { + public static function registerUserHooks() + { - \OCP\Util::connectHook( 'OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared' ); - \OCP\Util::connectHook( 'OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared' ); - \OCP\Util::connectHook( 'OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare' ); + \OCP\Util::connectHook('OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login'); + \OCP\Util::connectHook('OC_User', 'post_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase'); + \OCP\Util::connectHook('OC_User', 'post_createUser', 'OCA\Encryption\Hooks', 'postCreateUser'); + \OCP\Util::connectHook('OC_User', 'post_deleteUser', 'OCA\Encryption\Hooks', 'postDeleteUser'); } - /** - * @brief register user related hooks - * - */ - public static function registerUserHooks() { - - \OCP\Util::connectHook( 'OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login' ); - \OCP\Util::connectHook( 'OC_User', 'post_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase' ); - \OCP\Util::connectHook( 'OC_User', 'post_createUser', 'OCA\Encryption\Hooks', 'postCreateUser' ); - \OCP\Util::connectHook( 'OC_User', 'post_deleteUser', 'OCA\Encryption\Hooks', 'postDeleteUser' ); - } - - /** - * @brief register webdav related hooks - * - */ - public static function registerWebdavHooks() { - - - } - - /** - * @brief register filesystem related hooks - * - */ - public static function registerFilesystemHooks() { - - \OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename'); - } - - /** - * @brief setup user for files_encryption - * - * @param Util $util - * @param string $password - * @return bool - */ - public static function setupUser($util, $password) { - // Check files_encryption infrastructure is ready for action - if ( ! $util->ready() ) { - - \OC_Log::write( 'Encryption library', 'User account "' . $util->getUserId() . '" is not ready for encryption; configuration started', \OC_Log::DEBUG ); - - if(!$util->setupServerSide( $password )) { - return false; - } - } - - return true; - } + /** + * @brief register webdav related hooks + * + */ + public static function registerWebdavHooks() + { + + + } + + /** + * @brief register filesystem related hooks + * + */ + public static function registerFilesystemHooks() + { + + \OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename'); + } + + /** + * @brief setup user for files_encryption + * + * @param Util $util + * @param string $password + * @return bool + */ + public static function setupUser($util, $password) + { + // Check files_encryption infrastructure is ready for action + if (!$util->ready()) { + + \OC_Log::write('Encryption library', 'User account "' . $util->getUserId() . '" is not ready for encryption; configuration started', \OC_Log::DEBUG); + + if (!$util->setupServerSide($password)) { + return false; + } + } + + return true; + } /** * @brief enable recovery @@ -103,7 +109,8 @@ class Helper { * @internal param string $password * @return bool */ - public static function adminEnableRecovery($recoveryKeyId, $recoveryPassword) { + public static function adminEnableRecovery($recoveryKeyId, $recoveryPassword) + { $view = new \OC\Files\View('/'); if ($recoveryKeyId === null) { @@ -139,7 +146,7 @@ class Helper { $view->file_put_contents('/owncloud_private_key/' . $recoveryKeyId . '.private.key', $encryptedPrivateKey); // create control file which let us check later on if the entered password was correct. - $encryptedControlData = \OCA\Encryption\Crypt::keyEncrypt("ownCloud", $keypair['publicKey']); + $encryptedControlData = \OCA\Encryption\Crypt::keyEncrypt("ownCloud", $keypair['publicKey']); if (!$view->is_dir('/control-file')) { $view->mkdir('/control-file'); } @@ -170,7 +177,8 @@ class Helper { * @param $recoveryPassword * @return bool */ - public static function adminDisableRecovery($recoveryPassword) { + public static function adminDisableRecovery($recoveryPassword) + { $util = new Util(new \OC_FilesystemView('/'), \OCP\User::getUser()); $return = $util->checkRecoveryPassword($recoveryPassword); diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index b422ff099b1..1bc334e7a17 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -27,7 +27,8 @@ namespace OCA\Encryption; * @brief Class to manage storage and retrieval of encryption keys * @note Where a method requires a view object, it's root must be '/' */ -class Keymanager { +class Keymanager +{ /** * @brief retrieve the ENCRYPTED private key from a user @@ -37,17 +38,18 @@ class Keymanager { * @return string private key or false (hopefully) * @note the key returned by this method must be decrypted before use */ - public static function getPrivateKey( \OC_FilesystemView $view, $user ) { - - $path = '/' . $user . '/' . 'files_encryption' . '/' . $user.'.private.key'; + public static function getPrivateKey(\OC_FilesystemView $view, $user) + { - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + $path = '/' . $user . '/' . 'files_encryption' . '/' . $user . '.private.key'; - $key = $view->file_get_contents( $path ); + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $key = $view->file_get_contents($path); + + \OC_FileProxy::$enabled = $proxyStatus; - \OC_FileProxy::$enabled = $proxyStatus; - return $key; } @@ -57,104 +59,111 @@ class Keymanager { * @param $userId * @return string public key or false */ - public static function getPublicKey( \OC_FilesystemView $view, $userId ) { + public static function getPublicKey(\OC_FilesystemView $view, $userId) + { - $proxyStatus = \OC_FileProxy::$enabled; + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - - $result = $view->file_get_contents( '/public-keys/' . $userId . '.public.key' ); - + + $result = $view->file_get_contents('/public-keys/' . $userId . '.public.key'); + \OC_FileProxy::$enabled = $proxyStatus; - return $result; - + return $result; + } - + /** * @brief Retrieve a user's public and private key * @param \OC_FilesystemView $view * @param $userId * @return array keys: privateKey, publicKey */ - public static function getUserKeys( \OC_FilesystemView $view, $userId ) { - + public static function getUserKeys(\OC_FilesystemView $view, $userId) + { + return array( - 'publicKey' => self::getPublicKey( $view, $userId ) - , 'privateKey' => self::getPrivateKey( $view, $userId ) + 'publicKey' => self::getPublicKey($view, $userId) + , 'privateKey' => self::getPrivateKey($view, $userId) ); - + } - + /** * @brief Retrieve public keys for given users * @param \OC_FilesystemView $view * @param array $userIds * @return array of public keys for the specified users */ - public static function getPublicKeys( \OC_FilesystemView $view, array $userIds ) { - + public static function getPublicKeys(\OC_FilesystemView $view, array $userIds) + { + $keys = array(); - - foreach ( $userIds as $userId ) { - - $keys[$userId] = self::getPublicKey( $view, $userId ); - + + foreach ($userIds as $userId) { + + $keys[$userId] = self::getPublicKey($view, $userId); + } - + return $keys; - + } - + /** * @brief store file encryption key * + * @param \OC_FilesystemView $view * @param string $path relative path of the file, including filename - * @param string $key + * @param $userId + * @param $catfile + * @internal param string $key * @return bool true/false - * @note The keyfile is not encrypted here. Client code must + * @note The keyfile is not encrypted here. Client code must * asymmetrically encrypt the keyfile before passing it to this method */ - public static function setFileKey( \OC_FilesystemView $view, $path, $userId, $catfile ) { - + public static function setFileKey(\OC_FilesystemView $view, $path, $userId, $catfile) + { + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; //here we need the currently logged in user, while userId can be a different user - $util = new Util( $view, \OCP\User::getUser() ); - list( $owner, $filename ) = $util->getUidAndFilename( $path ); + $util = new Util($view, \OCP\User::getUser()); + list($owner, $filename) = $util->getUidAndFilename($path); $basePath = '/' . $owner . '/files_encryption/keyfiles'; - - $targetPath = self::keySetPreparation( $view, $filename, $basePath, $owner ); - - if ( !$view->is_dir( $basePath . '/' . $targetPath ) ) { + + $targetPath = self::keySetPreparation($view, $filename, $basePath, $owner); + + if (!$view->is_dir($basePath . '/' . $targetPath)) { // create all parent folders - $info = pathinfo( $basePath . '/' . $targetPath ); - $keyfileFolderName = $view->getLocalFolder( $info['dirname'] ); - - if ( ! file_exists( $keyfileFolderName ) ) { - - mkdir( $keyfileFolderName, 0750, true ); - + $info = pathinfo($basePath . '/' . $targetPath); + $keyfileFolderName = $view->getLocalFolder($info['dirname']); + + if (!file_exists($keyfileFolderName)) { + + mkdir($keyfileFolderName, 0750, true); + } } // try reusing key file if part file - if ( self::isPartialFilePath( $targetPath ) ) { - - $result = $view->file_put_contents( $basePath . '/' . self::fixPartialFilePath( $targetPath ) . '.key', $catfile ); - + if (self::isPartialFilePath($targetPath)) { + + $result = $view->file_put_contents($basePath . '/' . self::fixPartialFilePath($targetPath) . '.key', $catfile); + } else { - - $result = $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); - + + $result = $view->file_put_contents($basePath . '/' . $targetPath . '.key', $catfile); + } - + \OC_FileProxy::$enabled = $proxyStatus; - + return $result; - + } /** @@ -163,15 +172,16 @@ class Keymanager { * @return string File path without .part extension * @note this is needed for reusing keys */ - public static function fixPartialFilePath( $path ) { - + public static function fixPartialFilePath($path) + { + if (preg_match('/\.part$/', $path)) { $newLength = strlen($path) - 5; $fPath = substr($path, 0, $newLength); return $fPath; - + } else { return $path; @@ -185,19 +195,21 @@ class Keymanager { * @param string $path Path that may identify a .part file * @return bool */ - public static function isPartialFilePath( $path ) { - - if ( preg_match('/\.part$/', $path ) ) { - + public static function isPartialFilePath($path) + { + + if (preg_match('/\.part$/', $path)) { + return true; - + } else { - + return false; - + } } + /** * @brief retrieve keyfile for an encrypted file * @param \OC_FilesystemView $view @@ -208,227 +220,239 @@ class Keymanager { * @note The keyfile returned is asymmetrically encrypted. Decryption * of the keyfile must be performed by client code */ - public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) { + public static function getFileKey(\OC_FilesystemView $view, $userId, $filePath) + { // try reusing key file if part file - if ( self::isPartialFilePath( $filePath ) ) { - - $result = self::getFileKey( $view, $userId, self::fixPartialFilePath( $filePath ) ); - - if ( $result ) { - + if (self::isPartialFilePath($filePath)) { + + $result = self::getFileKey($view, $userId, self::fixPartialFilePath($filePath)); + + if ($result) { + return $result; - + } - + } $util = new Util($view, \OCP\User::getUser()); list($owner, $filename) = $util->getUidAndFilename($filePath); - $filePath_f = ltrim( $filename, '/' ); + $filePath_f = ltrim($filename, '/'); $keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key'; $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - - if ( $view->file_exists( $keyfilePath ) ) { - $result = $view->file_get_contents( $keyfilePath ); - + if ($view->file_exists($keyfilePath)) { + + $result = $view->file_get_contents($keyfilePath); + } else { - - $result = false; - + + $result = false; + } - + \OC_FileProxy::$enabled = $proxyStatus; - + return $result; - + } - + /** * @brief Delete a keyfile * - * @param OC_FilesystemView $view + * @param \OC_FilesystemView $view * @param string $userId username * @param string $path path of the file the key belongs to * @return bool Outcome of unlink operation * @note $path must be relative to data/user/files. e.g. mydoc.txt NOT * /data/admin/files/mydoc.txt */ - public static function deleteFileKey( \OC_FilesystemView $view, $userId, $path ) { - - $trimmed = ltrim( $path, '/' ); - $keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed; + public static function deleteFileKey(\OC_FilesystemView $view, $userId, $path) + { + + $trimmed = ltrim($path, '/'); + $keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed; $result = false; - if ( $view->is_dir($keyPath) ) { + if ($view->is_dir($keyPath)) { $result = $view->unlink($keyPath); - } else if ( $view->file_exists( $keyPath.'.key' ) ) { + } else if ($view->file_exists($keyPath . '.key')) { - $result = $view->unlink( $keyPath.'.key' ); + $result = $view->unlink($keyPath . '.key'); } - if ( !$result ) { - - \OC_Log::write( 'Encryption library', 'Could not delete keyfile; does not exist: "' . $keyPath, \OC_Log::ERROR ); + if (!$result) { + + \OC_Log::write('Encryption library', 'Could not delete keyfile; does not exist: "' . $keyPath, \OC_Log::ERROR); } return $result; - + } - + /** * @brief store private key from the user - * @param string key + * @param string $key * @return bool * @note Encryption of the private key must be performed by client code * as no encryption takes place here */ - public static function setPrivateKey( $key ) { - + public static function setPrivateKey($key) + { + $user = \OCP\User::getUser(); - - $view = new \OC_FilesystemView( '/' . $user . '/files_encryption' ); + + $view = new \OC_FilesystemView('/' . $user . '/files_encryption'); $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - - if ( !$view->file_exists( '' ) ) $view->mkdir( '' ); - - $result = $view->file_put_contents( $user . '.private.key', $key ); - + + if (!$view->file_exists('')) $view->mkdir(''); + + $result = $view->file_put_contents($user . '.private.key', $key); + \OC_FileProxy::$enabled = $proxyStatus; return $result; - + } - + /** * @brief store private keys from the user * - * @param string privatekey - * @param string publickey + * @param string $privatekey + * @param string $publickey * @return bool true/false */ - public static function setUserKeys($privatekey, $publickey) { - - return ( self::setPrivateKey( $privatekey ) && self::setPublicKey( $publickey ) ); - + public static function setUserKeys($privatekey, $publickey) + { + + return (self::setPrivateKey($privatekey) && self::setPublicKey($publickey)); + } - + /** * @brief store public key of the user * - * @param string key + * @param string $key * @return bool true/false */ - public static function setPublicKey( $key ) { - - $view = new \OC_FilesystemView( '/public-keys' ); + public static function setPublicKey($key) + { + + $view = new \OC_FilesystemView('/public-keys'); $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - - if ( !$view->file_exists( '' ) ) $view->mkdir( '' ); - - $result = $view->file_put_contents( \OCP\User::getUser() . '.public.key', $key ); - + + if (!$view->file_exists('')) $view->mkdir(''); + + $result = $view->file_put_contents(\OCP\User::getUser() . '.public.key', $key); + \OC_FileProxy::$enabled = $proxyStatus; return $result; - + } - + /** * @brief store share key * + * @param \OC_FilesystemView $view * @param string $path relative path of the file, including filename - * @param string $key - * @param null $view - * @param string $dbClassName + * @param $userId + * @param $shareKey + * @internal param string $key + * @internal param string $dbClassName * @return bool true/false * @note The keyfile is not encrypted here. Client code must * asymmetrically encrypt the keyfile before passing it to this method */ - public static function setShareKey( \OC_FilesystemView $view, $path, $userId, $shareKey ) { + public static function setShareKey(\OC_FilesystemView $view, $path, $userId, $shareKey) + { // Here we need the currently logged in user, while userId can be a different user - $util = new Util( $view, \OCP\User::getUser() ); + $util = new Util($view, \OCP\User::getUser()); - list( $owner, $filename ) = $util->getUidAndFilename( $path ); + list($owner, $filename) = $util->getUidAndFilename($path); $basePath = '/' . $owner . '/files_encryption/share-keys'; - - $shareKeyPath = self::keySetPreparation( $view, $filename, $basePath, $owner ); + + $shareKeyPath = self::keySetPreparation($view, $filename, $basePath, $owner); // try reusing key file if part file - if(self::isPartialFilePath($shareKeyPath)) { - + if (self::isPartialFilePath($shareKeyPath)) { + $writePath = $basePath . '/' . self::fixPartialFilePath($shareKeyPath) . '.' . $userId . '.shareKey'; - + } else { - + $writePath = $basePath . '/' . $shareKeyPath . '.' . $userId . '.shareKey'; - + } $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $result = $view->file_put_contents( $writePath, $shareKey ); + $result = $view->file_put_contents($writePath, $shareKey); \OC_FileProxy::$enabled = $proxyStatus; - if ( - is_int( $result ) + if ( + is_int($result) && $result > 0 ) { - + return true; - + } else { - + return false; - + } - + } - + /** * @brief store multiple share keys for a single file + * @param \OC_FilesystemView $view + * @param $path + * @param array $shareKeys * @return bool */ - public static function setShareKeys( \OC_FilesystemView $view, $path, array $shareKeys ) { + public static function setShareKeys(\OC_FilesystemView $view, $path, array $shareKeys) + { // $shareKeys must be an array with the following format: // [userId] => [encrypted key] - + $result = true; - - foreach ( $shareKeys as $userId => $shareKey ) { - - if ( ! self::setShareKey( $view, $path, $userId, $shareKey ) ) { - + + foreach ($shareKeys as $userId => $shareKey) { + + if (!self::setShareKey($view, $path, $userId, $shareKey)) { + // If any of the keys are not set, flag false $result = false; - + } - + } - + // Returns false if any of the keys weren't set return $result; - + } - + /** * @brief retrieve shareKey for an encrypted file * @param \OC_FilesystemView $view @@ -439,59 +463,61 @@ class Keymanager { * @note The sharekey returned is encrypted. Decryption * of the keyfile must be performed by client code */ - public static function getShareKey( \OC_FilesystemView $view, $userId, $filePath ) { + public static function getShareKey(\OC_FilesystemView $view, $userId, $filePath) + { // try reusing key file if part file - if(self::isPartialFilePath($filePath)) { - + if (self::isPartialFilePath($filePath)) { + $result = self::getShareKey($view, $userId, self::fixPartialFilePath($filePath)); - - if($result) { - + + if ($result) { + return $result; - + } - + } $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; //here we need the currently logged in user, while userId can be a different user - $util = new Util( $view, \OCP\User::getUser() ); + $util = new Util($view, \OCP\User::getUser()); list($owner, $filename) = $util->getUidAndFilename($filePath); $shareKeyPath = \OC\Files\Filesystem::normalizePath('/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey'); - if ( $view->file_exists( $shareKeyPath ) ) { - - $result = $view->file_get_contents( $shareKeyPath ); - + if ($view->file_exists($shareKeyPath)) { + + $result = $view->file_get_contents($shareKeyPath); + } else { - + $result = false; - + } - + \OC_FileProxy::$enabled = $proxyStatus; - + return $result; - + } /** * @brief delete all share keys of a given file * @param \OC_FilesystemView $view - * @param type $userId owner of the file - * @param type $filePath path to the file, relative to the owners file dir + * @param string $userId owner of the file + * @param string $filePath path to the file, relative to the owners file dir */ - public static function delAllShareKeys(\OC_FilesystemView $view, $userId, $filePath) { - - if ($view->is_dir($userId.'/files/'.$filePath)) { - $view->unlink($userId.'/files_encryption/share-keys/'.$filePath); + public static function delAllShareKeys(\OC_FilesystemView $view, $userId, $filePath) + { + + if ($view->is_dir($userId . '/files/' . $filePath)) { + $view->unlink($userId . '/files_encryption/share-keys/' . $filePath); } else { - $localKeyPath = $view->getLocalFile($userId.'/files_encryption/share-keys/'.$filePath); - $matches = glob(preg_quote($localKeyPath).'*.shareKey'); + $localKeyPath = $view->getLocalFile($userId . '/files_encryption/share-keys/' . $filePath); + $matches = glob(preg_quote($localKeyPath) . '*.shareKey'); foreach ($matches as $ma) { unlink($ma); } @@ -501,13 +527,14 @@ class Keymanager { /** * @brief Delete a single user's shareKey for a single file */ - public static function delShareKey( \OC_FilesystemView $view, $userIds, $filePath ) { + public static function delShareKey(\OC_FilesystemView $view, $userIds, $filePath) + { - $proxyStatus = \OC_FileProxy::$enabled; + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; //here we need the currently logged in user, while userId can be a different user - $util = new Util( $view, \OCP\User::getUser() ); + $util = new Util($view, \OCP\User::getUser()); list($owner, $filename) = $util->getUidAndFilename($filePath); @@ -515,7 +542,7 @@ class Keymanager { $result = false; - if ( $view->is_dir($shareKeyPath) ) { + if ($view->is_dir($shareKeyPath)) { $localPath = \OC_Filesystem::normalizePath($view->getLocalFolder($shareKeyPath)); $result = self::recursiveDelShareKeys($localPath, $userIds); @@ -523,40 +550,42 @@ class Keymanager { } else { foreach ($userIds as $userId) { - $view->unlink($shareKeyPath.'.'.$userId.'.shareKey'); + $view->unlink($shareKeyPath . '.' . $userId . '.shareKey'); } $result = true; } - if ( ! $result ) { - - \OC_Log::write( 'Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath, \OC_Log::ERROR ); - + if (!$result) { + + \OC_Log::write('Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath, \OC_Log::ERROR); + } - + \OC_FileProxy::$enabled = $proxyStatus; - + return $result; - + } /** * @brief recursively delete share keys from given users * - * @param type $dir directory - * @param type $userIds user ids for which the share keys should be deleted + * @param string $dir directory + * @param array $userIds user ids for which the share keys should be deleted */ - private static function recursiveDelShareKeys($dir, $userIds) { + private static function recursiveDelShareKeys($dir, $userIds) + { foreach ($userIds as $userId) { - $completePath = $dir.'/.*'.'.'.$userId.'.shareKey'; - $matches = glob(preg_quote($dir).'/*'.preg_quote('.'.$userId.'.shareKey')); + $completePath = $dir . '/.*' . '.' . $userId . '.shareKey'; + $matches = glob(preg_quote($dir) . '/*' . preg_quote('.' . $userId . '.shareKey')); } - foreach ($matches as $ma) { + /** @var $matches array */ + foreach ($matches as $ma) { unlink($ma); } - $subdirs = $directories = glob(preg_quote($dir) . '/*' , GLOB_ONLYDIR); - foreach ( $subdirs as $subdir ) { + $subdirs = $directories = glob(preg_quote($dir) . '/*', GLOB_ONLYDIR); + foreach ($subdirs as $subdir) { self::recursiveDelShareKeys($subdir, $userIds); } return true; @@ -565,16 +594,17 @@ class Keymanager { /** * @brief Make preparations to vars and filesystem for saving a keyfile */ - public static function keySetPreparation( \OC_FilesystemView $view, $path, $basePath, $userId ) { - - $targetPath = ltrim( $path, '/' ); - - $path_parts = pathinfo( $targetPath ); - + public static function keySetPreparation(\OC_FilesystemView $view, $path, $basePath, $userId) + { + + $targetPath = ltrim($path, '/'); + + $path_parts = pathinfo($targetPath); + // If the file resides within a subdirectory, create it - if ( - isset( $path_parts['dirname'] ) - && ! $view->file_exists( $basePath . '/' . $path_parts['dirname'] ) + if ( + isset($path_parts['dirname']) + && !$view->file_exists($basePath . '/' . $path_parts['dirname']) ) { $sub_dirs = explode(DIRECTORY_SEPARATOR, $basePath . '/' . $path_parts['dirname']); $dir = ''; @@ -585,41 +615,26 @@ class Keymanager { } } } - + return $targetPath; - - } - - /** - * @brief change password of private encryption key - * - * @param string $oldpasswd old password - * @param string $newpasswd new password - * @return bool true/false - */ - public static function changePasswd($oldpasswd, $newpasswd) { - - if ( \OCP\User::checkPassword(\OCP\User::getUser(), $newpasswd) ) { - return Crypt::changekeypasscode($oldpasswd, $newpasswd); - } - return false; - + } - + /** * @brief Fetch the legacy encryption key from user files - * @param string $login used to locate the legacy key - * @param string $passphrase used to decrypt the legacy key - * @return true / false + * @internal param string $login used to locate the legacy key + * @internal param string $passphrase used to decrypt the legacy key + * @return boolean * * if the key is left out, the default handeler will be used */ - public function getLegacyKey() { - + public function getLegacyKey() + { + $user = \OCP\User::getUser(); - $view = new \OC_FilesystemView( '/' . $user ); - return $view->file_get_contents( 'encryption.key' ); - + $view = new \OC_FilesystemView('/' . $user); + return $view->file_get_contents('encryption.key'); + } - + } \ No newline at end of file diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 1d60770b4d7..55ad882a8f9 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -1,41 +1,46 @@ . -* -*/ + * ownCloud + * + * @author Sam Tuke, Robin Appelman + * @copyright 2012 Sam Tuke samtuke@owncloud.com, Robin Appelman + * icewind1991@gmail.com + * + * 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 . + * + */ /** -* @brief Encryption proxy which handles filesystem operations before and after -* execution and encrypts, and handles keyfiles accordingly. Used for -* webui. -*/ + * @brief Encryption proxy which handles filesystem operations before and after + * execution and encrypts, and handles keyfiles accordingly. Used for + * webui. + */ namespace OCA\Encryption; -class Proxy extends \OC_FileProxy { +/** + * Class Proxy + * @package OCA\Encryption + */ +class Proxy extends \OC_FileProxy +{ private static $blackList = null; //mimetypes blacklisted from encryption - + private static $enableEncryption = null; - + /** * Check if a file requires encryption * @param string $path @@ -43,461 +48,481 @@ class Proxy extends \OC_FileProxy { * * Tests if server side encryption is enabled, and file is allowed by blacklists */ - private static function shouldEncrypt( $path ) { - - if ( is_null( self::$enableEncryption ) ) { - - if ( - \OCP\Config::getAppValue( 'files_encryption', 'enable_encryption', 'true' ) == 'true' - && Crypt::mode() == 'server' + private static function shouldEncrypt($path) + { + + if (is_null(self::$enableEncryption)) { + + if ( + \OCP\Config::getAppValue('files_encryption', 'enable_encryption', 'true') == 'true' + && Crypt::mode() == 'server' ) { - + self::$enableEncryption = true; - + } else { - + self::$enableEncryption = false; - + } - + } - - if ( !self::$enableEncryption ) { - + + if (!self::$enableEncryption) { + return false; - + } - - if ( is_null(self::$blackList ) ) { - - self::$blackList = explode(',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) ); - + + if (is_null(self::$blackList)) { + + self::$blackList = explode(',', \OCP\Config::getAppValue('files_encryption', 'type_blacklist', '')); + } - - if ( Crypt::isCatfileContent( $path ) ) { - + + if (Crypt::isCatfileContent($path)) { + return true; - + } - - $extension = substr( $path, strrpos( $path, '.' ) +1 ); - - if ( array_search( $extension, self::$blackList ) === false ) { - + + $extension = substr($path, strrpos($path, '.') + 1); + + if (array_search($extension, self::$blackList) === false) { + return true; - + } - + return false; } - - public function preFile_put_contents( $path, &$data ) { - if ( self::shouldEncrypt( $path ) ) { + /** + * @param $path + * @param $data + * @return bool + */ + public function preFile_put_contents($path, &$data) + { + + if (self::shouldEncrypt($path)) { // Stream put contents should have been converted to fopen - if ( !is_resource( $data ) ) { + if (!is_resource($data)) { $userId = \OCP\USER::getUser(); - $view = new \OC_FilesystemView( '/' ); - $util = new Util( $view, $userId ); - $session = new Session( $view ); + $view = new \OC_FilesystemView('/'); + $util = new Util($view, $userId); + $session = new Session($view); $privateKey = $session->getPrivateKey(); - $filePath = $util->stripUserFilesPath( $path ); + $filePath = $util->stripUserFilesPath($path); // Set the filesize for userland, before encrypting - $size = strlen( $data ); - + $size = strlen($data); + // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - + // Check if there is an existing key we can reuse - if ( $encKeyfile = Keymanager::getFileKey( $view, $userId, $filePath ) ) { - + if ($encKeyfile = Keymanager::getFileKey($view, $userId, $filePath)) { + // Fetch shareKey - $shareKey = Keymanager::getShareKey( $view, $userId, $filePath ); - + $shareKey = Keymanager::getShareKey($view, $userId, $filePath); + // Decrypt the keyfile - $plainKey = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); - + $plainKey = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + } else { - + // Make a new key $plainKey = Crypt::generateKey(); - + } - + // Encrypt data - $encData = Crypt::symmetricEncryptFileContent( $data, $plainKey ); - + $encData = Crypt::symmetricEncryptFileContent($data, $plainKey); + $sharingEnabled = \OCP\Share::isEnabled(); // if file exists try to get sharing users - if($view->file_exists($path)) { - $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $filePath, $userId ); + if ($view->file_exists($path)) { + $uniqueUserIds = $util->getSharingUsersArray($sharingEnabled, $filePath, $userId); } else { $uniqueUserIds[] = $userId; } // Fetch public keys for all users who will share the file - $publicKeys = Keymanager::getPublicKeys( $view, $uniqueUserIds ); + $publicKeys = Keymanager::getPublicKeys($view, $uniqueUserIds); // Encrypt plain keyfile to multiple sharefiles - $multiEncrypted = Crypt::multiKeyEncrypt( $plainKey, $publicKeys ); - + $multiEncrypted = Crypt::multiKeyEncrypt($plainKey, $publicKeys); + // Save sharekeys to user folders - Keymanager::setShareKeys( $view, $filePath, $multiEncrypted['keys'] ); - + Keymanager::setShareKeys($view, $filePath, $multiEncrypted['keys']); + // Set encrypted keyfile as common varname $encKey = $multiEncrypted['data']; - + // Save keyfile for newly encrypted file in parallel directory tree - Keymanager::setFileKey( $view, $filePath, $userId, $encKey ); + Keymanager::setFileKey($view, $filePath, $userId, $encKey); // Replace plain content with encrypted content by reference $data = $encData; - + // Update the file cache with file info - \OC\Files\Filesystem::putFileInfo( $filePath, array( 'encrypted'=>true, 'size' => strlen($size), 'unencrypted_size' => $size), '' ); + \OC\Files\Filesystem::putFileInfo($filePath, array('encrypted' => true, 'size' => strlen($size), 'unencrypted_size' => $size), ''); // Re-enable proxy - our work is done \OC_FileProxy::$enabled = $proxyStatus; - + } } return true; - + } - + /** * @param string $path Path of file from which has been read * @param string $data Data that has been read from file */ - public function postFile_get_contents( $path, $data ) { + public function postFile_get_contents($path, $data) + { + + // FIXME: $path for shared files is just /uid/files/Shared/filepath - // FIXME: $path for shared files is just /uid/files/Shared/filepath - $userId = \OCP\USER::getUser(); - $view = new \OC_FilesystemView( '/' ); - $util = new Util( $view, $userId ); - - $relPath = $util->stripUserFilesPath( $path ); - - + $view = new \OC_FilesystemView('/'); + $util = new Util($view, $userId); + + $relPath = $util->stripUserFilesPath($path); + + // TODO check for existing key file and reuse it if possible to avoid problems with versioning etc. // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // If data is a catfile - if ( - Crypt::mode() == 'server' - && Crypt::isCatfileContent( $data ) // TODO: Do we really need this check? Can't we assume it is properly encrypted? + // If data is a catfile + if ( + Crypt::mode() == 'server' + && Crypt::isCatfileContent($data) // TODO: Do we really need this check? Can't we assume it is properly encrypted? ) { - + // TODO: use get owner to find correct location of key files for shared files - $session = new Session( $view ); - $privateKey = $session->getPrivateKey( $userId ); - + $session = new Session($view); + $privateKey = $session->getPrivateKey($userId); + // Get the encrypted keyfile - $encKeyfile = Keymanager::getFileKey( $view, $userId, $relPath ); - + $encKeyfile = Keymanager::getFileKey($view, $userId, $relPath); + // Attempt to fetch the user's shareKey - $shareKey = Keymanager::getShareKey( $view, $userId, $relPath ); - + $shareKey = Keymanager::getShareKey($view, $userId, $relPath); + // Decrypt keyfile with shareKey - $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); - - $plainData = Crypt::symmetricDecryptFileContent( $data, $plainKeyfile ); + $plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + + $plainData = Crypt::symmetricDecryptFileContent($data, $plainKeyfile); } elseif ( - Crypt::mode() == 'server' - && isset( $_SESSION['legacyenckey'] ) - && Crypt::isEncryptedMeta( $path ) + Crypt::mode() == 'server' + && isset($_SESSION['legacyenckey']) + && Crypt::isEncryptedMeta($path) ) { - - $plainData = Crypt::legacyDecrypt( $data, $session->getLegacyKey() ); - + + $plainData = Crypt::legacyDecrypt($data, $session->getLegacyKey()); + } - + \OC_FileProxy::$enabled = $proxyStatus; - - if ( ! isset( $plainData ) ) { - + + if (!isset($plainData)) { + $plainData = $data; - + } - + return $plainData; - + } - + /** * @brief When a file is deleted, remove its keyfile also */ - public function preUnlink( $path ) { - + public function preUnlink($path) + { + // let the trashbin handle this - if ( \OCP\App::isEnabled('files_trashbin') ) { - return true; + if (\OCP\App::isEnabled('files_trashbin')) { + return true; } - + // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - - $view = new \OC_FilesystemView( '/' ); + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $view = new \OC_FilesystemView('/'); $userId = \OCP\USER::getUser(); - $util = new Util( $view, $userId ); + $util = new Util($view, $userId); // Format path to be relative to user files dir - $relPath = $util->stripUserFilesPath( $path ); + $relPath = $util->stripUserFilesPath($path); - list( $owner, $ownerPath ) = $util->getUidAndFilename( $relPath ); + list($owner, $ownerPath) = $util->getUidAndFilename($relPath); // Delete keyfile & shareKey so it isn't orphaned if ( - ! ( - Keymanager::deleteFileKey( $view, $owner, $ownerPath ) - && Keymanager::delAllShareKeys( $view, $owner, $ownerPath ) + !( + Keymanager::deleteFileKey($view, $owner, $ownerPath) + && Keymanager::delAllShareKeys($view, $owner, $ownerPath) ) ) { - - \OC_Log::write( 'Encryption library', 'Keyfile or shareKey could not be deleted for file "'.$ownerPath.'"', \OC_Log::ERROR ); - + + \OC_Log::write('Encryption library', 'Keyfile or shareKey could not be deleted for file "' . $ownerPath . '"', \OC_Log::ERROR); + } - + \OC_FileProxy::$enabled = $proxyStatus; - + // If we don't return true then file delete will fail; better // to leave orphaned keyfiles than to disallow file deletion return true; - + } /** - * @brief When a file is renamed, rename its keyfile also - * @return bool Result of rename() - * @note This is pre rather than post because using post didn't work - */ - public function postWrite( $path ) - { - $this->handleFile($path); + * @brief When a file is renamed, rename its keyfile also + * @param $path + * @return bool Result of rename() + * @note This is pre rather than post because using post didn't work + */ + public function postWrite($path) + { + $this->handleFile($path); - return true; - } + return true; + } + + /** + * @param $path + * @return bool + */ + public function postTouch($path) + { + $this->handleFile($path); - public function postTouch( $path ) - { - $this->handleFile($path); + return true; + } - return true; - } + /** + * @param $path + * @param $result + * @return resource + */ + public function postFopen($path, &$result) + { - public function postFopen( $path, &$result ){ + if (!$result) { - if ( !$result ) { - return $result; - + } - // Reformat path for use with OC_FSV - $path_split = explode( '/', $path ); - $path_f = implode( '/', array_slice( $path_split, 3 ) ); + // Reformat path for use with OC_FSV + $path_split = explode('/', $path); + $path_f = implode('/', array_slice($path_split, 3)); - // FIXME: handling for /userId/cache used by webdav for chunking. The cache chunks are NOT encrypted - if($path_split[2] == 'cache') { - return $result; - } + // FIXME: handling for /userId/cache used by webdav for chunking. The cache chunks are NOT encrypted + if ($path_split[2] == 'cache') { + return $result; + } // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - - $meta = stream_get_meta_data( $result ); - - $view = new \OC_FilesystemView( '' ); - - $util = new Util( $view, \OCP\USER::getUser()); - + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $meta = stream_get_meta_data($result); + + $view = new \OC_FilesystemView(''); + + $util = new Util($view, \OCP\USER::getUser()); + // If file is already encrypted, decrypt using crypto protocol - if ( - Crypt::mode() == 'server' - && $util->isEncryptedPath( $path ) + if ( + Crypt::mode() == 'server' + && $util->isEncryptedPath($path) ) { - + // Close the original encrypted file - fclose( $result ); - + fclose($result); + // Open the file using the crypto stream wrapper // protocol and let it do the decryption work instead - $result = fopen( 'crypt://' . $path_f, $meta['mode'] ); - - - } elseif ( - self::shouldEncrypt( $path ) - and $meta ['mode'] != 'r' - and $meta['mode'] != 'rb' + $result = fopen('crypt://' . $path_f, $meta['mode']); + + + } elseif ( + self::shouldEncrypt($path) + and $meta ['mode'] != 'r' + and $meta['mode'] != 'rb' ) { - // If the file is not yet encrypted, but should be - // encrypted when it's saved (it's not read only) - - // NOTE: this is the case for new files saved via WebDAV - -// if ( -// $view->file_exists( $path ) -// and $view->filesize( $path ) > 0 -// ) { -// $x = $view->file_get_contents( $path ); -// -// $tmp = tmpfile(); - -// // Make a temporary copy of the original file -// \OCP\Files::streamCopy( $result, $tmp ); -// -// // Close the original stream, we'll return another one -// fclose( $result ); -// -// $view->file_put_contents( $path_f, $tmp ); -// -// fclose( $tmp ); - -// } - - $result = fopen( 'crypt://'.$path_f, $meta['mode'] ); - + $result = fopen('crypt://' . $path_f, $meta['mode']); } - + // Re-enable the proxy \OC_FileProxy::$enabled = $proxyStatus; - + return $result; - + } - public function postGetMimeType( $path, $mime ) { + /** + * @param $path + * @param $mime + * @return string + */ + public function postGetMimeType($path, $mime) + { + + if (Crypt::isCatfileContent($path)) { + + $mime = \OCP\Files::getMimeType('crypt://' . $path, 'w'); - if ( Crypt::isCatfileContent( $path ) ) { - - $mime = \OCP\Files::getMimeType( 'crypt://' . $path, 'w' ); - } - + return $mime; - - } - public function postGetFileInfo( $path, $data ) { + } - // if path is a folder do nothing - if(is_array($data) && array_key_exists('size', $data)) { + /** + * @param $path + * @param $data + * @return array + */ + public function postGetFileInfo($path, $data) + { - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // if path is a folder do nothing + if (is_array($data) && array_key_exists('size', $data)) { - // get file size - $data['size'] = self::postFileSize($path, $data['size']); + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // Re-enable the proxy - \OC_FileProxy::$enabled = $proxyStatus; - } + // get file size + $data['size'] = self::postFileSize($path, $data['size']); - return $data; - } + // Re-enable the proxy + \OC_FileProxy::$enabled = $proxyStatus; + } - public function postStat($path, $data) - { - // check if file is encrypted - if (Crypt::isCatfileContent($path)) { + return $data; + } - // get file info from cache - $cached = \OC\Files\Filesystem::getFileInfo($path, ''); + /** + * @param $path + * @param $data + * @return mixed + */ + public function postStat($path, $data) + { + // check if file is encrypted + if (Crypt::isCatfileContent($path)) { - // set the real file size - $data['size'] = $cached['unencrypted_size']; - } + // get file info from cache + $cached = \OC\Files\Filesystem::getFileInfo($path, ''); - return $data; - } + // set the real file size + $data['size'] = $cached['unencrypted_size']; + } - public function postFileSize($path, $size) - { + return $data; + } - $view = new \OC_FilesystemView('/'); + /** + * @param $path + * @param $size + * @return bool + */ + public function postFileSize($path, $size) + { - // if path is a folder do nothing - if ($view->is_dir($path)) { - return $size; - } + $view = new \OC_FilesystemView('/'); - // Reformat path for use with OC_FSV - $path_split = explode('/', $path); - $path_f = implode('/', array_slice($path_split, 3)); + // if path is a folder do nothing + if ($view->is_dir($path)) { + return $size; + } - // if path is empty we cannot resolve anything - if(empty($path_f)) { - return $size; - } + // Reformat path for use with OC_FSV + $path_split = explode('/', $path); + $path_f = implode('/', array_slice($path_split, 3)); - // get file info from database/cache - $fileInfo = \OC\Files\Filesystem::getFileInfo($path_f); + // if path is empty we cannot resolve anything + if (empty($path_f)) { + return $size; + } - // if file is encrypted return real file size - if (is_array($fileInfo) && $fileInfo['encrypted'] === true) { - $size = $fileInfo['unencrypted_size']; - } else { - // self healing if file was removed from file cache - if(is_array($fileInfo)) { - $userId = \OCP\User::getUser(); - $util = new Util( $view, $userId ); - $fixSize = $util->getFileSize($path); - if($fixSize > 0) { - $size = $fixSize; + // get file info from database/cache + $fileInfo = \OC\Files\Filesystem::getFileInfo($path_f); + + // if file is encrypted return real file size + if (is_array($fileInfo) && $fileInfo['encrypted'] === true) { + $size = $fileInfo['unencrypted_size']; + } else { + // self healing if file was removed from file cache + if (is_array($fileInfo)) { + $userId = \OCP\User::getUser(); + $util = new Util($view, $userId); + $fixSize = $util->getFileSize($path); + if ($fixSize > 0) { + $size = $fixSize; + + $fileInfo['encrypted'] = true; + $fileInfo['unencrypted_size'] = $size; + + // put file info + $view->putFileInfo($path_f, $fileInfo); + } + } + } + return $size; + } - $fileInfo['encrypted'] = true; - $fileInfo['unencrypted_size'] = $size; + /** + * @param $path + */ + public function handleFile($path) + { - // put file info - $view->putFileInfo( $path_f, $fileInfo ); - } - } - } - return $size; - } + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - public function handleFile($path) { + $view = new \OC_FilesystemView('/'); + $session = new Session($view); + $userId = \OCP\User::getUser(); + $util = new Util($view, $userId); - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // Reformat path for use with OC_FSV + $path_split = explode('/', $path); + $path_f = implode('/', array_slice($path_split, 3)); - $view = new \OC_FilesystemView('/'); - $session = new Session($view); - $userId = \OCP\User::getUser(); - $util = new Util( $view, $userId ); + // only if file is on 'files' folder fix file size and sharing + if ($path_split[2] == 'files' && $util->fixFileSize($path)) { - // Reformat path for use with OC_FSV - $path_split = explode( '/', $path ); - $path_f = implode( '/', array_slice( $path_split, 3 ) ); + // get sharing app state + $sharingEnabled = \OCP\Share::isEnabled(); - // only if file is on 'files' folder fix file size and sharing - if($path_split[2] == 'files' && $util->fixFileSize($path)) { + // get users + $usersSharing = $util->getSharingUsersArray($sharingEnabled, $path_f); - // get sharing app state - $sharingEnabled = \OCP\Share::isEnabled(); + // update sharing-keys + $util->setSharedFileKeyfiles($session, $usersSharing, $path_f); + } - // get users - $usersSharing = $util->getSharingUsersArray($sharingEnabled, $path_f); - - // update sharing-keys - $util->setSharedFileKeyfiles($session, $usersSharing, $path_f); - } - - \OC_FileProxy::$enabled = $proxyStatus; - } - } + \OC_FileProxy::$enabled = $proxyStatus; + } +} diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index 8d604dc721e..8425cedd99f 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -26,73 +26,75 @@ namespace OCA\Encryption; * Class for handling encryption related session data */ -class Session { +class Session +{ private $view; - + /** * @brief if session is started, check if ownCloud key pair is set up, if not create it - * - * The ownCloud key pair is used to allow public link sharing even if encryption is enabled + * @param \OC_FilesystemView $view + * + * @note The ownCloud key pair is used to allow public link sharing even if encryption is enabled */ - public function __construct( $view ) { - + public function __construct($view) + { + $this->view = $view; + if (!$this->view->is_dir('owncloud_private_key')) { + + $this->view->mkdir('owncloud_private_key'); - if ( ! $this->view->is_dir( 'owncloud_private_key' ) ) { - - $this->view->mkdir( 'owncloud_private_key' ); - } $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); if ($publicShareKeyId === null) { - $publicShareKeyId = 'pubShare_'.substr(md5(time()),0,8); + $publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8); \OC_Appconfig::setValue('files_encryption', 'publicShareKeyId', $publicShareKeyId); } - - if ( - ! $this->view->file_exists( "/public-keys/".$publicShareKeyId.".public.key" ) - || ! $this->view->file_exists( "/owncloud_private_key/".$publicShareKeyId.".private.key" ) + + if ( + !$this->view->file_exists("/public-keys/" . $publicShareKeyId . ".public.key") + || !$this->view->file_exists("/owncloud_private_key/" . $publicShareKeyId . ".private.key") ) { - - $keypair = Crypt::createKeypair(); - - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - - // Save public key - - if (!$view->is_dir('/public-keys')) { - $view->mkdir('/public-keys'); - } - - $this->view->file_put_contents( '/public-keys/'.$publicShareKeyId.'.public.key', $keypair['publicKey'] ); - - // Encrypt private key empthy passphrase - $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], '' ); - - // Save private key - $this->view->file_put_contents( '/owncloud_private_key/'.$publicShareKeyId.'.private.key', $encryptedPrivateKey ); - + + $keypair = Crypt::createKeypair(); + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + // Save public key + + if (!$view->is_dir('/public-keys')) { + $view->mkdir('/public-keys'); + } + + $this->view->file_put_contents('/public-keys/' . $publicShareKeyId . '.public.key', $keypair['publicKey']); + + // Encrypt private key empthy passphrase + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], ''); + + // Save private key + $this->view->file_put_contents('/owncloud_private_key/' . $publicShareKeyId . '.private.key', $encryptedPrivateKey); + \OC_FileProxy::$enabled = $proxyStatus; - + } - if(\OCP\USER::getUser() === false) { - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + if (\OCP\USER::getUser() === false) { + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - $encryptedKey = $this->view->file_get_contents( '/owncloud_private_key/'.$publicShareKeyId.'.private.key' ); - $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, '' ); - $this->setPrivateKey($privateKey); + $encryptedKey = $this->view->file_get_contents('/owncloud_private_key/' . $publicShareKeyId . '.private.key'); + $privateKey = Crypt::symmetricDecryptFileContent($encryptedKey, ''); + $this->setPrivateKey($privateKey); - \OC_FileProxy::$enabled = $proxyStatus; - } + \OC_FileProxy::$enabled = $proxyStatus; + } } /** @@ -100,71 +102,72 @@ class Session { * @param string $privateKey * @return bool */ - public function setPrivateKey( $privateKey ) { - + public function setPrivateKey($privateKey) + { + $_SESSION['privateKey'] = $privateKey; - + return true; - + } - + /** * @brief Gets user private key from session * @returns string $privateKey The user's plaintext private key * */ - public function getPrivateKey() { - - if ( - isset( $_SESSION['privateKey'] ) - && !empty( $_SESSION['privateKey'] ) + public function getPrivateKey() + { + + if ( + isset($_SESSION['privateKey']) + && !empty($_SESSION['privateKey']) ) { - + return $_SESSION['privateKey']; - + } else { - + return false; - + } - + } - + /** * @brief Sets user legacy key to session + * @param $legacyKey * @return bool - * */ - public function setLegacyKey( $legacyKey ) { - - if ( $_SESSION['legacyKey'] = $legacyKey ) { - - return true; - - } - + public function setLegacyKey($legacyKey) + { + + $_SESSION['legacyKey'] = $legacyKey; + + return true; } - + /** * @brief Gets user legacy key from session * @returns string $legacyKey The user's plaintext legacy key * */ - public function getLegacyKey() { - - if ( - isset( $_SESSION['legacyKey'] ) - && !empty( $_SESSION['legacyKey'] ) + public function getLegacyKey() + { + + if ( + isset($_SESSION['legacyKey']) + && !empty($_SESSION['legacyKey']) ) { - + return $_SESSION['legacyKey']; - + } else { - + return false; - + } - + } } \ No newline at end of file diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index ab967835082..31546a2cc50 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -3,7 +3,7 @@ * ownCloud * * @author Robin Appelman - * @copyright 2012 Sam Tuke , 2011 Robin Appelman + * @copyright 2012 Sam Tuke , 2011 Robin Appelman * * * This library is free software; you can redistribute it and/or @@ -32,30 +32,31 @@ namespace OCA\Encryption; /** * @brief Provides 'crypt://' stream wrapper protocol. - * @note We use a stream wrapper because it is the most secure way to handle + * @note We use a stream wrapper because it is the most secure way to handle * decrypted content transfers. There is no safe way to decrypt the entire file * somewhere on the server, so we have to encrypt and decrypt blocks on the fly. * @note Paths used with this protocol MUST BE RELATIVE. Use URLs like: - * crypt://filename, or crypt://subdirectory/filename, NOT - * crypt:///home/user/owncloud/data. Otherwise keyfiles will be put in - * [owncloud]/data/user/files_encryption/keyfiles/home/user/owncloud/data and + * crypt://filename, or crypt://subdirectory/filename, NOT + * crypt:///home/user/owncloud/data. Otherwise keyfiles will be put in + * [owncloud]/data/user/files_encryption/keyfiles/home/user/owncloud/data and * will not be accessible to other methods. - * @note Data read and written must always be 8192 bytes long, as this is the - * buffer size used internally by PHP. The encryption process makes the input - * data longer, and input is chunked into smaller pieces in order to result in + * @note Data read and written must always be 8192 bytes long, as this is the + * buffer size used internally by PHP. The encryption process makes the input + * data longer, and input is chunked into smaller pieces in order to result in * a 8192 encrypted block size. - * @note When files are deleted via webdav, or when they are updated and the - * previous version deleted, this is handled by OC\Files\View, and thus the + * @note When files are deleted via webdav, or when they are updated and the + * previous version deleted, this is handled by OC\Files\View, and thus the * encryption proxies are used and keyfiles deleted. */ -class Stream { +class Stream +{ public static $sourceStreams = array(); + private $plainKey; + private $encKeyfiles; - // TODO: make all below properties private again once unit testing is - // configured correctly - public $rawPath; // The raw path relative to the data dir - public $relPath; // rel path to users file dir + private $rawPath; // The raw path relative to the data dir + private $relPath; // rel path to users file dir private $userId; private $handle; // Resource returned by fopen private $path; @@ -63,226 +64,238 @@ class Stream { private $meta = array(); // Header / meta for source stream private $count; private $writeCache; - public $size; - public $unencryptedSize; + private $size; + private $unencryptedSize; private $publicKey; private $keyfile; private $encKeyfile; private static $view; // a fsview object set to user dir private $rootView; // a fsview object set to '/' - public function stream_open( $path, $mode, $options, &$opened_path ) { + /** + * @param $path + * @param $mode + * @param $options + * @param $opened_path + * @return bool + */ + public function stream_open($path, $mode, $options, &$opened_path) + { - if ( ! isset( $this->rootView ) ) { - $this->rootView = new \OC_FilesystemView( '/' ); + if (!isset($this->rootView)) { + $this->rootView = new \OC_FilesystemView('/'); } - $util = new Util( $this->rootView, \OCP\USER::getUser()); + $util = new Util($this->rootView, \OCP\USER::getUser()); - $this->userId = $util->getUserId(); + $this->userId = $util->getUserId(); + + // Strip identifier text from path, this gives us the path relative to data//files + $this->relPath = \OC\Files\Filesystem::normalizePath(str_replace('crypt://', '', $path)); - // Strip identifier text from path, this gives us the path relative to data//files - $this->relPath = \OC\Files\Filesystem::normalizePath(str_replace( 'crypt://', '', $path )); - // rawPath is relative to the data directory $this->rawPath = $util->getUserFilesDir() . $this->relPath; - + if ( - dirname( $this->rawPath ) == 'streams' - and isset( self::$sourceStreams[basename( $this->rawPath )] ) + dirname($this->rawPath) == 'streams' + and isset(self::$sourceStreams[basename($this->rawPath)]) ) { - + // Is this just for unit testing purposes? - $this->handle = self::$sourceStreams[basename( $this->rawPath )]['stream']; + $this->handle = self::$sourceStreams[basename($this->rawPath)]['stream']; - $this->path = self::$sourceStreams[basename( $this->rawPath )]['path']; + $this->path = self::$sourceStreams[basename($this->rawPath)]['path']; - $this->size = self::$sourceStreams[basename( $this->rawPath )]['size']; + $this->size = self::$sourceStreams[basename($this->rawPath)]['size']; } else { - // Disable fileproxies so we can get the file size and open the source file without recursive encryption - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // Disable fileproxies so we can get the file size and open the source file without recursive encryption + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - if ( - $mode == 'w' - or $mode == 'w+' - or $mode == 'wb' - or $mode == 'wb+' + if ( + $mode == 'w' + or $mode == 'w+' + 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; + $this->unencryptedSize = 0; } else { - - $this->size = $this->rootView->filesize( $this->rawPath, $mode ); - - //$this->size = filesize( $this->rawPath ); - + + $this->size = $this->rootView->filesize($this->rawPath, $mode); + } - //$this->handle = fopen( $this->rawPath, $mode ); - - $this->handle = $this->rootView->fopen( $this->rawPath, $mode ); - + $this->handle = $this->rootView->fopen($this->rawPath, $mode); + \OC_FileProxy::$enabled = $proxyStatus; - if ( ! is_resource( $this->handle ) ) { + if (!is_resource($this->handle)) { - \OCP\Util::writeLog( 'files_encryption', 'failed to open file "' . $this->rawPath . '"', \OCP\Util::ERROR ); + \OCP\Util::writeLog('files_encryption', 'failed to open file "' . $this->rawPath . '"', \OCP\Util::ERROR); } else { - - $this->meta = stream_get_meta_data( $this->handle ); - + + $this->meta = stream_get_meta_data($this->handle); + } } - return is_resource( $this->handle ); + return is_resource($this->handle); } - - public function stream_seek( $offset, $whence = SEEK_SET ) { - + + /** + * @param $offset + * @param int $whence + */ + public function stream_seek($offset, $whence = SEEK_SET) + { + $this->flush(); - - fseek( $this->handle, $offset, $whence ); - + + fseek($this->handle, $offset, $whence); + } - - public function stream_tell() { + + /** + * @return int + */ + public function stream_tell() + { return ftell($this->handle); } - - public function stream_read( $count ) { - + + /** + * @param $count + * @return bool|string + * @throws \Exception + */ + public function stream_read($count) + { + $this->writeCache = ''; - if ( $count != 8192 ) { - + if ($count != 8192) { + // $count will always be 8192 https://bugs.php.net/bug.php?id=21641 // This makes this function a lot simpler, but will break this class if the above 'bug' gets 'fixed' - \OCP\Util::writeLog( 'files_encryption', 'PHP "bug" 21641 no longer holds, decryption system requires refactoring', \OCP\Util::FATAL ); + \OCP\Util::writeLog('files_encryption', 'PHP "bug" 21641 no longer holds, decryption system requires refactoring', \OCP\Util::FATAL); die(); } -// $pos = ftell( $this->handle ); -// // Get the data from the file handle - $data = fread( $this->handle, 8192 ); - + $data = fread($this->handle, 8192); + $result = ''; - - if ( strlen( $data ) ) { - - if ( ! $this->getKey() ) { - + + if (strlen($data)) { + + if (!$this->getKey()) { + // Error! We don't have a key to decrypt the file with - throw new \Exception( 'Encryption key not found for "' . $this->rawPath . '" during attempted read via stream' ); - + throw new \Exception('Encryption key not found for "' . $this->rawPath . '" during attempted read via stream'); + } - + // Decrypt data - $result = Crypt::symmetricDecryptFileContent( $data, $this->plainKey ); - - } + $result = Crypt::symmetricDecryptFileContent($data, $this->plainKey); -// $length = $this->size - $pos; -// -// if ( $length < 8192 ) { -// -// $result = substr( $result, 0, $length ); -// -// } + } return $result; } - + /** * @brief Encrypt and pad data ready for writing to disk * @param string $plainData data to be encrypted * @param string $key key to use for encryption - * @return encrypted data on success, false on failure + * @return string encrypted data on success, false on failure */ - public function preWriteEncrypt( $plainData, $key ) { - + public function preWriteEncrypt($plainData, $key) + { + // Encrypt data to 'catfile', which includes IV - if ( $encrypted = Crypt::symmetricEncryptFileContent( $plainData, $key ) ) { - - return $encrypted; - + if ($encrypted = Crypt::symmetricEncryptFileContent($plainData, $key)) { + + return $encrypted; + } else { - + return false; - + } - + } - + /** * @brief Fetch the plain encryption key for the file and set it as plainKey property - * @param bool $generate if true, a new key will be generated if none can be found + * @internal param bool $generate if true, a new key will be generated if none can be found * @return bool true on key found and set, false on key not found and new key generated and set */ - public function getKey() { - + public function getKey() + { + // Check if key is already set - if ( isset( $this->plainKey ) && isset( $this->encKeyfile ) ) { - + if (isset($this->plainKey) && isset($this->encKeyfile)) { + return true; - + } - + // Fetch and decrypt keyfile - // Fetch existing keyfile - $this->encKeyfile = Keymanager::getFileKey( $this->rootView, $this->userId, $this->relPath ); + // Fetch existing keyfile + $this->encKeyfile = Keymanager::getFileKey($this->rootView, $this->userId, $this->relPath); // If a keyfile already exists - if ( $this->encKeyfile ) { + if ($this->encKeyfile) { $this->setUserProperty(); - - $session = new Session( $this->rootView ); - - $privateKey = $session->getPrivateKey( $this->userId ); - - $shareKey = Keymanager::getShareKey( $this->rootView, $this->userId, $this->relPath ); - - $this->plainKey = Crypt::multiKeyDecrypt( $this->encKeyfile, $shareKey, $privateKey ); - + + $session = new Session($this->rootView); + + $privateKey = $session->getPrivateKey($this->userId); + + $shareKey = Keymanager::getShareKey($this->rootView, $this->userId, $this->relPath); + + $this->plainKey = Crypt::multiKeyDecrypt($this->encKeyfile, $shareKey, $privateKey); + return true; - + } else { - + return false; - + } - + } - - public function setUserProperty() { - + + public function setUserProperty() + { + // Only get the user again if it isn't already set - if ( empty( $this->userId ) ) { - + if (empty($this->userId)) { + // TODO: Move this user call out of here - it belongs // elsewhere $this->userId = \OCP\User::getUser(); - + } - + // TODO: Add a method for getting the user in case OCP\User:: // getUser() doesn't work (can that scenario ever occur?) - + } - + /** * @brief Handle plain data from the stream, and write it in 8192 byte blocks * @param string $data data to be written to disk @@ -292,89 +305,64 @@ class Stream { * @note Padding is added to each encrypted block to ensure that the resulting block is exactly 8192 bytes. This is removed during stream_read * @note PHP automatically updates the file pointer after writing data to reflect it's length. There is generally no need to update the poitner manually using fseek */ - public function stream_write( $data ) { - + public function stream_write($data) + { + // Disable the file proxies so that encryption is not // automatically attempted when the file is written to disk - // we are handling that separately here and we don't want to // get into an infinite loop - $proxyStatus = \OC_FileProxy::$enabled; + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - + // Get the length of the unencrypted data that we are handling - $length = strlen( $data ); - + $length = strlen($data); + // So far this round, no data has been written $written = 0; - + // Find out where we are up to in the writing of data to the // file - $pointer = ftell( $this->handle ); - + $pointer = ftell($this->handle); + // Make sure the userId is set $this->setUserProperty(); - + // Get / generate the keyfile for the file we're handling // If we're writing a new file (not overwriting an existing // one), save the newly generated keyfile - if ( ! $this->getKey() ) { - + if (!$this->getKey()) { + $this->plainKey = Crypt::generateKey(); - + } - - + // If extra data is left over from the last round, make sure it // is integrated into the next 6126 / 8192 block - if ( $this->writeCache ) { - + if ($this->writeCache) { + // Concat writeCache to start of $data $data = $this->writeCache . $data; - + // Clear the write cache, ready for resuse - it has been // flushed and its old contents processed $this->writeCache = ''; } -// -// // Make sure we always start on a block start - if ( 0 != ( $pointer % 8192 ) ) { - // if the current position of - // file indicator is not aligned to a 8192 byte block, fix it - // so that it is - -// fseek( $this->handle, - ( $pointer % 8192 ), SEEK_CUR ); -// -// $pointer = ftell( $this->handle ); -// -// $unencryptedNewBlock = fread( $this->handle, 8192 ); -// -// fseek( $this->handle, - ( $currentPos % 8192 ), SEEK_CUR ); -// -// $block = Crypt::symmetricDecryptFileContent( $unencryptedNewBlock, $this->plainKey ); -// -// $x = substr( $block, 0, $currentPos % 8192 ); -// -// $data = $x . $data; -// -// fseek( $this->handle, - ( $currentPos % 8192 ), SEEK_CUR ); -// - } -// $currentPos = ftell( $this->handle ); - -// // While there still remains somed data to be processed & written - while( strlen( $data ) > 0 ) { - -// // Remaining length for this iteration, not of the -// // entire file (may be greater than 8192 bytes) -// $remainingLength = strlen( $data ); -// -// // If data remaining to be written is less than the -// // size of 1 6126 byte block - if ( strlen( $data ) < 6126 ) { - + + // While there still remains somed data to be processed & written + while (strlen($data) > 0) { + + // Remaining length for this iteration, not of the + // entire file (may be greater than 8192 bytes) + $remainingLength = strlen( $data ); + + // If data remaining to be written is less than the + // size of 1 6126 byte block + if (strlen($data) < 6126) { + // Set writeCache to contents of $data // The writeCache will be carried over to the // next write round, and added to the start of @@ -387,148 +375,174 @@ class Stream { // Clear $data ready for next round $data = ''; - + } else { - + // Read the chunk from the start of $data - $chunk = substr( $data, 0, 6126 ); - - $encrypted = $this->preWriteEncrypt( $chunk, $this->plainKey ); - + $chunk = substr($data, 0, 6126); + + $encrypted = $this->preWriteEncrypt($chunk, $this->plainKey); + // Write the data chunk to disk. This will be // attended to the last data chunk if the file // being handled totals more than 6126 bytes - fwrite( $this->handle, $encrypted ); - - $writtenLen = strlen( $encrypted ); - //fseek( $this->handle, $writtenLen, SEEK_CUR ); + fwrite($this->handle, $encrypted); + + $writtenLen = strlen($encrypted); // Remove the chunk we just processed from // $data, leaving only unprocessed data in $data // var, for handling on the next round - $data = substr( $data, 6126 ); + $data = substr($data, 6126); } - + } - - $this->size = max( $this->size, $pointer + $length ); - $this->unencryptedSize += $length; - \OC_FileProxy::$enabled = $proxyStatus; + $this->size = max($this->size, $pointer + $length); + $this->unencryptedSize += $length; + + \OC_FileProxy::$enabled = $proxyStatus; return $length; } - public function stream_set_option( $option, $arg1, $arg2 ) { - switch($option) { + /** + * @param $option + * @param $arg1 + * @param $arg2 + */ + public function stream_set_option($option, $arg1, $arg2) + { + switch ($option) { case STREAM_OPTION_BLOCKING: - stream_set_blocking( $this->handle, $arg1 ); + stream_set_blocking($this->handle, $arg1); break; case STREAM_OPTION_READ_TIMEOUT: - stream_set_timeout( $this->handle, $arg1, $arg2 ); + stream_set_timeout($this->handle, $arg1, $arg2); break; case STREAM_OPTION_WRITE_BUFFER: - stream_set_write_buffer( $this->handle, $arg1, $arg2 ); + stream_set_write_buffer($this->handle, $arg1, $arg2); } } - public function stream_stat() { + /** + * @return array + */ + public function stream_stat() + { return fstat($this->handle); } - - public function stream_lock( $mode ) { - flock( $this->handle, $mode ); + + /** + * @param $mode + */ + public function stream_lock($mode) + { + flock($this->handle, $mode); } - - public function stream_flush() { - - return fflush( $this->handle ); + + /** + * @return bool + */ + public function stream_flush() + { + + return fflush($this->handle); // Not a typo: http://php.net/manual/en/function.fflush.php - + } - public function stream_eof() { + /** + * @return bool + */ + public function stream_eof() + { return feof($this->handle); } - private function flush() { - - if ( $this->writeCache ) { - + private function flush() + { + + if ($this->writeCache) { + // Set keyfile property for file in question $this->getKey(); - - $encrypted = $this->preWriteEncrypt( $this->writeCache, $this->plainKey ); - - fwrite( $this->handle, $encrypted ); - + + $encrypted = $this->preWriteEncrypt($this->writeCache, $this->plainKey); + + fwrite($this->handle, $encrypted); + $this->writeCache = ''; - + } - + } - public function stream_close() { + /** + * @return bool + */ + public function stream_close() + { + + $this->flush(); - $this->flush(); - - if ( - $this->meta['mode']!='r' - and $this->meta['mode']!='rb' - and $this->size > 0 + if ( + $this->meta['mode'] != 'r' + and $this->meta['mode'] != 'rb' + and $this->size > 0 ) { - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // Fetch user's public key - $this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId ); + // Fetch user's public key + $this->publicKey = Keymanager::getPublicKey($this->rootView, $this->userId); - // Check if OC sharing api is enabled - $sharingEnabled = \OCP\Share::isEnabled(); + // Check if OC sharing api is enabled + $sharingEnabled = \OCP\Share::isEnabled(); - $util = new Util( $this->rootView, $this->userId ); + $util = new Util($this->rootView, $this->userId); - // Get all users sharing the file includes current user - $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $this->relPath, $this->userId); + // Get all users sharing the file includes current user + $uniqueUserIds = $util->getSharingUsersArray($sharingEnabled, $this->relPath, $this->userId); - // Fetch public keys for all sharing users - $publicKeys = Keymanager::getPublicKeys( $this->rootView, $uniqueUserIds ); + // Fetch public keys for all sharing users + $publicKeys = Keymanager::getPublicKeys($this->rootView, $uniqueUserIds); - // Encrypt enc key for all sharing users - $this->encKeyfiles = Crypt::multiKeyEncrypt( $this->plainKey, $publicKeys ); + // Encrypt enc key for all sharing users + $this->encKeyfiles = Crypt::multiKeyEncrypt($this->plainKey, $publicKeys); - $view = new \OC_FilesystemView( '/' ); + $view = new \OC_FilesystemView('/'); - // Save the new encrypted file key - Keymanager::setFileKey( $this->rootView, $this->relPath, $this->userId, $this->encKeyfiles['data'] ); + // Save the new encrypted file key + Keymanager::setFileKey($this->rootView, $this->relPath, $this->userId, $this->encKeyfiles['data']); - // Save the sharekeys - Keymanager::setShareKeys( $view, $this->relPath, $this->encKeyfiles['keys'] ); + // Save the sharekeys + Keymanager::setShareKeys($view, $this->relPath, $this->encKeyfiles['keys']); - // get file info - $fileInfo = $view->getFileInfo($this->rawPath); - if(!is_array($fileInfo)) { - $fileInfo = array(); - } + // get file info + $fileInfo = $view->getFileInfo($this->rawPath); + if (!is_array($fileInfo)) { + $fileInfo = array(); + } - // Re-enable proxy - our work is done - \OC_FileProxy::$enabled = $proxyStatus; + // Re-enable proxy - our work is done + \OC_FileProxy::$enabled = $proxyStatus; - // set encryption data - $fileInfo['encrypted'] = true; - $fileInfo['size'] = $this->size; - $fileInfo['unencrypted_size'] = $this->unencryptedSize; + // set encryption data + $fileInfo['encrypted'] = true; + $fileInfo['size'] = $this->size; + $fileInfo['unencrypted_size'] = $this->unencryptedSize; - // set fileinfo - $view->putFileInfo( $this->rawPath, $fileInfo); + // set fileinfo + $view->putFileInfo($this->rawPath, $fileInfo); } - return fclose( $this->handle ); - + return fclose($this->handle); + } } diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 82f789c5202..9ba7b3b3a31 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -3,7 +3,7 @@ * ownCloud * * @author Sam Tuke, Frank Karlitschek - * @copyright 2012 Sam Tuke , + * @copyright 2012 Sam Tuke , * Frank Karlitschek * * This library is free software; you can redistribute it and/or @@ -55,49 +55,49 @@ namespace OCA\Encryption; * unused, likely to become obsolete shortly */ -class Util { - - +class Util +{ + // Web UI: - + //// DONE: files created via web ui are encrypted //// DONE: file created & encrypted via web ui are readable in web ui //// DONE: file created & encrypted via web ui are readable via webdav - - + + // WebDAV: - + //// DONE: new data filled files added via webdav get encrypted //// DONE: new data filled files added via webdav are readable via webdav //// DONE: reading unencrypted files when encryption is enabled works via //// webdav //// DONE: files created & encrypted via web ui are readable via webdav - - + + // Legacy support: - + //// DONE: add method to check if file is encrypted using new system //// DONE: add method to check if file is encrypted using old system //// DONE: add method to fetch legacy key //// DONE: add method to decrypt legacy encrypted data - - + + // Admin UI: - + //// DONE: changing user password also changes encryption passphrase - + //// TODO: add support for optional recovery in case of lost passphrase / keys //// TODO: add admin optional required long passphrase for users //// TODO: implement flag system to allow user to specify encryption by folder, subfolder, etc. - - + + // Integration testing: - + //// TODO: test new encryption with versioning //// DONE: test new encryption with sharing //// TODO: test new encryption with proxies - - + + private $view; // OC_FilesystemView object for filesystem operations private $userId; // ID of the currently logged-in user private $pwd; // User Password @@ -110,228 +110,246 @@ class Util { private $privateKeyPath; // Path to user's private key private $publicShareKeyId; private $recoveryKeyId; - private $isPublic; + private $isPublic; - public function __construct( \OC_FilesystemView $view, $userId, $client = false ) { + /** + * @param \OC_FilesystemView $view + * @param $userId + * @param bool $client + */ + public function __construct(\OC_FilesystemView $view, $userId, $client = false) + { $this->view = $view; $this->userId = $userId; $this->client = $client; - $this->isPublic = false; - - $this->publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); - $this->recoveryKeyId = \OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); - - // if we are anonymous/public - if($this->userId === false) { - $this->userId = $this->publicShareKeyId; - - // only handle for files_sharing app - if($GLOBALS['app'] === 'files_sharing') { - $this->userDir = '/' . $GLOBALS['fileOwner']; - $this->fileFolderName = 'files'; - $this->userFilesDir = '/' . $GLOBALS['fileOwner'] . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable? - $this->publicKeyDir = '/' . 'public-keys'; - $this->encryptionDir = '/' . $GLOBALS['fileOwner'] . '/' . 'files_encryption'; - $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; - $this->shareKeysPath = $this->encryptionDir . '/' . 'share-keys'; - $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key - $this->privateKeyPath = '/owncloud_private_key/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key - $this->isPublic = true; - } - - } else { - $this->userDir = '/' . $this->userId; - $this->fileFolderName = 'files'; - $this->userFilesDir = '/' . $this->userId . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable? - $this->publicKeyDir = '/' . 'public-keys'; - $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption'; - $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; - $this->shareKeysPath = $this->encryptionDir . '/' . 'share-keys'; - $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key - $this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key - } + $this->isPublic = false; + + $this->publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); + $this->recoveryKeyId = \OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); + + // if we are anonymous/public + if ($this->userId === false) { + $this->userId = $this->publicShareKeyId; + + // only handle for files_sharing app + if ($GLOBALS['app'] === 'files_sharing') { + $this->userDir = '/' . $GLOBALS['fileOwner']; + $this->fileFolderName = 'files'; + $this->userFilesDir = '/' . $GLOBALS['fileOwner'] . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable? + $this->publicKeyDir = '/' . 'public-keys'; + $this->encryptionDir = '/' . $GLOBALS['fileOwner'] . '/' . 'files_encryption'; + $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; + $this->shareKeysPath = $this->encryptionDir . '/' . 'share-keys'; + $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key + $this->privateKeyPath = '/owncloud_private_key/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key + $this->isPublic = true; + } + + } else { + $this->userDir = '/' . $this->userId; + $this->fileFolderName = 'files'; + $this->userFilesDir = '/' . $this->userId . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable? + $this->publicKeyDir = '/' . 'public-keys'; + $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption'; + $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; + $this->shareKeysPath = $this->encryptionDir . '/' . 'share-keys'; + $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key + $this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key + } } - - public function ready() { - - if( - ! $this->view->file_exists( $this->encryptionDir ) - or ! $this->view->file_exists( $this->keyfilesPath ) - or ! $this->view->file_exists( $this->shareKeysPath ) - or ! $this->view->file_exists( $this->publicKeyPath ) - or ! $this->view->file_exists( $this->privateKeyPath ) + + /** + * @return bool + */ + public function ready() + { + + if ( + !$this->view->file_exists($this->encryptionDir) + or !$this->view->file_exists($this->keyfilesPath) + or !$this->view->file_exists($this->shareKeysPath) + or !$this->view->file_exists($this->publicKeyPath) + or !$this->view->file_exists($this->privateKeyPath) ) { - + return false; - + } else { - + return true; - + } - + } - - /** - * @brief Sets up user folders and keys for serverside encryption - * @param $passphrase passphrase to encrypt server-stored private key with - */ - public function setupServerSide( $passphrase = null ) { - + + /** + * @brief Sets up user folders and keys for serverside encryption + * @param string $passphrase passphrase to encrypt server-stored private key with + */ + public function setupServerSide($passphrase = null) + { + // Set directories to check / create - $setUpDirs = array( + $setUpDirs = array( $this->userDir - , $this->userFilesDir - , $this->publicKeyDir - , $this->encryptionDir - , $this->keyfilesPath - , $this->shareKeysPath + , $this->userFilesDir + , $this->publicKeyDir + , $this->encryptionDir + , $this->keyfilesPath + , $this->shareKeysPath ); - + // Check / create all necessary dirs - foreach ( $setUpDirs as $dirPath ) { - - if( !$this->view->file_exists( $dirPath ) ) { - - $this->view->mkdir( $dirPath ); - + foreach ($setUpDirs as $dirPath) { + + if (!$this->view->file_exists($dirPath)) { + + $this->view->mkdir($dirPath); + } - + } - + // Create user keypair - if ( - ! $this->view->file_exists( $this->publicKeyPath ) - or ! $this->view->file_exists( $this->privateKeyPath ) + if ( + !$this->view->file_exists($this->publicKeyPath) + or !$this->view->file_exists($this->privateKeyPath) ) { - + // Generate keypair $keypair = Crypt::createKeypair(); - + \OC_FileProxy::$enabled = false; - + // Save public key - $this->view->file_put_contents( $this->publicKeyPath, $keypair['publicKey'] ); - + $this->view->file_put_contents($this->publicKeyPath, $keypair['publicKey']); + // Encrypt private key with user pwd as passphrase - $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], $passphrase ); - + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $passphrase); + // Save private key - $this->view->file_put_contents( $this->privateKeyPath, $encryptedPrivateKey ); - + $this->view->file_put_contents($this->privateKeyPath, $encryptedPrivateKey); + \OC_FileProxy::$enabled = true; - + } - + // If there's no record for this user's encryption preferences - if ( false === $this->recoveryEnabledForUser() ) { - + if (false === $this->recoveryEnabledForUser()) { + // create database configuration $sql = 'INSERT INTO `*PREFIX*encryption` (`uid`,`mode`,`recovery_enabled`) VALUES (?,?,?)'; - $args = array( $this->userId, 'server-side', 0); - $query = \OCP\DB::prepare( $sql ); - $query->execute( $args ); - + $args = array($this->userId, 'server-side', 0); + $query = \OCP\DB::prepare($sql); + $query->execute($args); + } - + return true; - + } - public function getPublicShareKeyId() { + /** + * @return string + */ + public function getPublicShareKeyId() + { return $this->publicShareKeyId; } - + /** * @brief Check whether pwd recovery is enabled for a given user - * @return 1 = yes, 0 = no, false = no record - * @note If records are not being returned, check for a hidden space + * @return bool 1 = yes, 0 = no, false = no record + * + * @note If records are not being returned, check for a hidden space * at the start of the uid in db */ - public function recoveryEnabledForUser() { - + public function recoveryEnabledForUser() + { + $sql = 'SELECT recovery_enabled FROM `*PREFIX*encryption` WHERE uid = ?'; - - $args = array( $this->userId ); - $query = \OCP\DB::prepare( $sql ); - - $result = $query->execute( $args ); - + $args = array($this->userId); + + $query = \OCP\DB::prepare($sql); + + $result = $query->execute($args); + $recoveryEnabled = array(); - - while( $row = $result->fetchRow() ) { - + + while ($row = $result->fetchRow()) { + $recoveryEnabled[] = $row['recovery_enabled']; - + } - + // If no record is found - if ( empty( $recoveryEnabled ) ) { - + if (empty($recoveryEnabled)) { + return false; - - // If a record is found + + // If a record is found } else { - + return $recoveryEnabled[0]; - + } - + } - + /** * @brief Enable / disable pwd recovery for a given user * @param bool $enabled Whether to enable or disable recovery * @return bool */ - public function setRecoveryForUser( $enabled ) { - + public function setRecoveryForUser($enabled) + { + $recoveryStatus = $this->recoveryEnabledForUser(); - + // If a record for this user already exists, update it - if ( false === $recoveryStatus ) { - + if (false === $recoveryStatus) { + $sql = 'INSERT INTO `*PREFIX*encryption` (`uid`,`mode`,`recovery_enabled`) VALUES (?,?,?)'; - - $args = array( $this->userId, 'server-side', $enabled ); - - // Create a new record instead + + $args = array($this->userId, 'server-side', $enabled); + + // Create a new record instead } else { - + $sql = 'UPDATE *PREFIX*encryption SET recovery_enabled = ? WHERE uid = ?'; - - $args = array( $enabled, $this->userId ); - + + $args = array($enabled, $this->userId); + } - - $query = \OCP\DB::prepare( $sql ); - - if ( $query->execute( $args ) ) { - + + $query = \OCP\DB::prepare($sql); + + if ($query->execute($args)) { + return true; - + } else { - + return false; - + } - + } - + /** * @brief Find all files and their encryption status within a directory * @param string $directory The path of the parent directory to search @@ -339,45 +357,46 @@ class Util { * @note $directory needs to be a path relative to OC data dir. e.g. * /admin/files NOT /backup OR /home/www/oc/data/admin/files */ - public function findEncFiles( $directory ) { - + public function findEncFiles($directory) + { + // Disable proxy - we don't want files to be decrypted before // we handle them \OC_FileProxy::$enabled = false; - - $found = array( 'plain' => array(), 'encrypted' => array(), 'legacy' => array() ); - - if ( - $this->view->is_dir( $directory ) - && $handle = $this->view->opendir( $directory ) + + $found = array('plain' => array(), 'encrypted' => array(), 'legacy' => array()); + + if ( + $this->view->is_dir($directory) + && $handle = $this->view->opendir($directory) ) { - - while ( false !== ( $file = readdir( $handle ) ) ) { - + + while (false !== ($file = readdir($handle))) { + if ( - $file != "." - && $file != ".." + $file != "." + && $file != ".." ) { - - $filePath = $directory . '/' . $this->view->getRelativePath( '/' . $file ); - $relPath = $this->stripUserFilesPath( $filePath ); - + + $filePath = $directory . '/' . $this->view->getRelativePath('/' . $file); + $relPath = $this->stripUserFilesPath($filePath); + // If the path is a directory, search // its contents - if ( $this->view->is_dir( $filePath ) ) { - - $this->findEncFiles( $filePath ); - - // If the path is a file, determine - // its encryption status - } elseif ( $this->view->is_file( $filePath ) ) { - + if ($this->view->is_dir($filePath)) { + + $this->findEncFiles($filePath); + + // If the path is a file, determine + // its encryption status + } elseif ($this->view->is_file($filePath)) { + // Disable proxies again, some- // where they got re-enabled :/ \OC_FileProxy::$enabled = false; - - $data = $this->view->file_get_contents( $filePath ); - + + $data = $this->view->file_get_contents($filePath); + // If the file is encrypted // NOTE: If the userId is // empty or not set, file will @@ -385,128 +404,131 @@ class Util { // NOTE: This is inefficient; // scanning every file like this // will eat server resources :( - if ( - Keymanager::getFileKey( $this->view, $this->userId, $relPath ) - && Crypt::isCatfileContent( $data ) + if ( + Keymanager::getFileKey($this->view, $this->userId, $relPath) + && Crypt::isCatfileContent($data) ) { - - $found['encrypted'][] = array( 'name' => $file, 'path' => $filePath ); - - // If the file uses old - // encryption system - } elseif ( Crypt::isLegacyEncryptedContent( $this->tail( $filePath, 3 ), $relPath ) ) { - - $found['legacy'][] = array( 'name' => $file, 'path' => $filePath ); - - // If the file is not encrypted + + $found['encrypted'][] = array('name' => $file, 'path' => $filePath); + + // If the file uses old + // encryption system + } elseif (Crypt::isLegacyEncryptedContent($this->tail($filePath, 3), $relPath)) { + + $found['legacy'][] = array('name' => $file, 'path' => $filePath); + + // If the file is not encrypted } else { - - $found['plain'][] = array( 'name' => $file, 'path' => $relPath ); - + + $found['plain'][] = array('name' => $file, 'path' => $relPath); + } - + } - + } - + } - + \OC_FileProxy::$enabled = true; - - if ( empty( $found ) ) { - + + if (empty($found)) { + return false; - + } else { - + return $found; - + } - + } - + \OC_FileProxy::$enabled = true; - + return false; } - - /** - * @brief Fetch the last lines of a file efficiently - * @note Safe to use on large files; does not read entire file to memory - * @note Derivative of http://tekkie.flashbit.net/php/tail-functionality-in-php - */ - public function tail( $filename, $numLines ) { - + + /** + * @brief Fetch the last lines of a file efficiently + * @note Safe to use on large files; does not read entire file to memory + * @note Derivative of http://tekkie.flashbit.net/php/tail-functionality-in-php + */ + public function tail($filename, $numLines) + { + \OC_FileProxy::$enabled = false; - + $text = ''; $pos = -1; - $handle = $this->view->fopen( $filename, 'r' ); + $handle = $this->view->fopen($filename, 'r'); + + while ($numLines > 0) { - while ( $numLines > 0 ) { - --$pos; - if( fseek( $handle, $pos, SEEK_END ) !== 0 ) { - - rewind( $handle ); + if (fseek($handle, $pos, SEEK_END) !== 0) { + + rewind($handle); $numLines = 0; - - } elseif ( fgetc( $handle ) === "\n" ) { - + + } elseif (fgetc($handle) === "\n") { + --$numLines; - + } - $block_size = ( -$pos ) % 8192; - if ( $block_size === 0 || $numLines === 0 ) { - - $text = fread( $handle, ( $block_size === 0 ? 8192 : $block_size ) ) . $text; - + $block_size = (-$pos) % 8192; + if ($block_size === 0 || $numLines === 0) { + + $text = fread($handle, ($block_size === 0 ? 8192 : $block_size)) . $text; + } } - fclose( $handle ); - + fclose($handle); + \OC_FileProxy::$enabled = true; - + return $text; } - + /** - * @brief Check if a given path identifies an encrypted file - * @return true / false - */ - public function isEncryptedPath( $path ) { - + * @brief Check if a given path identifies an encrypted file + * @param $path + * @return boolean + */ + public function isEncryptedPath($path) + { + // Disable encryption proxy so data retrieved is in its // original form - $proxyStatus = \OC_FileProxy::$enabled; + $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - // we only need 24 byte from the last chunk - $data = ''; - $handle = $this->view->fopen( $path, 'r' ); - if(!fseek($handle, -24, SEEK_END)) { - $data = fgets($handle); - } + // we only need 24 byte from the last chunk + $data = ''; + $handle = $this->view->fopen($path, 'r'); + if (!fseek($handle, -24, SEEK_END)) { + $data = fgets($handle); + } - // re-enable proxy + // re-enable proxy \OC_FileProxy::$enabled = $proxyStatus; - - return Crypt::isCatfileContent( $data ); - + + return Crypt::isCatfileContent($data); + } /** - * @brief get the file size of the unencrypted file - * @param $path absolute path - * @return bool - */ + * @brief get the file size of the unencrypted file + * @param string $path absolute path + * @return bool + */ + public function getFileSize($path) + { - public function getFileSize( $path ) { - $result = 0; // Disable encryption proxy to prevent recursive calls @@ -514,8 +536,8 @@ class Util { \OC_FileProxy::$enabled = false; // Reformat path for use with OC_FSV - $pathSplit = explode( '/', $path ); - $pathRelative = implode( '/', array_slice( $pathSplit, 3 ) ); + $pathSplit = explode('/', $path); + $pathRelative = implode('/', array_slice($pathSplit, 3)); if ($pathSplit[2] == 'files' && $this->view->file_exists($path) && $this->isEncryptedPath($path)) { @@ -529,7 +551,7 @@ class Util { // open stream $stream = fopen('crypt://' . $pathRelative, "r"); - if(is_resource($stream)) { + if (is_resource($stream)) { // calculate last chunk position $lastChunckPos = ($lastChunckNr * 8192); @@ -551,36 +573,36 @@ class Util { return $result; } - + /** * @brief fix the file size of the encrypted file * @param $path absolute path * @return true / false if file is encrypted */ + public function fixFileSize($path) + { - public function fixFileSize( $path ) { - $result = false; // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $realSize = $this->getFileSize( $path ); - - if ( $realSize > 0 ) { - - $cached = $this->view->getFileInfo( $path ); + $realSize = $this->getFileSize($path); + + if ($realSize > 0) { + + $cached = $this->view->getFileInfo($path); $cached['encrypted'] = true; // set the size $cached['unencrypted_size'] = $realSize; // put file info - $this->view->putFileInfo( $path, $cached ); + $this->view->putFileInfo($path, $cached); $result = true; - + } \OC_FileProxy::$enabled = $proxyStatus; @@ -592,70 +614,82 @@ class Util { * @brief Format a path to be relative to the /user/files/ directory * @note e.g. turns '/admin/files/test.txt' into 'test.txt' */ - public function stripUserFilesPath( $path ) { - - $trimmed = ltrim( $path, '/' ); - $split = explode( '/', $trimmed ); - $sliced = array_slice( $split, 2 ); - $relPath = implode( '/', $sliced ); - + public function stripUserFilesPath($path) + { + + $trimmed = ltrim($path, '/'); + $split = explode('/', $trimmed); + $sliced = array_slice($split, 2); + $relPath = implode('/', $sliced); + return $relPath; - + } - + /** * @brief Format a path to be relative to the /user directory * @note e.g. turns '/admin/files/test.txt' into 'files/test.txt' */ - public function stripFilesPath( $path ) { - - $trimmed = ltrim( $path, '/' ); - $split = explode( '/', $trimmed ); - $sliced = array_slice( $split, 1 ); - $relPath = implode( '/', $sliced ); - + public function stripFilesPath($path) + { + + $trimmed = ltrim($path, '/'); + $split = explode('/', $trimmed); + $sliced = array_slice($split, 1); + $relPath = implode('/', $sliced); + return $relPath; - + } - + /** * @brief Format a shared path to be relative to the /user/files/ directory * @note Expects a path like /uid/files/Shared/filepath */ - public function stripSharedFilePath( $path ) { - - $trimmed = ltrim( $path, '/' ); - $split = explode( '/', $trimmed ); - $sliced = array_slice( $split, 3 ); - $relPath = implode( '/', $sliced ); - + public function stripSharedFilePath($path) + { + + $trimmed = ltrim($path, '/'); + $split = explode('/', $trimmed); + $sliced = array_slice($split, 3); + $relPath = implode('/', $sliced); + return $relPath; - + } - - public function isSharedPath( $path ) { - - $trimmed = ltrim( $path, '/' ); - $split = explode( '/', $trimmed ); - - if ( $split[2] == "Shared" ) { - + + /** + * @param $path + * @return bool + */ + public function isSharedPath($path) + { + + $trimmed = ltrim($path, '/'); + $split = explode('/', $trimmed); + + if ($split[2] == "Shared") { + return true; - + } else { - + return false; - + } - + } - + /** * @brief Encrypt all files in a directory * @param string $dirPath the directory whose files will be encrypted + * @param null $legacyPassphrase + * @param null $newPassphrase + * @return bool * @note Encryption is recursive */ - public function encryptAll($dirPath, $legacyPassphrase = null, $newPassphrase = null) { + public function encryptAll($dirPath, $legacyPassphrase = null, $newPassphrase = null) + { if ($found = $this->findEncFiles($dirPath)) { @@ -762,174 +796,180 @@ class Util { * @param string $pathName Name of the directory to return the path of * @return string path */ - public function getPath( $pathName ) { - - switch ( $pathName ) { - + public function getPath($pathName) + { + + switch ($pathName) { + case 'publicKeyDir': - + return $this->publicKeyDir; - + break; - + case 'encryptionDir': - + return $this->encryptionDir; - + break; - + case 'keyfilesPath': - + return $this->keyfilesPath; - + break; - + case 'publicKeyPath': - + return $this->publicKeyPath; - + break; - + case 'privateKeyPath': - + return $this->privateKeyPath; - + break; - + } - + } - + /** * @brief get path of a file. - * @param $fileId id of the file - * @return path of the file + * @param int $fileId id of the file + * @return string path of the file */ - public static function fileIdToPath( $fileId ) { - - $query = \OC_DB::prepare( 'SELECT `path`' - .' FROM `*PREFIX*filecache`' - .' WHERE `fileid` = ?' ); - - $result = $query->execute( array( $fileId ) ); - + public static function fileIdToPath($fileId) + { + + $query = \OC_DB::prepare('SELECT `path`' + . ' FROM `*PREFIX*filecache`' + . ' WHERE `fileid` = ?'); + + $result = $query->execute(array($fileId)); + $row = $result->fetchRow(); - - return substr( $row['path'], 5 ); - + + return substr($row['path'], 5); + } - + /** * @brief Filter an array of UIDs to return only ones ready for sharing * @param array $unfilteredUsers users to be checked for sharing readiness * @return multi-dimensional array. keys: ready, unready */ - public function filterShareReadyUsers( $unfilteredUsers ) { - + public function filterShareReadyUsers($unfilteredUsers) + { + // This array will collect the filtered IDs $readyIds = $unreadyIds = array(); - + // Loop through users and create array of UIDs that need new keyfiles - foreach ( $unfilteredUsers as $user ) { - - $util = new Util( $this->view, $user ); - + foreach ($unfilteredUsers as $user) { + + $util = new Util($this->view, $user); + // Check that the user is encryption capable, or is the // public system user 'ownCloud' (for public shares) - if ( + if ( $user == $this->publicShareKeyId or $user == $this->recoveryKeyId - or $util->ready() + or $util->ready() ) { - + // Construct array of ready UIDs for Keymanager{} $readyIds[] = $user; - + } else { - + // Construct array of unready UIDs for Keymanager{} $unreadyIds[] = $user; - + // Log warning; we can't do necessary setup here // because we don't have the user passphrase - \OC_Log::write( 'Encryption library', '"'.$user.'" is not setup for encryption', \OC_Log::WARN ); - + \OC_Log::write('Encryption library', '"' . $user . '" is not setup for encryption', \OC_Log::WARN); + } - + } - - return array ( + + return array( 'ready' => $readyIds - , 'unready' => $unreadyIds + , 'unready' => $unreadyIds ); - + } - + /** * @brief Decrypt a keyfile without knowing how it was encrypted * @param string $filePath * @param string $fileOwner * @param string $privateKey - * @note Checks whether file was encrypted with openssl_seal or + * @note Checks whether file was encrypted with openssl_seal or * openssl_encrypt, and decrypts accrdingly - * @note This was used when 2 types of encryption for keyfiles was used, + * @note This was used when 2 types of encryption for keyfiles was used, * but now we've switched to exclusively using openssl_seal() */ - public function decryptUnknownKeyfile( $filePath, $fileOwner, $privateKey ) { + public function decryptUnknownKeyfile($filePath, $fileOwner, $privateKey) + { // Get the encrypted keyfile // NOTE: the keyfile format depends on how it was encrypted! At // this stage we don't know how it was encrypted - $encKeyfile = Keymanager::getFileKey( $this->view, $this->userId, $filePath ); - + $encKeyfile = Keymanager::getFileKey($this->view, $this->userId, $filePath); + // We need to decrypt the keyfile // Has the file been shared yet? - if ( + if ( $this->userId == $fileOwner - && ! Keymanager::getShareKey( $this->view, $this->userId, $filePath ) // NOTE: we can't use isShared() here because it's a post share hook so it always returns true + && !Keymanager::getShareKey($this->view, $this->userId, $filePath) // NOTE: we can't use isShared() here because it's a post share hook so it always returns true ) { - + // The file has no shareKey, and its keyfile must be // decrypted conventionally - $plainKeyfile = Crypt::keyDecrypt( $encKeyfile, $privateKey ); - - + $plainKeyfile = Crypt::keyDecrypt($encKeyfile, $privateKey); + + } else { - + // The file has a shareKey and must use it for decryption - $shareKey = Keymanager::getShareKey( $this->view, $this->userId, $filePath ); - - $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); - + $shareKey = Keymanager::getShareKey($this->view, $this->userId, $filePath); + + $plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + } - + return $plainKeyfile; } - + /** * @brief Encrypt keyfile to multiple users + * @param Session $session * @param array $users list of users which should be able to access the file * @param string $filePath path of the file to be shared - * @return bool + * @return bool */ - public function setSharedFileKeyfiles( Session $session, array $users, $filePath ) { - + public function setSharedFileKeyfiles(Session $session, array $users, $filePath) + { + // Make sure users are capable of sharing - $filteredUids = $this->filterShareReadyUsers( $users ); - + $filteredUids = $this->filterShareReadyUsers($users); + // If we're attempting to share to unready users - if ( ! empty( $filteredUids['unready'] ) ) { - - \OC_Log::write( 'Encryption library', 'Sharing to these user(s) failed as they are unready for encryption:"'.print_r( $filteredUids['unready'], 1 ), \OC_Log::WARN ); - + if (!empty($filteredUids['unready'])) { + + \OC_Log::write('Encryption library', 'Sharing to these user(s) failed as they are unready for encryption:"' . print_r($filteredUids['unready'], 1), \OC_Log::WARN); + return false; - + } - + // Get public keys for each user, ready for generating sharekeys - $userPubKeys = Keymanager::getPublicKeys( $this->view, $filteredUids['ready'] ); - + $userPubKeys = Keymanager::getPublicKeys($this->view, $filteredUids['ready']); + // Note proxy status then disable it $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; @@ -937,273 +977,279 @@ class Util { // Get the current users's private key for decrypting existing keyfile $privateKey = $session->getPrivateKey(); - $fileOwner = \OC\Files\Filesystem::getOwner( $filePath ); - + $fileOwner = \OC\Files\Filesystem::getOwner($filePath); + // Decrypt keyfile - $plainKeyfile = $this->decryptUnknownKeyfile( $filePath, $fileOwner, $privateKey ); - + $plainKeyfile = $this->decryptUnknownKeyfile($filePath, $fileOwner, $privateKey); + // Re-enc keyfile to (additional) sharekeys - $multiEncKey = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys ); - + $multiEncKey = Crypt::multiKeyEncrypt($plainKeyfile, $userPubKeys); + // Save the recrypted key to it's owner's keyfiles directory // Save new sharekeys to all necessary user directory - if ( - ! Keymanager::setFileKey( $this->view, $filePath, $fileOwner, $multiEncKey['data'] ) - || ! Keymanager::setShareKeys( $this->view, $filePath, $multiEncKey['keys'] ) + if ( + !Keymanager::setFileKey($this->view, $filePath, $fileOwner, $multiEncKey['data']) + || !Keymanager::setShareKeys($this->view, $filePath, $multiEncKey['keys']) ) { - \OC_Log::write( 'Encryption library', 'Keyfiles could not be saved for users sharing ' . $filePath, \OC_Log::ERROR ); - + \OC_Log::write('Encryption library', 'Keyfiles could not be saved for users sharing ' . $filePath, \OC_Log::ERROR); + return false; } - + // Return proxy to original status \OC_FileProxy::$enabled = $proxyStatus; return true; } - + /** * @brief Find, sanitise and format users sharing a file * @note This wraps other methods into a portable bundle */ - public function getSharingUsersArray( $sharingEnabled, $filePath, $currentUserId = false ) { + public function getSharingUsersArray($sharingEnabled, $filePath, $currentUserId = false) + { // Check if key recovery is enabled if ( - \OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' ) + \OC_Appconfig::getValue('files_encryption', 'recoveryAdminEnabled') && $this->recoveryEnabledForUser() ) { - + $recoveryEnabled = true; - + } else { - + $recoveryEnabled = false; - + } - + // Make sure that a share key is generated for the owner too - list( $owner, $ownerPath ) = $this->getUidAndFilename( $filePath ); + list($owner, $ownerPath) = $this->getUidAndFilename($filePath); + + if ($sharingEnabled) { - if ( $sharingEnabled ) { - // Find out who, if anyone, is sharing the file - $result = \OCP\Share::getUsersSharingFile( $ownerPath, $owner,true, true, true ); + $result = \OCP\Share::getUsersSharingFile($ownerPath, $owner, true, true, true); $userIds = $result['users']; - if ( $result['public'] ) { + if ($result['public']) { $userIds[] = $this->publicShareKeyId; } - + } - + // If recovery is enabled, add the // Admin UID to list of users to share to - if ( $recoveryEnabled ) { - + if ($recoveryEnabled) { + // Find recoveryAdmin user ID - $recoveryKeyId = \OC_Appconfig::getValue( 'files_encryption', 'recoveryKeyId' ); - + $recoveryKeyId = \OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); + // Add recoveryAdmin to list of users sharing $userIds[] = $recoveryKeyId; - + } // add current user if given - if ( $currentUserId != false ) { - + if ($currentUserId != false) { + $userIds[] = $currentUserId; - + } // Remove duplicate UIDs - $uniqueUserIds = array_unique ( $userIds ); - + $uniqueUserIds = array_unique($userIds); + return $uniqueUserIds; } - + /** * @brief Set file migration status for user + * @param $status * @return bool */ - public function setMigrationStatus( $status ) { - + public function setMigrationStatus($status) + { + $sql = 'UPDATE *PREFIX*encryption SET migration_status = ? WHERE uid = ?'; - - $args = array( $status, $this->userId ); - - $query = \OCP\DB::prepare( $sql ); - - if ( $query->execute( $args ) ) { - + + $args = array($status, $this->userId); + + $query = \OCP\DB::prepare($sql); + + if ($query->execute($args)) { + return true; - + } else { - + return false; - + } - + } - + /** * @brief Check whether pwd recovery is enabled for a given user - * @return 1 = yes, 0 = no, false = no record - * @note If records are not being returned, check for a hidden space + * @return bool 1 = yes, 0 = no, false = no record + * @note If records are not being returned, check for a hidden space * at the start of the uid in db */ - public function getMigrationStatus() { - + public function getMigrationStatus() + { + $sql = 'SELECT migration_status FROM `*PREFIX*encryption` WHERE uid = ?'; - - $args = array( $this->userId ); - $query = \OCP\DB::prepare( $sql ); - - $result = $query->execute( $args ); - + $args = array($this->userId); + + $query = \OCP\DB::prepare($sql); + + $result = $query->execute($args); + $migrationStatus = array(); - - while( $row = $result->fetchRow() ) { - + + while ($row = $result->fetchRow()) { + $migrationStatus[] = $row['migration_status']; - + } - + // If no record is found - if ( empty( $migrationStatus ) ) { - + if (empty($migrationStatus)) { + return false; - - // If a record is found + + // If a record is found } else { - + return $migrationStatus[0]; - + } - + } - + /** * @brief get uid of the owners of the file and the path to the file - * @param $path Path of the file to check - * @note $shareFilePath must be relative to data/UID/files. Files + * @param string $path Path of the file to check + * @note $shareFilePath must be relative to data/UID/files. Files * relative to /Shared are also acceptable * @return array */ - public function getUidAndFilename( $path ) { + public function getUidAndFilename($path) + { + + $view = new \OC\Files\View($this->userFilesDir); + $fileOwnerUid = $view->getOwner($path); - $view = new \OC\Files\View($this->userFilesDir); - $fileOwnerUid = $view->getOwner( $path ); + // handle public access + if ($fileOwnerUid === false && $this->isPublic) { + $filename = $path; + $fileOwnerUid = $GLOBALS['fileOwner']; - // handle public access - if($fileOwnerUid === false && $this->isPublic) { - $filename = $path; - $fileOwnerUid = $GLOBALS['fileOwner']; + return array($fileOwnerUid, $filename); + } else { - return array ( $fileOwnerUid, $filename ); - } else { + // Check that UID is valid + if (!\OCP\User::userExists($fileOwnerUid)) { + throw new \Exception('Could not find owner (UID = "' . var_export($fileOwnerUid, 1) . '") of file "' . $path . '"'); + } - // Check that UID is valid - if ( ! \OCP\User::userExists( $fileOwnerUid ) ) { - throw new \Exception( 'Could not find owner (UID = "' . var_export( $fileOwnerUid, 1 ) . '") of file "' . $path . '"' ); - } + // NOTE: Bah, this dependency should be elsewhere + \OC\Files\Filesystem::initMountPoints($fileOwnerUid); - // NOTE: Bah, this dependency should be elsewhere - \OC\Files\Filesystem::initMountPoints( $fileOwnerUid ); + // If the file owner is the currently logged in user + if ($fileOwnerUid == $this->userId) { - // If the file owner is the currently logged in user - if ( $fileOwnerUid == $this->userId ) { + // Assume the path supplied is correct + $filename = $path; - // Assume the path supplied is correct - $filename = $path; + } else { - } else { + $info = $view->getFileInfo($path); + $ownerView = new \OC\Files\View('/' . $fileOwnerUid . '/files'); - $info = $view->getFileInfo( $path ); - $ownerView = new \OC\Files\View( '/' . $fileOwnerUid . '/files' ); + // Fetch real file path from DB + $filename = $ownerView->getPath($info['fileid']); // TODO: Check that this returns a path without including the user data dir - // Fetch real file path from DB - $filename = $ownerView->getPath( $info['fileid'] ); // TODO: Check that this returns a path without including the user data dir + } - } + return array($fileOwnerUid, $filename); + } - return array ( $fileOwnerUid, $filename ); - } - } /** * @brief geo recursively through a dir and collect all files and sub files. - * @param type $dir relative to the users files folder + * @param string $dir relative to the users files folder * @return array with list of files relative to the users files folder */ - public function getAllFiles( $dir ) { - + public function getAllFiles($dir) + { + $result = array(); - $content = $this->view->getDirectoryContent( $this->userFilesDir . $dir ); + $content = $this->view->getDirectoryContent($this->userFilesDir . $dir); // handling for re shared folders - $path_split = explode( '/', $dir ); + $path_split = explode('/', $dir); $shared = ''; - - if( $path_split[1] === 'Shared' ) { - + + if ($path_split[1] === 'Shared') { + $shared = '/Shared'; - + } - foreach ( $content as $c ) { - - $sharedPart = $path_split[sizeof( $path_split )-1]; - $targetPathSplit = array_reverse( explode( '/', $c['path'] ) ); + foreach ($content as $c) { + + $sharedPart = $path_split[sizeof($path_split) - 1]; + $targetPathSplit = array_reverse(explode('/', $c['path'])); $path = ''; // rebuild path - foreach ( $targetPathSplit as $pathPart ) { - - if ( $pathPart !== $sharedPart ) { - + foreach ($targetPathSplit as $pathPart) { + + if ($pathPart !== $sharedPart) { + $path = '/' . $pathPart . $path; - + } else { - + break; - + } - + } - $path = $dir.$path; + $path = $dir . $path; + + if ($c['type'] === "dir") { + + $result = array_merge($result, $this->getAllFiles($path)); - if ($c['type'] === "dir" ) { - - $result = array_merge( $result, $this->getAllFiles( $path ) ); - } else { - + $result[] = $path; - + } } - + return $result; - + } /** @@ -1211,13 +1257,14 @@ class Util { * @param int $id of the current share * @return array of the parent */ - public static function getShareParent( $id ) { + public static function getShareParent($id) + { - $query = \OC_DB::prepare( 'SELECT `file_target`, `item_type`' - .' FROM `*PREFIX*share`' - .' WHERE `id` = ?' ); + $query = \OC_DB::prepare('SELECT `file_target`, `item_type`' + . ' FROM `*PREFIX*share`' + . ' WHERE `id` = ?'); - $result = $query->execute( array( $id ) ); + $result = $query->execute(array($id)); $row = $result->fetchRow(); @@ -1230,13 +1277,14 @@ class Util { * @param int $id of the current share * @return array of the parent */ - public static function getParentFromShare( $id ) { + public static function getParentFromShare($id) + { - $query = \OC_DB::prepare( 'SELECT `parent`' - .' FROM `*PREFIX*share`' - .' WHERE `id` = ?' ); + $query = \OC_DB::prepare('SELECT `parent`' + . ' FROM `*PREFIX*share`' + . ' WHERE `id` = ?'); - $result = $query->execute( array( $id ) ); + $result = $query->execute(array($id)); $row = $result->fetchRow(); @@ -1246,57 +1294,70 @@ class Util { /** * @brief get owner of the shared files. - * @param int $Id of a share - * @return owner + * @param $id + * @internal param int $Id of a share + * @return string owner */ - public function getOwnerFromSharedFile( $id ) { - - $query = \OC_DB::prepare( 'SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1 ); - $source = $query->execute( array( $id ) )->fetchRow(); + public function getOwnerFromSharedFile($id) + { + + $query = \OC_DB::prepare('SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1); + $source = $query->execute(array($id))->fetchRow(); + + if (isset($source['parent'])) { - if ( isset($source['parent'] ) ) { - $parent = $source['parent']; - - while ( isset( $parent ) ) { - - $query = \OC_DB::prepare( 'SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1 ); - $item = $query->execute( array( $parent ) )->fetchRow(); - - if ( isset( $item['parent'] ) ) { - + + while (isset($parent)) { + + $query = \OC_DB::prepare('SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1); + $item = $query->execute(array($parent))->fetchRow(); + + if (isset($item['parent'])) { + $parent = $item['parent']; - + } else { - + $fileOwner = $item['uid_owner']; - + break; - + } } - + } else { - + $fileOwner = $source['uid_owner']; - + } return $fileOwner; - + } - public function getUserId() - { - return $this->userId; - } + /** + * @return string + */ + public function getUserId() + { + return $this->userId; + } - public function getUserFilesDir() - { - return $this->userFilesDir; - } + /** + * @return string + */ + public function getUserFilesDir() + { + return $this->userFilesDir; + } - public function checkRecoveryPassword($password) { + /** + * @param $password + * @return bool + */ + public function checkRecoveryPassword($password) + { $pathKey = '/owncloud_private_key/' . $this->recoveryKeyId . ".private.key"; $pathControlData = '/control-file/controlfile.enc'; @@ -1315,30 +1376,35 @@ class Util { if ($decryptedControlData === 'ownCloud') { return true; - } - + } + return false; } - public function getRecoveryKeyId() { + /** + * @return string + */ + public function getRecoveryKeyId() + { return $this->recoveryKeyId; } /** * @brief add recovery key to all encrypted files */ - public function addRecoveryKeys($path = '/') { - $dirContent = $this->view->getDirectoryContent($this->keyfilesPath.$path); + public function addRecoveryKeys($path = '/') + { + $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path); foreach ($dirContent as $item) { $filePath = substr($item['path'], 25); if ($item['type'] == 'dir') { - $this->addRecoveryKeys($filePath.'/'); + $this->addRecoveryKeys($filePath . '/'); } else { $session = new Session(new \OC_FilesystemView('/')); $sharingEnabled = \OCP\Share::isEnabled(); $file = substr($filePath, 0, -4); $usersSharing = $this->getSharingUsersArray($sharingEnabled, $file); - $this->setSharedFileKeyfiles( $session, $usersSharing, $file ); + $this->setSharedFileKeyfiles($session, $usersSharing, $file); } } } @@ -1346,25 +1412,27 @@ class Util { /** * @brief remove recovery key to all encrypted files */ - public function removeRecoveryKeys($path = '/') { - $dirContent = $this->view->getDirectoryContent($this->keyfilesPath.$path); + public function removeRecoveryKeys($path = '/') + { + $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path); foreach ($dirContent as $item) { $filePath = substr($item['path'], 25); if ($item['type'] == 'dir') { - $this->removeRecoveryKeys($filePath.'/'); + $this->removeRecoveryKeys($filePath . '/'); } else { $file = substr($filePath, 0, -4); - $this->view->unlink($this->shareKeysPath.'/'.$file.'.'.$this->recoveryKeyId.'.shareKey'); + $this->view->unlink($this->shareKeysPath . '/' . $file . '.' . $this->recoveryKeyId . '.shareKey'); } } } /** * @brief decrypt given file with recovery key and encrypt it again to the owner and his new key - * @param type $file - * @param type $privateKey recovery key to decrypt the file + * @param string $file + * @param string $privateKey recovery key to decrypt the file */ - private function recoverFile($file, $privateKey) { + private function recoverFile($file, $privateKey) + { $sharingEnabled = \OCP\Share::isEnabled(); @@ -1385,17 +1453,17 @@ class Util { \OC_FileProxy::$enabled = false; //decrypt file key - $encKeyfile = $this->view->file_get_contents($this->keyfilesPath.$file.".key"); - $shareKey = $this->view->file_get_contents($this->shareKeysPath.$file.".".$this->recoveryKeyId.".shareKey"); + $encKeyfile = $this->view->file_get_contents($this->keyfilesPath . $file . ".key"); + $shareKey = $this->view->file_get_contents($this->shareKeysPath . $file . "." . $this->recoveryKeyId . ".shareKey"); $plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); // encrypt file key again to all users, this time with the new public key for the recovered use $userPubKeys = Keymanager::getPublicKeys($this->view, $filteredUids['ready']); $multiEncKey = Crypt::multiKeyEncrypt($plainKeyfile, $userPubKeys); // write new keys to filesystem TDOO! - $this->view->file_put_contents($this->keyfilesPath.$file.'.key', $multiEncKey['data']); + $this->view->file_put_contents($this->keyfilesPath . $file . '.key', $multiEncKey['data']); foreach ($multiEncKey['keys'] as $userId => $shareKey) { - $shareKeyPath = $this->shareKeysPath.$file.'.'.$userId.'.shareKey'; + $shareKeyPath = $this->shareKeysPath . $file . '.' . $userId . '.shareKey'; $this->view->file_put_contents($shareKeyPath, $shareKey); } @@ -1405,10 +1473,11 @@ class Util { /** * @brief collect all files and recover them one by one - * @param type $path to look for files keys - * @param type $privateKey private recovery key which is used to decrypt the files + * @param string $path to look for files keys + * @param string $privateKey private recovery key which is used to decrypt the files */ - private function recoverAllFiles($path, $privateKey) { + private function recoverAllFiles($path, $privateKey) + { $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path); foreach ($dirContent as $item) { $filePath = substr($item['path'], 25); @@ -1423,16 +1492,17 @@ class Util { /** * @brief recover users files in case of password lost - * @param type $recoveryPassword + * @param string $recoveryPassword */ - public function recoverUsersFiles($recoveryPassword) { + public function recoverUsersFiles($recoveryPassword) + { // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $encryptedKey = $this->view->file_get_contents( '/owncloud_private_key/'.$this->recoveryKeyId.'.private.key' ); - $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $recoveryPassword ); + $encryptedKey = $this->view->file_get_contents('/owncloud_private_key/' . $this->recoveryKeyId . '.private.key'); + $privateKey = Crypt::symmetricDecryptFileContent($encryptedKey, $recoveryPassword); \OC_FileProxy::$enabled = $proxyStatus; diff --git a/apps/files_encryption/tests/crypt.php b/apps/files_encryption/tests/crypt.php index c669aec1222..5b5a2189a48 100755 --- a/apps/files_encryption/tests/crypt.php +++ b/apps/files_encryption/tests/crypt.php @@ -7,22 +7,23 @@ * See the COPYING-README file. */ -require_once realpath( dirname(__FILE__).'/../../../3rdparty/Crypt_Blowfish/Blowfish.php' ); -require_once realpath( dirname(__FILE__).'/../../../lib/base.php' ); -require_once realpath( dirname(__FILE__).'/../lib/crypt.php' ); -require_once realpath( dirname(__FILE__).'/../lib/keymanager.php' ); -require_once realpath( dirname(__FILE__).'/../lib/proxy.php' ); -require_once realpath( dirname(__FILE__).'/../lib/stream.php' ); -require_once realpath( dirname(__FILE__).'/../lib/util.php' ); -require_once realpath( dirname(__FILE__).'/../lib/helper.php' ); -require_once realpath( dirname(__FILE__).'/../appinfo/app.php' ); +require_once realpath(dirname(__FILE__) . '/../../../3rdparty/Crypt_Blowfish/Blowfish.php'); +require_once realpath(dirname(__FILE__) . '/../../../lib/base.php'); +require_once realpath(dirname(__FILE__) . '/../lib/crypt.php'); +require_once realpath(dirname(__FILE__) . '/../lib/keymanager.php'); +require_once realpath(dirname(__FILE__) . '/../lib/proxy.php'); +require_once realpath(dirname(__FILE__) . '/../lib/stream.php'); +require_once realpath(dirname(__FILE__) . '/../lib/util.php'); +require_once realpath(dirname(__FILE__) . '/../lib/helper.php'); +require_once realpath(dirname(__FILE__) . '/../appinfo/app.php'); use OCA\Encryption; /** * Class Test_Encryption_Crypt */ -class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { +class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase +{ public $userId; public $pass; @@ -38,39 +39,40 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { public $genPrivateKey; public $genPublicKey; - function setUp() { - // reset backend - \OC_User::clearBackends(); - \OC_User::useBackend('database'); + function setUp() + { + // reset backend + \OC_User::clearBackends(); + \OC_User::useBackend('database'); - // set content for encrypting / decrypting in tests - $this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) ); + // set content for encrypting / decrypting in tests + $this->dataLong = file_get_contents(realpath(dirname(__FILE__) . '/../lib/crypt.php')); $this->dataShort = 'hats'; - $this->dataUrl = realpath( dirname(__FILE__).'/../lib/crypt.php' ); - $this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' ); - $this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' ); + $this->dataUrl = realpath(dirname(__FILE__) . '/../lib/crypt.php'); + $this->legacyData = realpath(dirname(__FILE__) . '/legacy-text.txt'); + $this->legacyEncryptedData = realpath(dirname(__FILE__) . '/legacy-encrypted-text.txt'); $this->randomKey = Encryption\Crypt::generateKey(); - + $keypair = Encryption\Crypt::createKeypair(); - $this->genPublicKey = $keypair['publicKey']; + $this->genPublicKey = $keypair['publicKey']; $this->genPrivateKey = $keypair['privateKey']; - - $this->view = new \OC_FilesystemView( '/' ); - - \OC_User::setUserId( 'admin' ); + + $this->view = new \OC_FilesystemView('/'); + + \OC_User::setUserId('admin'); $this->userId = 'admin'; $this->pass = 'admin'; - $userHome = \OC_User::getHome($this->userId); - $this->dataDir = str_replace('/'.$this->userId, '', $userHome); + $userHome = \OC_User::getHome($this->userId); + $this->dataDir = str_replace('/' . $this->userId, '', $userHome); - // Filesystem related hooks - \OCA\Encryption\Helper::registerFilesystemHooks(); + // Filesystem related hooks + \OCA\Encryption\Helper::registerFilesystemHooks(); // Filesystem related hooks \OCA\Encryption\Helper::registerUserHooks(); - \OC_FileProxy::register(new OCA\Encryption\Proxy()); + \OC_FileProxy::register(new OCA\Encryption\Proxy()); // remember files_trashbin state $this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin'); @@ -78,19 +80,20 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { // we don't want to tests with app files_trashbin enabled \OC_App::disable('files_trashbin'); - \OC_Util::tearDownFS(); - \OC_User::setUserId(''); - \OC\Files\Filesystem::tearDown(); - \OC_Util::setupFS($this->userId); - \OC_User::setUserId($this->userId); + \OC_Util::tearDownFS(); + \OC_User::setUserId(''); + \OC\Files\Filesystem::tearDown(); + \OC_Util::setupFS($this->userId); + \OC_User::setUserId($this->userId); - $params['uid'] = $this->userId; - $params['password'] = $this->pass; - OCA\Encryption\Hooks::login($params); + $params['uid'] = $this->userId; + $params['password'] = $this->pass; + OCA\Encryption\Hooks::login($params); } - - function tearDown() { + + function tearDown() + { \OC_FileProxy::clearProxies(); // reset app files_trashbin @@ -99,285 +102,297 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { } else { OC_App::disable('files_trashbin'); } - } + } + + function testGenerateKey() + { - function testGenerateKey() { - # TODO: use more accurate (larger) string length for test confirmation - + $key = Encryption\Crypt::generateKey(); - - $this->assertTrue( strlen( $key ) > 16 ); - + + $this->assertTrue(strlen($key) > 16); + } /** * @return String */ - function testGenerateIv() { - + function testGenerateIv() + { + $iv = Encryption\Crypt::generateIv(); - - $this->assertEquals( 16, strlen( $iv ) ); - + + $this->assertEquals(16, strlen($iv)); + return $iv; - + } - + /** * @depends testGenerateIv */ - function testConcatIv( $iv ) { - - $catFile = Encryption\Crypt::concatIv( $this->dataLong, $iv ); - + function testConcatIv($iv) + { + + $catFile = Encryption\Crypt::concatIv($this->dataLong, $iv); + // Fetch encryption metadata from end of file - $meta = substr( $catFile, -22 ); - - $identifier = substr( $meta, 0, 6); - + $meta = substr($catFile, -22); + + $identifier = substr($meta, 0, 6); + // Fetch IV from end of file - $foundIv = substr( $meta, 6 ); - - $this->assertEquals( '00iv00', $identifier ); - - $this->assertEquals( $iv, $foundIv ); - + $foundIv = substr($meta, 6); + + $this->assertEquals('00iv00', $identifier); + + $this->assertEquals($iv, $foundIv); + // Remove IV and IV identifier text to expose encrypted content - $data = substr( $catFile, 0, -22 ); - - $this->assertEquals( $this->dataLong, $data ); - + $data = substr($catFile, 0, -22); + + $this->assertEquals($this->dataLong, $data); + return array( 'iv' => $iv - , 'catfile' => $catFile + , 'catfile' => $catFile ); - + } - + /** * @depends testConcatIv */ - function testSplitIv( $testConcatIv ) { - + function testSplitIv($testConcatIv) + { + // Split catfile into components - $splitCatfile = Encryption\Crypt::splitIv( $testConcatIv['catfile'] ); - + $splitCatfile = Encryption\Crypt::splitIv($testConcatIv['catfile']); + // Check that original IV and split IV match - $this->assertEquals( $testConcatIv['iv'], $splitCatfile['iv'] ); - + $this->assertEquals($testConcatIv['iv'], $splitCatfile['iv']); + // Check that original data and split data match - $this->assertEquals( $this->dataLong, $splitCatfile['encrypted'] ); - + $this->assertEquals($this->dataLong, $splitCatfile['encrypted']); + } /** * @return string padded */ - function testAddPadding() { - - $padded = Encryption\Crypt::addPadding( $this->dataLong ); - - $padding = substr( $padded, -2 ); - - $this->assertEquals( 'xx' , $padding ); - + function testAddPadding() + { + + $padded = Encryption\Crypt::addPadding($this->dataLong); + + $padding = substr($padded, -2); + + $this->assertEquals('xx', $padding); + return $padded; - + } - + /** * @depends testAddPadding */ - function testRemovePadding( $padded ) { - - $noPadding = Encryption\Crypt::RemovePadding( $padded ); - - $this->assertEquals( $this->dataLong, $noPadding ); - + function testRemovePadding($padded) + { + + $noPadding = Encryption\Crypt::RemovePadding($padded); + + $this->assertEquals($this->dataLong, $noPadding); + } - - function testEncrypt() { - - $random = openssl_random_pseudo_bytes( 13 ); - $iv = substr( base64_encode( $random ), 0, -4 ); // i.e. E5IG033j+mRNKrht + function testEncrypt() + { + + $random = openssl_random_pseudo_bytes(13); + + $iv = substr(base64_encode($random), 0, -4); // i.e. E5IG033j+mRNKrht + + $crypted = Encryption\Crypt::encrypt($this->dataUrl, $iv, 'hat'); - $crypted = Encryption\Crypt::encrypt( $this->dataUrl, $iv, 'hat' ); + $this->assertNotEquals($this->dataUrl, $crypted); - $this->assertNotEquals( $this->dataUrl, $crypted ); - } - - function testDecrypt() { - - $random = openssl_random_pseudo_bytes( 13 ); - $iv = substr( base64_encode( $random ), 0, -4 ); // i.e. E5IG033j+mRNKrht + function testDecrypt() + { - $crypted = Encryption\Crypt::encrypt( $this->dataUrl, $iv, 'hat' ); - - $decrypt = Encryption\Crypt::decrypt( $crypted, $iv, 'hat' ); + $random = openssl_random_pseudo_bytes(13); + + $iv = substr(base64_encode($random), 0, -4); // i.e. E5IG033j+mRNKrht + + $crypted = Encryption\Crypt::encrypt($this->dataUrl, $iv, 'hat'); + + $decrypt = Encryption\Crypt::decrypt($crypted, $iv, 'hat'); + + $this->assertEquals($this->dataUrl, $decrypt); - $this->assertEquals( $this->dataUrl, $decrypt ); - } - - function testSymmetricEncryptFileContent() { - + + function testSymmetricEncryptFileContent() + { + # TODO: search in keyfile for actual content as IV will ensure this test always passes - - $crypted = Encryption\Crypt::symmetricEncryptFileContent( $this->dataShort, 'hat' ); - $this->assertNotEquals( $this->dataShort, $crypted ); - + $crypted = Encryption\Crypt::symmetricEncryptFileContent($this->dataShort, 'hat'); - $decrypt = Encryption\Crypt::symmetricDecryptFileContent( $crypted, 'hat' ); + $this->assertNotEquals($this->dataShort, $crypted); + + + $decrypt = Encryption\Crypt::symmetricDecryptFileContent($crypted, 'hat'); + + $this->assertEquals($this->dataShort, $decrypt); - $this->assertEquals( $this->dataShort, $decrypt ); - } - function testSymmetricStreamEncryptShortFileContent() { - - $filename = 'tmp-'.time().'.test'; + function testSymmetricStreamEncryptShortFileContent() + { + + $filename = 'tmp-' . time() . '.test'; + + $cryptedFile = file_put_contents('crypt://' . $filename, $this->dataShort); - $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataShort ); - // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // Get file contents without using any wrapper to get it's actual contents on disk - $retreivedCryptedFile = $this->view->file_get_contents($this->userId . '/files/' . $filename); + // Get file contents without using any wrapper to get it's actual contents on disk + $retreivedCryptedFile = $this->view->file_get_contents($this->userId . '/files/' . $filename); - // Re-enable proxy - our work is done - \OC_FileProxy::$enabled = $proxyStatus; + // Re-enable proxy - our work is done + \OC_FileProxy::$enabled = $proxyStatus; // Check that the file was encrypted before being written to disk - $this->assertNotEquals( $this->dataShort, $retreivedCryptedFile ); + $this->assertNotEquals($this->dataShort, $retreivedCryptedFile); - // Get the encrypted keyfile - $encKeyfile = Encryption\Keymanager::getFileKey( $this->view, $this->userId, $filename ); + // Get the encrypted keyfile + $encKeyfile = Encryption\Keymanager::getFileKey($this->view, $this->userId, $filename); - // Attempt to fetch the user's shareKey - $shareKey = Encryption\Keymanager::getShareKey( $this->view, $this->userId, $filename ); + // Attempt to fetch the user's shareKey + $shareKey = Encryption\Keymanager::getShareKey($this->view, $this->userId, $filename); - // get session - $session = new Encryption\Session( $this->view ); + // get session + $session = new Encryption\Session($this->view); - // get private key - $privateKey = $session->getPrivateKey( $this->userId ); + // get private key + $privateKey = $session->getPrivateKey($this->userId); - // Decrypt keyfile with shareKey - $plainKeyfile = Encryption\Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); + // Decrypt keyfile with shareKey + $plainKeyfile = Encryption\Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); - // Manually decrypt - $manualDecrypt = Encryption\Crypt::symmetricDecryptFileContent( $retreivedCryptedFile, $plainKeyfile ); + // Manually decrypt + $manualDecrypt = Encryption\Crypt::symmetricDecryptFileContent($retreivedCryptedFile, $plainKeyfile); // Check that decrypted data matches - $this->assertEquals( $this->dataShort, $manualDecrypt ); + $this->assertEquals($this->dataShort, $manualDecrypt); - // Teardown - $this->view->unlink( $this->userId . '/files/' . $filename ); + // Teardown + $this->view->unlink($this->userId . '/files/' . $filename); - Encryption\Keymanager::deleteFileKey( $this->view, $this->userId, $filename ); + Encryption\Keymanager::deleteFileKey($this->view, $this->userId, $filename); } - + /** * @brief Test that data that is written by the crypto stream wrapper * @note Encrypted data is manually prepared and decrypted here to avoid dependency on success of stream_read - * @note If this test fails with truncate content, check that enough array slices are being rejoined to form $e, as the crypt.php file may have gotten longer and broken the manual + * @note If this test fails with truncate content, check that enough array slices are being rejoined to form $e, as the crypt.php file may have gotten longer and broken the manual * reassembly of its data */ - function testSymmetricStreamEncryptLongFileContent() { - + function testSymmetricStreamEncryptLongFileContent() + { + // Generate a a random filename - $filename = 'tmp-'.time().'.test'; - + $filename = 'tmp-' . time() . '.test'; + // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong.$this->dataLong ); - + $cryptedFile = file_put_contents('crypt://' . $filename, $this->dataLong . $this->dataLong); + // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); - + $this->assertTrue(is_int($cryptedFile)); + // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + // Get file contents without using any wrapper to get it's actual contents on disk + $retreivedCryptedFile = $this->view->file_get_contents($this->userId . '/files/' . $filename); - // Get file contents without using any wrapper to get it's actual contents on disk - $retreivedCryptedFile = $this->view->file_get_contents($this->userId . '/files/' . $filename); + // Re-enable proxy - our work is done + \OC_FileProxy::$enabled = $proxyStatus; - // Re-enable proxy - our work is done - \OC_FileProxy::$enabled = $proxyStatus; + // Check that the file was encrypted before being written to disk + $this->assertNotEquals($this->dataLong . $this->dataLong, $retreivedCryptedFile); - // Check that the file was encrypted before being written to disk - $this->assertNotEquals( $this->dataLong.$this->dataLong, $retreivedCryptedFile ); - // Manuallly split saved file into separate IVs and encrypted chunks $r = preg_split('/(00iv00.{16,18})/', $retreivedCryptedFile, NULL, PREG_SPLIT_DELIM_CAPTURE); - + //print_r($r); - + // Join IVs and their respective data chunks - $e = array( $r[0].$r[1], $r[2].$r[3], $r[4].$r[5], $r[6].$r[7], $r[8].$r[9], $r[10].$r[11]);//.$r[11], $r[12].$r[13], $r[14] ); - + $e = array($r[0] . $r[1], $r[2] . $r[3], $r[4] . $r[5], $r[6] . $r[7], $r[8] . $r[9], $r[10] . $r[11]); //.$r[11], $r[12].$r[13], $r[14] ); + //print_r($e); - // Get the encrypted keyfile - $encKeyfile = Encryption\Keymanager::getFileKey( $this->view, $this->userId, $filename ); + // Get the encrypted keyfile + $encKeyfile = Encryption\Keymanager::getFileKey($this->view, $this->userId, $filename); - // Attempt to fetch the user's shareKey - $shareKey = Encryption\Keymanager::getShareKey( $this->view, $this->userId, $filename ); + // Attempt to fetch the user's shareKey + $shareKey = Encryption\Keymanager::getShareKey($this->view, $this->userId, $filename); - // get session - $session = new Encryption\Session( $this->view ); + // get session + $session = new Encryption\Session($this->view); - // get private key - $privateKey = $session->getPrivateKey( $this->userId ); + // get private key + $privateKey = $session->getPrivateKey($this->userId); - // Decrypt keyfile with shareKey - $plainKeyfile = Encryption\Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); + // Decrypt keyfile with shareKey + $plainKeyfile = Encryption\Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); // Set var for reassembling decrypted content $decrypt = ''; - + // Manually decrypt chunk foreach ($e as $chunk) { - - $chunkDecrypt = Encryption\Crypt::symmetricDecryptFileContent( $chunk, $plainKeyfile ); - + + $chunkDecrypt = Encryption\Crypt::symmetricDecryptFileContent($chunk, $plainKeyfile); + // Assemble decrypted chunks $decrypt .= $chunkDecrypt; - + } - - $this->assertEquals( $this->dataLong.$this->dataLong, $decrypt ); - + + $this->assertEquals($this->dataLong . $this->dataLong, $decrypt); + // Teardown - - $this->view->unlink( $this->userId . '/files/' . $filename ); - - Encryption\Keymanager::deleteFileKey( $this->view, $this->userId, $filename ); - + + $this->view->unlink($this->userId . '/files/' . $filename); + + Encryption\Keymanager::deleteFileKey($this->view, $this->userId, $filename); + } - + /** * @brief Test that data that is read by the crypto stream wrapper */ - function testSymmetricStreamDecryptShortFileContent() { - - $filename = 'tmp-'.time(); - + function testSymmetricStreamDecryptShortFileContent() + { + + $filename = 'tmp-' . time(); + // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataShort ); - + $cryptedFile = file_put_contents('crypt://' . $filename, $this->dataShort); + // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; @@ -387,34 +402,35 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { \OC_FileProxy::$enabled = $proxyStatus; - // Get file decrypted contents - $decrypt = file_get_contents( 'crypt://' . $filename ); - - $this->assertEquals( $this->dataShort, $decrypt ); + // Get file decrypted contents + $decrypt = file_get_contents('crypt://' . $filename); + + $this->assertEquals($this->dataShort, $decrypt); - // tear down - $this->view->unlink( $this->userId . '/files/' . $filename ); + // tear down + $this->view->unlink($this->userId . '/files/' . $filename); } - - function testSymmetricStreamDecryptLongFileContent() { - - $filename = 'tmp-'.time(); - + + function testSymmetricStreamDecryptLongFileContent() + { + + $filename = 'tmp-' . time(); + // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong ); - + $cryptedFile = file_put_contents('crypt://' . $filename, $this->dataLong); + // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); - // Get file decrypted contents - $decrypt = file_get_contents( 'crypt://' . $filename ); + // Get file decrypted contents + $decrypt = file_get_contents('crypt://' . $filename); - $this->assertEquals( $this->dataLong, $decrypt ); + $this->assertEquals($this->dataLong, $decrypt); - // tear down - $this->view->unlink( $this->userId . '/files/' . $filename ); + // tear down + $this->view->unlink($this->userId . '/files/' . $filename); } - + // Is this test still necessary? // function testSymmetricBlockStreamDecryptFileContent() { // @@ -438,260 +454,274 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { // // } - function testSymmetricEncryptFileContentKeyfile() { - + function testSymmetricEncryptFileContentKeyfile() + { + # TODO: search in keyfile for actual content as IV will ensure this test always passes - - $crypted = Encryption\Crypt::symmetricEncryptFileContentKeyfile( $this->dataUrl ); - - $this->assertNotEquals( $this->dataUrl, $crypted['encrypted'] ); - - - $decrypt = Encryption\Crypt::symmetricDecryptFileContent( $crypted['encrypted'], $crypted['key'] ); - - $this->assertEquals( $this->dataUrl, $decrypt ); - - } - - function testIsEncryptedContent() { - - $this->assertFalse( Encryption\Crypt::isCatfileContent( $this->dataUrl ) ); - - $this->assertFalse( Encryption\Crypt::isCatfileContent( $this->legacyEncryptedData ) ); - - $keyfileContent = Encryption\Crypt::symmetricEncryptFileContent( $this->dataUrl, 'hat' ); - - $this->assertTrue( Encryption\Crypt::isCatfileContent( $keyfileContent ) ); - - } - - function testMultiKeyEncrypt() { - + + $crypted = Encryption\Crypt::symmetricEncryptFileContentKeyfile($this->dataUrl); + + $this->assertNotEquals($this->dataUrl, $crypted['encrypted']); + + + $decrypt = Encryption\Crypt::symmetricDecryptFileContent($crypted['encrypted'], $crypted['key']); + + $this->assertEquals($this->dataUrl, $decrypt); + + } + + function testIsEncryptedContent() + { + + $this->assertFalse(Encryption\Crypt::isCatfileContent($this->dataUrl)); + + $this->assertFalse(Encryption\Crypt::isCatfileContent($this->legacyEncryptedData)); + + $keyfileContent = Encryption\Crypt::symmetricEncryptFileContent($this->dataUrl, 'hat'); + + $this->assertTrue(Encryption\Crypt::isCatfileContent($keyfileContent)); + + } + + function testMultiKeyEncrypt() + { + # TODO: search in keyfile for actual content as IV will ensure this test always passes - + $pair1 = Encryption\Crypt::createKeypair(); - - $this->assertEquals( 2, count( $pair1 ) ); - - $this->assertTrue( strlen( $pair1['publicKey'] ) > 1 ); - - $this->assertTrue( strlen( $pair1['privateKey'] ) > 1 ); - - - $crypted = Encryption\Crypt::multiKeyEncrypt( $this->dataShort, array( $pair1['publicKey'] ) ); - - $this->assertNotEquals( $this->dataShort, $crypted['data'] ); - - - $decrypt = Encryption\Crypt::multiKeyDecrypt( $crypted['data'], $crypted['keys'][0], $pair1['privateKey'] ); - - $this->assertEquals( $this->dataShort, $decrypt ); - - } - - function testKeyEncrypt() { - + + $this->assertEquals(2, count($pair1)); + + $this->assertTrue(strlen($pair1['publicKey']) > 1); + + $this->assertTrue(strlen($pair1['privateKey']) > 1); + + + $crypted = Encryption\Crypt::multiKeyEncrypt($this->dataShort, array($pair1['publicKey'])); + + $this->assertNotEquals($this->dataShort, $crypted['data']); + + + $decrypt = Encryption\Crypt::multiKeyDecrypt($crypted['data'], $crypted['keys'][0], $pair1['privateKey']); + + $this->assertEquals($this->dataShort, $decrypt); + + } + + function testKeyEncrypt() + { + // Generate keypair $pair1 = Encryption\Crypt::createKeypair(); - + // Encrypt data - $crypted = Encryption\Crypt::keyEncrypt( $this->dataUrl, $pair1['publicKey'] ); - - $this->assertNotEquals( $this->dataUrl, $crypted ); - + $crypted = Encryption\Crypt::keyEncrypt($this->dataUrl, $pair1['publicKey']); + + $this->assertNotEquals($this->dataUrl, $crypted); + // Decrypt data - $decrypt = Encryption\Crypt::keyDecrypt( $crypted, $pair1['privateKey'] ); - - $this->assertEquals( $this->dataUrl, $decrypt ); - + $decrypt = Encryption\Crypt::keyDecrypt($crypted, $pair1['privateKey']); + + $this->assertEquals($this->dataUrl, $decrypt); + } - + /** * @brief test encryption using legacy blowfish method */ - function testLegacyEncryptShort() { - - $crypted = Encryption\Crypt::legacyEncrypt( $this->dataShort, $this->pass ); + function testLegacyEncryptShort() + { + + $crypted = Encryption\Crypt::legacyEncrypt($this->dataShort, $this->pass); + + $this->assertNotEquals($this->dataShort, $crypted); - $this->assertNotEquals( $this->dataShort, $crypted ); - # TODO: search inencrypted text for actual content to ensure it # genuine transformation - + return $crypted; - + } - + /** * @brief test decryption using legacy blowfish method * @depends testLegacyEncryptShort */ - function testLegacyDecryptShort( $crypted ) { - - $decrypted = Encryption\Crypt::legacyDecrypt( $crypted, $this->pass ); - - $this->assertEquals( $this->dataShort, $decrypted ); - + function testLegacyDecryptShort($crypted) + { + + $decrypted = Encryption\Crypt::legacyDecrypt($crypted, $this->pass); + + $this->assertEquals($this->dataShort, $decrypted); + } /** * @brief test encryption using legacy blowfish method */ - function testLegacyEncryptLong() { - - $crypted = Encryption\Crypt::legacyEncrypt( $this->dataLong, $this->pass ); + function testLegacyEncryptLong() + { + + $crypted = Encryption\Crypt::legacyEncrypt($this->dataLong, $this->pass); + + $this->assertNotEquals($this->dataLong, $crypted); - $this->assertNotEquals( $this->dataLong, $crypted ); - # TODO: search inencrypted text for actual content to ensure it # genuine transformation - + return $crypted; - + } - + /** * @brief test decryption using legacy blowfish method * @depends testLegacyEncryptLong */ - function testLegacyDecryptLong( $crypted ) { - - $decrypted = Encryption\Crypt::legacyDecrypt( $crypted, $this->pass ); - - $this->assertEquals( $this->dataLong, $decrypted ); - - } - + function testLegacyDecryptLong($crypted) + { + + $decrypted = Encryption\Crypt::legacyDecrypt($crypted, $this->pass); + + $this->assertEquals($this->dataLong, $decrypted); + + } + /** * @brief test generation of legacy encryption key * @depends testLegacyDecryptShort */ - function testLegacyCreateKey() { - + function testLegacyCreateKey() + { + // Create encrypted key - $encKey = Encryption\Crypt::legacyCreateKey( $this->pass ); - + $encKey = Encryption\Crypt::legacyCreateKey($this->pass); + // Decrypt key - $key = Encryption\Crypt::legacyDecrypt( $encKey, $this->pass ); - - $this->assertTrue( is_numeric( $key ) ); - + $key = Encryption\Crypt::legacyDecrypt($encKey, $this->pass); + + $this->assertTrue(is_numeric($key)); + // Check that key is correct length - $this->assertEquals( 20, strlen( $key ) ); - + $this->assertEquals(20, strlen($key)); + } /** * @brief test decryption using legacy blowfish method * @depends testLegacyEncryptLong */ - function testLegacyKeyRecryptKeyfileEncrypt( $crypted ) { - - $recrypted = Encryption\Crypt::LegacyKeyRecryptKeyfile( $crypted, $this->pass, array($this->genPublicKey), $this->pass, ''); - - $this->assertNotEquals( $this->dataLong, $recrypted['data'] ); - + function testLegacyKeyRecryptKeyfileEncrypt($crypted) + { + + $recrypted = Encryption\Crypt::LegacyKeyRecryptKeyfile($crypted, $this->pass, array($this->genPublicKey), $this->pass, ''); + + $this->assertNotEquals($this->dataLong, $recrypted['data']); + return $recrypted; - + # TODO: search inencrypted text for actual content to ensure it # genuine transformation - + } - function testRenameFile() { + function testRenameFile() + { - $filename = 'tmp-'.time(); + $filename = 'tmp-' . time(); - // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong ); + // Save long data as encrypted file using stream wrapper + $cryptedFile = file_put_contents('crypt://' . $filename, $this->dataLong); - // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + // Test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); // Get file decrypted contents - $decrypt = file_get_contents( 'crypt://' . $filename ); + $decrypt = file_get_contents('crypt://' . $filename); - $this->assertEquals( $this->dataLong, $decrypt ); + $this->assertEquals($this->dataLong, $decrypt); - $newFilename = 'tmp-new-'.time(); - $view = new \OC\Files\View('/' . $this->userId . '/files'); - $view->rename( $filename, $newFilename ); + $newFilename = 'tmp-new-' . time(); + $view = new \OC\Files\View('/' . $this->userId . '/files'); + $view->rename($filename, $newFilename); - // Get file decrypted contents - $newDecrypt = file_get_contents( 'crypt://' . $newFilename ); + // Get file decrypted contents + $newDecrypt = file_get_contents('crypt://' . $newFilename); - $this->assertEquals( $this->dataLong, $newDecrypt ); + $this->assertEquals($this->dataLong, $newDecrypt); - // tear down - $view->unlink( $newFilename ); - } + // tear down + $view->unlink($newFilename); + } - function testMoveFileIntoFolder() { + function testMoveFileIntoFolder() + { - $filename = 'tmp-'.time(); + $filename = 'tmp-' . time(); - // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong ); + // Save long data as encrypted file using stream wrapper + $cryptedFile = file_put_contents('crypt://' . $filename, $this->dataLong); - // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + // Test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); - // Get file decrypted contents - $decrypt = file_get_contents( 'crypt://' . $filename ); + // Get file decrypted contents + $decrypt = file_get_contents('crypt://' . $filename); - $this->assertEquals( $this->dataLong, $decrypt ); + $this->assertEquals($this->dataLong, $decrypt); - $newFolder = '/newfolder'.time(); - $newFilename = 'tmp-new-'.time(); - $view = new \OC\Files\View('/' . $this->userId . '/files'); - $view->mkdir($newFolder); - $view->rename( $filename, $newFolder . '/' . $newFilename ); + $newFolder = '/newfolder' . time(); + $newFilename = 'tmp-new-' . time(); + $view = new \OC\Files\View('/' . $this->userId . '/files'); + $view->mkdir($newFolder); + $view->rename($filename, $newFolder . '/' . $newFilename); - // Get file decrypted contents - $newDecrypt = file_get_contents( 'crypt://' . $newFolder . '/' . $newFilename ); + // Get file decrypted contents + $newDecrypt = file_get_contents('crypt://' . $newFolder . '/' . $newFilename); - $this->assertEquals( $this->dataLong, $newDecrypt ); + $this->assertEquals($this->dataLong, $newDecrypt); - // tear down - $view->unlink( $newFolder ); - } + // tear down + $view->unlink($newFolder); + } - function testMoveFolder() { + function testMoveFolder() + { $view = new \OC\Files\View('/' . $this->userId . '/files'); - $filename = '/tmp-'.time(); - $folder = '/folder'.time(); + $filename = '/tmp-' . time(); + $folder = '/folder' . time(); $view->mkdir($folder); // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents( 'crypt://' . $folder . $filename, $this->dataLong ); + $cryptedFile = file_put_contents('crypt://' . $folder . $filename, $this->dataLong); // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); // Get file decrypted contents - $decrypt = file_get_contents( 'crypt://' . $folder . $filename ); + $decrypt = file_get_contents('crypt://' . $folder . $filename); - $this->assertEquals( $this->dataLong, $decrypt ); + $this->assertEquals($this->dataLong, $decrypt); - $newFolder = '/newfolder'.time(); + $newFolder = '/newfolder' . time(); - $view->rename( $folder, $newFolder ); + $view->rename($folder, $newFolder); // Get file decrypted contents - $newDecrypt = file_get_contents( 'crypt://' . $newFolder . $filename ); + $newDecrypt = file_get_contents('crypt://' . $newFolder . $filename); - $this->assertEquals( $this->dataLong, $newDecrypt ); + $this->assertEquals($this->dataLong, $newDecrypt); // tear down - $view->unlink( $newFolder ); + $view->unlink($newFolder); } - function testRenameFolder() { + function testRenameFolder() + { - $filename = '/tmp-'.time(); + $filename = '/tmp-' . time(); $folder = '/folder'; $newFolder = '/newfolder'; @@ -699,42 +729,43 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { $view->mkdir($folder); // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents( 'crypt://' . $folder . $filename, $this->dataLong ); + $cryptedFile = file_put_contents('crypt://' . $folder . $filename, $this->dataLong); // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); // Get file decrypted contents - $decrypt = file_get_contents( 'crypt://' . $folder . $filename ); + $decrypt = file_get_contents('crypt://' . $folder . $filename); - $this->assertEquals( $this->dataLong, $decrypt ); + $this->assertEquals($this->dataLong, $decrypt); // rename folder $view->rename($folder, $newFolder); // Get file decrypted contents - $newDecrypt = file_get_contents( 'crypt://' . $newFolder . $filename ); + $newDecrypt = file_get_contents('crypt://' . $newFolder . $filename); - $this->assertEquals( $this->dataLong, $newDecrypt ); + $this->assertEquals($this->dataLong, $newDecrypt); // tear down - $view->unlink( $newFolder ); + $view->unlink($newFolder); } - function testChangePassphrase() { + function testChangePassphrase() + { - $filename = 'tmp-'.time(); + $filename = 'tmp-' . time(); // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong ); + $cryptedFile = file_put_contents('crypt://' . $filename, $this->dataLong); // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); // Get file decrypted contents - $decrypt = file_get_contents( 'crypt://' . $filename ); + $decrypt = file_get_contents('crypt://' . $filename); - $this->assertEquals( $this->dataLong, $decrypt ); + $this->assertEquals($this->dataLong, $decrypt); // change password \OC_User::setPassword($this->userId, 'test', null); @@ -745,109 +776,113 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { OCA\Encryption\Hooks::login($params); // Get file decrypted contents - $newDecrypt = file_get_contents( 'crypt://' . $filename ); + $newDecrypt = file_get_contents('crypt://' . $filename); - $this->assertEquals( $this->dataLong, $newDecrypt ); + $this->assertEquals($this->dataLong, $newDecrypt); // tear down // change password back \OC_User::setPassword($this->userId, $this->pass); $view = new \OC\Files\View('/' . $this->userId . '/files'); - $view->unlink( $filename ); + $view->unlink($filename); } - function testViewFilePutAndGetContents() { + function testViewFilePutAndGetContents() + { - $filename = '/tmp-'.time(); + $filename = '/tmp-' . time(); $view = new \OC\Files\View('/' . $this->userId . '/files'); // Save short data as encrypted file using stream wrapper - $cryptedFile = $view->file_put_contents( $filename, $this->dataShort ); + $cryptedFile = $view->file_put_contents($filename, $this->dataShort); // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); // Get file decrypted contents - $decrypt = $view->file_get_contents( $filename ); + $decrypt = $view->file_get_contents($filename); - $this->assertEquals( $this->dataShort, $decrypt ); + $this->assertEquals($this->dataShort, $decrypt); // Save long data as encrypted file using stream wrapper - $cryptedFileLong = $view->file_put_contents( $filename, $this->dataLong ); + $cryptedFileLong = $view->file_put_contents($filename, $this->dataLong); // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFileLong ) ); + $this->assertTrue(is_int($cryptedFileLong)); // Get file decrypted contents - $decryptLong = $view->file_get_contents( $filename ); + $decryptLong = $view->file_get_contents($filename); - $this->assertEquals( $this->dataLong, $decryptLong ); + $this->assertEquals($this->dataLong, $decryptLong); // tear down - $view->unlink( $filename ); + $view->unlink($filename); } - function testTouchExistingFile() { - $filename = '/tmp-'.time(); + function testTouchExistingFile() + { + $filename = '/tmp-' . time(); $view = new \OC\Files\View('/' . $this->userId . '/files'); // Save short data as encrypted file using stream wrapper - $cryptedFile = $view->file_put_contents( $filename, $this->dataShort ); + $cryptedFile = $view->file_put_contents($filename, $this->dataShort); // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); $view->touch($filename); // Get file decrypted contents - $decrypt = $view->file_get_contents( $filename ); + $decrypt = $view->file_get_contents($filename); - $this->assertEquals( $this->dataShort, $decrypt ); + $this->assertEquals($this->dataShort, $decrypt); // tear down - $view->unlink( $filename ); + $view->unlink($filename); } - function testTouchFile() { - $filename = '/tmp-'.time(); + function testTouchFile() + { + $filename = '/tmp-' . time(); $view = new \OC\Files\View('/' . $this->userId . '/files'); $view->touch($filename); // Save short data as encrypted file using stream wrapper - $cryptedFile = $view->file_put_contents( $filename, $this->dataShort ); + $cryptedFile = $view->file_put_contents($filename, $this->dataShort); // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); // Get file decrypted contents - $decrypt = $view->file_get_contents( $filename ); + $decrypt = $view->file_get_contents($filename); - $this->assertEquals( $this->dataShort, $decrypt ); + $this->assertEquals($this->dataShort, $decrypt); // tear down - $view->unlink( $filename ); + $view->unlink($filename); } - function testFopenFile() { - $filename = '/tmp-'.time(); + function testFopenFile() + { + $filename = '/tmp-' . time(); $view = new \OC\Files\View('/' . $this->userId . '/files'); // Save short data as encrypted file using stream wrapper - $cryptedFile = $view->file_put_contents( $filename, $this->dataShort ); + $cryptedFile = $view->file_put_contents($filename, $this->dataShort); // Test that data was successfully written - $this->assertTrue( is_int( $cryptedFile ) ); + $this->assertTrue(is_int($cryptedFile)); $handle = $view->fopen($filename, 'r'); // Get file decrypted contents $decrypt = fgets($handle); - $this->assertEquals( $this->dataShort, $decrypt ); + $this->assertEquals($this->dataShort, $decrypt); // tear down - $view->unlink( $filename ); + $view->unlink($filename); } // function testEncryption(){ // @@ -912,5 +947,5 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { // $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key,strlen($source)); // $this->assertEquals($decrypted,$source); // } - + } diff --git a/apps/files_encryption/tests/keymanager.php b/apps/files_encryption/tests/keymanager.php index 8ca8b0287e4..334cc743f2c 100644 --- a/apps/files_encryption/tests/keymanager.php +++ b/apps/files_encryption/tests/keymanager.php @@ -6,21 +6,22 @@ * See the COPYING-README file. */ -require_once realpath( dirname(__FILE__).'/../../../lib/base.php' ); -require_once realpath( dirname(__FILE__).'/../lib/crypt.php' ); -require_once realpath( dirname(__FILE__).'/../lib/keymanager.php' ); -require_once realpath( dirname(__FILE__).'/../lib/proxy.php' ); -require_once realpath( dirname(__FILE__).'/../lib/stream.php' ); -require_once realpath( dirname(__FILE__).'/../lib/util.php' ); -require_once realpath( dirname(__FILE__).'/../lib/helper.php' ); -require_once realpath( dirname(__FILE__).'/../appinfo/app.php' ); +require_once realpath(dirname(__FILE__) . '/../../../lib/base.php'); +require_once realpath(dirname(__FILE__) . '/../lib/crypt.php'); +require_once realpath(dirname(__FILE__) . '/../lib/keymanager.php'); +require_once realpath(dirname(__FILE__) . '/../lib/proxy.php'); +require_once realpath(dirname(__FILE__) . '/../lib/stream.php'); +require_once realpath(dirname(__FILE__) . '/../lib/util.php'); +require_once realpath(dirname(__FILE__) . '/../lib/helper.php'); +require_once realpath(dirname(__FILE__) . '/../appinfo/app.php'); use OCA\Encryption; /** * Class Test_Encryption_Keymanager */ -class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { +class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase +{ public $userId; public $pass; @@ -31,38 +32,39 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { public $view; public $randomKey; - function setUp() { - // reset backend - \OC_User::clearBackends(); - \OC_User::useBackend('database'); + function setUp() + { + // reset backend + \OC_User::clearBackends(); + \OC_User::useBackend('database'); \OC_FileProxy::$enabled = false; - + // set content for encrypting / decrypting in tests - $this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) ); + $this->dataLong = file_get_contents(realpath(dirname(__FILE__) . '/../lib/crypt.php')); $this->dataShort = 'hats'; - $this->dataUrl = realpath( dirname(__FILE__).'/../lib/crypt.php' ); - $this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' ); - $this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' ); + $this->dataUrl = realpath(dirname(__FILE__) . '/../lib/crypt.php'); + $this->legacyData = realpath(dirname(__FILE__) . '/legacy-text.txt'); + $this->legacyEncryptedData = realpath(dirname(__FILE__) . '/legacy-encrypted-text.txt'); $this->randomKey = Encryption\Crypt::generateKey(); - + $keypair = Encryption\Crypt::createKeypair(); - $this->genPublicKey = $keypair['publicKey']; + $this->genPublicKey = $keypair['publicKey']; $this->genPrivateKey = $keypair['privateKey']; - $this->view = new \OC_FilesystemView( '/' ); + $this->view = new \OC_FilesystemView('/'); - \OC_User::setUserId( 'admin' ); - $this->userId = 'admin'; - $this->pass = 'admin'; + \OC_User::setUserId('admin'); + $this->userId = 'admin'; + $this->pass = 'admin'; - $userHome = \OC_User::getHome($this->userId); - $this->dataDir = str_replace('/'.$this->userId, '', $userHome); + $userHome = \OC_User::getHome($this->userId); + $this->dataDir = str_replace('/' . $this->userId, '', $userHome); - // Filesystem related hooks - \OCA\Encryption\Helper::registerFilesystemHooks(); + // Filesystem related hooks + \OCA\Encryption\Helper::registerFilesystemHooks(); - \OC_FileProxy::register(new OCA\Encryption\Proxy()); + \OC_FileProxy::register(new OCA\Encryption\Proxy()); // remember files_trashbin state $this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin'); @@ -70,19 +72,20 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { // we don't want to tests with app files_trashbin enabled \OC_App::disable('files_trashbin'); - \OC_Util::tearDownFS(); - \OC_User::setUserId(''); - \OC\Files\Filesystem::tearDown(); - \OC_Util::setupFS($this->userId); - \OC_User::setUserId($this->userId); + \OC_Util::tearDownFS(); + \OC_User::setUserId(''); + \OC\Files\Filesystem::tearDown(); + \OC_Util::setupFS($this->userId); + \OC_User::setUserId($this->userId); - $params['uid'] = $this->userId; - $params['password'] = $this->pass; - OCA\Encryption\Hooks::login($params); + $params['uid'] = $this->userId; + $params['password'] = $this->pass; + OCA\Encryption\Hooks::login($params); } - - function tearDown(){ - + + function tearDown() + { + \OC_FileProxy::$enabled = true; \OC_FileProxy::clearProxies(); @@ -94,11 +97,12 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { } } - function testGetPrivateKey() { - - $key = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId ); + function testGetPrivateKey() + { + + $key = Encryption\Keymanager::getPrivateKey($this->view, $this->userId); - $privateKey = Encryption\Crypt::symmetricDecryptFileContent( $key, $this->pass); + $privateKey = Encryption\Crypt::symmetricDecryptFileContent($key, $this->pass); $res = openssl_pkey_get_private($privateKey); @@ -107,12 +111,13 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { $sslInfo = openssl_pkey_get_details($res); $this->assertArrayHasKey('key', $sslInfo); - + } - - function testGetPublicKey() { - $publiceKey = Encryption\Keymanager::getPublicKey( $this->view, $this->userId ); + function testGetPublicKey() + { + + $publiceKey = Encryption\Keymanager::getPublicKey($this->view, $this->userId); $res = openssl_pkey_get_public($publiceKey); @@ -122,40 +127,41 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { $this->assertArrayHasKey('key', $sslInfo); } - - function testSetFileKey() { - + + function testSetFileKey() + { + # NOTE: This cannot be tested until we are able to break out # of the FileSystemView data directory root - - $key = Encryption\Crypt::symmetricEncryptFileContentKeyfile( $this->randomKey, 'hat' ); - - $file = 'unittest-'.time().'.txt'; - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + $key = Encryption\Crypt::symmetricEncryptFileContentKeyfile($this->randomKey, 'hat'); + + $file = 'unittest-' . time() . '.txt'; - $this->view->file_put_contents($this->userId . '/files/' . $file, $key['encrypted']); + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // Re-enable proxy - our work is done - \OC_FileProxy::$enabled = $proxyStatus; + $this->view->file_put_contents($this->userId . '/files/' . $file, $key['encrypted']); + + // Re-enable proxy - our work is done + \OC_FileProxy::$enabled = $proxyStatus; //$view = new \OC_FilesystemView( '/' . $this->userId . '/files_encryption/keyfiles' ); - Encryption\Keymanager::setFileKey( $this->view, $file, $this->userId, $key['key'] ); + Encryption\Keymanager::setFileKey($this->view, $file, $this->userId, $key['key']); // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = true; // cleanup - $this->view->unlink('/'.$this->userId . '/files/' . $file); + $this->view->unlink('/' . $this->userId . '/files/' . $file); // Re-enable proxy - our work is done \OC_FileProxy::$enabled = $proxyStatus; - + } - + // /** // * @depends testGetPrivateKey // */ @@ -171,10 +177,11 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { // $this->assertEquals( '-----BEGIN PRIVATE KEY-----', substr( $decrypted, 0, 27 ) ); // // } - - function testGetUserKeys() { - - $keys = Encryption\Keymanager::getUserKeys( $this->view, $this->userId ); + + function testGetUserKeys() + { + + $keys = Encryption\Keymanager::getUserKeys($this->view, $this->userId); $resPublic = openssl_pkey_get_public($keys['publicKey']); @@ -184,7 +191,7 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { $this->assertArrayHasKey('key', $sslInfoPublic); - $privateKey = Encryption\Crypt::symmetricDecryptFileContent( $keys['privateKey'], $this->pass); + $privateKey = Encryption\Crypt::symmetricDecryptFileContent($keys['privateKey'], $this->pass); $resPrivate = openssl_pkey_get_private($privateKey); diff --git a/apps/files_encryption/tests/share.php b/apps/files_encryption/tests/share.php index efff8e322e4..a9ee8d00235 100755 --- a/apps/files_encryption/tests/share.php +++ b/apps/files_encryption/tests/share.php @@ -50,446 +50,446 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase public $subsubfolder; function setUp() - { - // reset backend - \OC_User::clearBackends(); - \OC_User::useBackend('database'); + { + // reset backend + \OC_User::clearBackends(); + \OC_User::useBackend('database'); - $this->dataShort = 'hats'; - $this->view = new \OC_FilesystemView('/'); + $this->dataShort = 'hats'; + $this->view = new \OC_FilesystemView('/'); - $userHome = \OC_User::getHome('admin'); - $this->dataDir = str_replace('/admin', '', $userHome); + $userHome = \OC_User::getHome('admin'); + $this->dataDir = str_replace('/admin', '', $userHome); - $this->folder1 = '/folder1'; - $this->subfolder = '/subfolder1'; - $this->subsubfolder = '/subsubfolder1'; + $this->folder1 = '/folder1'; + $this->subfolder = '/subfolder1'; + $this->subsubfolder = '/subsubfolder1'; - $this->filename = 'share-tmp.test'; + $this->filename = 'share-tmp.test'; - // enable resharing - \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'yes'); + // enable resharing + \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'yes'); - // clear share hooks - \OC_Hook::clear('OCP\\Share'); - \OC::registerShareHooks(); - \OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup'); + // clear share hooks + \OC_Hook::clear('OCP\\Share'); + \OC::registerShareHooks(); + \OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup'); - // Sharing related hooks - \OCA\Encryption\Helper::registerShareHooks(); + // Sharing related hooks + \OCA\Encryption\Helper::registerShareHooks(); - // Filesystem related hooks - \OCA\Encryption\Helper::registerFilesystemHooks(); + // Filesystem related hooks + \OCA\Encryption\Helper::registerFilesystemHooks(); - \OC_FileProxy::register(new OCA\Encryption\Proxy()); + \OC_FileProxy::register(new OCA\Encryption\Proxy()); - // remember files_trashbin state - $this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin'); + // remember files_trashbin state + $this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin'); - // we don't want to tests with app files_trashbin enabled - \OC_App::disable('files_trashbin'); + // we don't want to tests with app files_trashbin enabled + \OC_App::disable('files_trashbin'); - // create users - $this->loginHelper('user1', true); - $this->loginHelper('user2', true); - $this->loginHelper('user3', true); + // create users + $this->loginHelper('user1', true); + $this->loginHelper('user2', true); + $this->loginHelper('user3', true); // create group and assign users \OC_Group::createGroup('group1'); \OC_Group::addToGroup('user2', 'group1'); \OC_Group::addToGroup('user3', 'group1'); - } + } - function tearDown() - { - // reset app files_trashbin - if ($this->stateFilesTrashbin) { - OC_App::enable('files_trashbin'); - } else { - OC_App::disable('files_trashbin'); - } + function tearDown() + { + // reset app files_trashbin + if ($this->stateFilesTrashbin) { + OC_App::enable('files_trashbin'); + } else { + OC_App::disable('files_trashbin'); + } // clean group \OC_Group::deleteGroup('group1'); - // cleanup users - \OC_User::deleteUser('user1'); - \OC_User::deleteUser('user2'); - \OC_User::deleteUser('user3'); + // cleanup users + \OC_User::deleteUser('user1'); + \OC_User::deleteUser('user2'); + \OC_User::deleteUser('user3'); \OC_FileProxy::clearProxies(); - } + } /** * @param bool $withTeardown */ function testShareFile($withTeardown = true) - { - // login as admin - $this->loginHelper('admin'); + { + // login as admin + $this->loginHelper('admin'); - // save file with content - $cryptedFile = file_put_contents('crypt://' . $this->filename, $this->dataShort); + // save file with content + $cryptedFile = file_put_contents('crypt://' . $this->filename, $this->dataShort); - // test that data was successfully written - $this->assertTrue(is_int($cryptedFile)); + // test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); - // disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // get the file info from previous created file - $fileInfo = $this->view->getFileInfo('/admin/files/' . $this->filename); + // get the file info from previous created file + $fileInfo = $this->view->getFileInfo('/admin/files/' . $this->filename); - // check if we have a valid file info - $this->assertTrue(is_array($fileInfo)); + // check if we have a valid file info + $this->assertTrue(is_array($fileInfo)); - // check if the unencrypted file size is stored - $this->assertGreaterThan(0, $fileInfo['unencrypted_size']); + // check if the unencrypted file size is stored + $this->assertGreaterThan(0, $fileInfo['unencrypted_size']); - // re-enable the file proxy - \OC_FileProxy::$enabled = $proxyStatus; + // re-enable the file proxy + \OC_FileProxy::$enabled = $proxyStatus; - // share the file - \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1', OCP\PERMISSION_ALL); + // share the file + \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1', OCP\PERMISSION_ALL); - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // check if share key for user1 exists - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey')); + // check if share key for user1 exists + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey')); - // login as user1 - $this->loginHelper('user1'); + // login as user1 + $this->loginHelper('user1'); - // get file contents - $retrievedCryptedFile = $this->view->file_get_contents('/user1/files/Shared/' . $this->filename); + // get file contents + $retrievedCryptedFile = $this->view->file_get_contents('/user1/files/Shared/' . $this->filename); - // check if data is the same as we previously written - $this->assertEquals($this->dataShort, $retrievedCryptedFile); + // check if data is the same as we previously written + $this->assertEquals($this->dataShort, $retrievedCryptedFile); - // cleanup - if ($withTeardown) { + // cleanup + if ($withTeardown) { - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // unshare the file - \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1'); + // unshare the file + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1'); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey')); + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey')); - // cleanup - $this->view->unlink('/admin/files/' . $this->filename); + // cleanup + $this->view->unlink('/admin/files/' . $this->filename); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey')); - } - } + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey')); + } + } /** * @param bool $withTeardown */ function testReShareFile($withTeardown = true) - { - $this->testShareFile(false); + { + $this->testShareFile(false); - // login as user1 - $this->loginHelper('user1'); + // login as user1 + $this->loginHelper('user1'); - // get the file info - $fileInfo = $this->view->getFileInfo('/user1/files/Shared/' . $this->filename); + // get the file info + $fileInfo = $this->view->getFileInfo('/user1/files/Shared/' . $this->filename); - // share the file with user2 - \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2', OCP\PERMISSION_ALL); + // share the file with user2 + \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2', OCP\PERMISSION_ALL); - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // check if share key for user2 exists - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user2.shareKey')); + // check if share key for user2 exists + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user2.shareKey')); - // login as user2 - $this->loginHelper('user2'); + // login as user2 + $this->loginHelper('user2'); - // get file contents - $retrievedCryptedFile = $this->view->file_get_contents('/user2/files/Shared/' . $this->filename); + // get file contents + $retrievedCryptedFile = $this->view->file_get_contents('/user2/files/Shared/' . $this->filename); - // check if data is the same as previously written - $this->assertEquals($this->dataShort, $retrievedCryptedFile); + // check if data is the same as previously written + $this->assertEquals($this->dataShort, $retrievedCryptedFile); - // cleanup - if ($withTeardown) { + // cleanup + if ($withTeardown) { - // login as user1 - $this->loginHelper('user1'); + // login as user1 + $this->loginHelper('user1'); - // unshare the file with user2 - \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2'); + // unshare the file with user2 + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2'); - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user2.shareKey')); + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user2.shareKey')); - // unshare the file with user1 - \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1'); + // unshare the file with user1 + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1'); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey')); + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey')); - // cleanup - $this->view->unlink('/admin/files/' . $this->filename); + // cleanup + $this->view->unlink('/admin/files/' . $this->filename); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey')); - } - } + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey')); + } + } /** * @param bool $withTeardown * @return array */ function testShareFolder($withTeardown = true) - { - // login as admin - $this->loginHelper('admin'); + { + // login as admin + $this->loginHelper('admin'); - // create folder structure - $this->view->mkdir('/admin/files' . $this->folder1); - $this->view->mkdir('/admin/files' . $this->folder1 . $this->subfolder); - $this->view->mkdir('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder); + // create folder structure + $this->view->mkdir('/admin/files' . $this->folder1); + $this->view->mkdir('/admin/files' . $this->folder1 . $this->subfolder); + $this->view->mkdir('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder); - // save file with content - $cryptedFile = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename, $this->dataShort); + // save file with content + $cryptedFile = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename, $this->dataShort); - // test that data was successfully written - $this->assertTrue(is_int($cryptedFile)); + // test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); - // disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // get the file info from previous created folder - $fileInfo = $this->view->getFileInfo('/admin/files' . $this->folder1); + // get the file info from previous created folder + $fileInfo = $this->view->getFileInfo('/admin/files' . $this->folder1); - // check if we have a valid file info - $this->assertTrue(is_array($fileInfo)); + // check if we have a valid file info + $this->assertTrue(is_array($fileInfo)); - // re-enable the file proxy - \OC_FileProxy::$enabled = $proxyStatus; + // re-enable the file proxy + \OC_FileProxy::$enabled = $proxyStatus; - // share the folder with user1 - \OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1', OCP\PERMISSION_ALL); + // share the folder with user1 + \OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1', OCP\PERMISSION_ALL); - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // check if share key for user1 exists - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey')); + // check if share key for user1 exists + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey')); - // login as user1 - $this->loginHelper('user1'); + // login as user1 + $this->loginHelper('user1'); - // get file contents - $retrievedCryptedFile = $this->view->file_get_contents('/user1/files/Shared' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); + // get file contents + $retrievedCryptedFile = $this->view->file_get_contents('/user1/files/Shared' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); - // check if data is the same - $this->assertEquals($this->dataShort, $retrievedCryptedFile); + // check if data is the same + $this->assertEquals($this->dataShort, $retrievedCryptedFile); - // cleanup - if ($withTeardown) { + // cleanup + if ($withTeardown) { - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // unshare the folder with user1 - \OCP\Share::unshare('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1'); + // unshare the folder with user1 + \OCP\Share::unshare('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1'); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey')); + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey')); - // cleanup - $this->view->unlink('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); + // cleanup + $this->view->unlink('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey')); - } + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey')); + } - return $fileInfo; - } + return $fileInfo; + } /** * @param bool $withTeardown */ function testReShareFolder($withTeardown = true) - { - $fileInfoFolder1 = $this->testShareFolder(false); + { + $fileInfoFolder1 = $this->testShareFolder(false); - // login as user1 - $this->loginHelper('user1'); + // login as user1 + $this->loginHelper('user1'); - // disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // get the file info from previous created folder - $fileInfoSubFolder = $this->view->getFileInfo('/user1/files/Shared' . $this->folder1 . $this->subfolder); + // get the file info from previous created folder + $fileInfoSubFolder = $this->view->getFileInfo('/user1/files/Shared' . $this->folder1 . $this->subfolder); - // check if we have a valid file info - $this->assertTrue(is_array($fileInfoSubFolder)); + // check if we have a valid file info + $this->assertTrue(is_array($fileInfoSubFolder)); - // re-enable the file proxy - \OC_FileProxy::$enabled = $proxyStatus; + // re-enable the file proxy + \OC_FileProxy::$enabled = $proxyStatus; - // share the file with user2 - \OCP\Share::shareItem('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2', OCP\PERMISSION_ALL); + // share the file with user2 + \OCP\Share::shareItem('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2', OCP\PERMISSION_ALL); - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // check if share key for user2 exists - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user2.shareKey')); + // check if share key for user2 exists + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user2.shareKey')); - // login as user2 - $this->loginHelper('user2'); + // login as user2 + $this->loginHelper('user2'); - // get file contents - $retrievedCryptedFile = $this->view->file_get_contents('/user2/files/Shared' . $this->subfolder . $this->subsubfolder . '/' . $this->filename); + // get file contents + $retrievedCryptedFile = $this->view->file_get_contents('/user2/files/Shared' . $this->subfolder . $this->subsubfolder . '/' . $this->filename); - // check if data is the same - $this->assertEquals($this->dataShort, $retrievedCryptedFile); + // check if data is the same + $this->assertEquals($this->dataShort, $retrievedCryptedFile); - // get the file info - $fileInfo = $this->view->getFileInfo('/user2/files/Shared' . $this->subfolder . $this->subsubfolder . '/' . $this->filename); + // get the file info + $fileInfo = $this->view->getFileInfo('/user2/files/Shared' . $this->subfolder . $this->subsubfolder . '/' . $this->filename); - // check if we have fileInfos - $this->assertTrue(is_array($fileInfo)); + // check if we have fileInfos + $this->assertTrue(is_array($fileInfo)); - // share the file with user3 - \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user3', OCP\PERMISSION_ALL); + // share the file with user3 + \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user3', OCP\PERMISSION_ALL); - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // check if share key for user3 exists - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user3.shareKey')); + // check if share key for user3 exists + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user3.shareKey')); - // login as user3 - $this->loginHelper('user3'); + // login as user3 + $this->loginHelper('user3'); - // get file contents - $retrievedCryptedFile = $this->view->file_get_contents('/user3/files/Shared/' . $this->filename); + // get file contents + $retrievedCryptedFile = $this->view->file_get_contents('/user3/files/Shared/' . $this->filename); - // check if data is the same - $this->assertEquals($this->dataShort, $retrievedCryptedFile); + // check if data is the same + $this->assertEquals($this->dataShort, $retrievedCryptedFile); - // cleanup - if ($withTeardown) { + // cleanup + if ($withTeardown) { - // login as user2 - $this->loginHelper('user2'); + // login as user2 + $this->loginHelper('user2'); - // unshare the file with user3 - \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user3'); + // unshare the file with user3 + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user3'); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user3.shareKey')); + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user3.shareKey')); - // login as user1 - $this->loginHelper('user1'); + // login as user1 + $this->loginHelper('user1'); - // unshare the folder with user2 - \OCP\Share::unshare('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2'); + // unshare the folder with user2 + \OCP\Share::unshare('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2'); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user2.shareKey')); + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user2.shareKey')); - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // unshare the folder1 with user1 - \OCP\Share::unshare('folder', $fileInfoFolder1['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1'); + // unshare the folder1 with user1 + \OCP\Share::unshare('folder', $fileInfoFolder1['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1'); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey')); + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey')); - // cleanup - $this->view->unlink('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); + // cleanup + $this->view->unlink('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey')); - } - } + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey')); + } + } - function testPublicShareFile() - { - // login as admin - $this->loginHelper('admin'); + function testPublicShareFile() + { + // login as admin + $this->loginHelper('admin'); - // save file with content - $cryptedFile = file_put_contents('crypt://' . $this->filename, $this->dataShort); + // save file with content + $cryptedFile = file_put_contents('crypt://' . $this->filename, $this->dataShort); - // test that data was successfully written - $this->assertTrue(is_int($cryptedFile)); + // test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); - // disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // get the file info from previous created file - $fileInfo = $this->view->getFileInfo('/admin/files/' . $this->filename); + // get the file info from previous created file + $fileInfo = $this->view->getFileInfo('/admin/files/' . $this->filename); - // check if we have a valid file info - $this->assertTrue(is_array($fileInfo)); + // check if we have a valid file info + $this->assertTrue(is_array($fileInfo)); - // check if the unencrypted file size is stored - $this->assertGreaterThan(0, $fileInfo['unencrypted_size']); + // check if the unencrypted file size is stored + $this->assertGreaterThan(0, $fileInfo['unencrypted_size']); - // re-enable the file proxy - \OC_FileProxy::$enabled = $proxyStatus; + // re-enable the file proxy + \OC_FileProxy::$enabled = $proxyStatus; - // share the file - \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, false, OCP\PERMISSION_ALL); + // share the file + \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, false, OCP\PERMISSION_ALL); - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); + $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); - // check if share key for public exists - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $publicShareKeyId . '.shareKey')); + // check if share key for public exists + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $publicShareKeyId . '.shareKey')); - // some hacking to simulate public link - $GLOBALS['app'] = 'files_sharing'; - $GLOBALS['fileOwner'] = 'admin'; - \OC_User::setUserId(''); + // some hacking to simulate public link + $GLOBALS['app'] = 'files_sharing'; + $GLOBALS['fileOwner'] = 'admin'; + \OC_User::setUserId(''); - // get file contents - $retrievedCryptedFile = file_get_contents('crypt://' . $this->filename); + // get file contents + $retrievedCryptedFile = file_get_contents('crypt://' . $this->filename); - // check if data is the same as we previously written - $this->assertEquals($this->dataShort, $retrievedCryptedFile); + // check if data is the same as we previously written + $this->assertEquals($this->dataShort, $retrievedCryptedFile); - // tear down + // tear down - // login as admin - $this->loginHelper('admin'); + // login as admin + $this->loginHelper('admin'); - // unshare the file - \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null); + // unshare the file + \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $publicShareKeyId . '.shareKey')); + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $publicShareKeyId . '.shareKey')); - // cleanup - $this->view->unlink('/admin/files/' . $this->filename); + // cleanup + $this->view->unlink('/admin/files/' . $this->filename); - // check if share key not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey')); - } + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey')); + } function testShareFileWithGroup() { @@ -581,7 +581,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase // save file with content $cryptedFile1 = file_put_contents('crypt://' . $this->filename, $this->dataShort); - $cryptedFile2 = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename, $this->dataShort); + $cryptedFile2 = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename, $this->dataShort); // test that data was successfully written $this->assertTrue(is_int($cryptedFile1)); @@ -589,9 +589,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase // check if share key for admin and recovery exists $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey')); - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey')); - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.admin.shareKey')); - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey')); + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey')); + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); // disable recovery for admin $this->assertTrue($util->setRecoveryForUser(0)); @@ -600,8 +600,8 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase $util->removeRecoveryKeys('/'); // check if share key for recovery not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey')); - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey')); + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); // enable recovery for admin $this->assertTrue($util->setRecoveryForUser(1)); @@ -610,16 +610,16 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase $util->addRecoveryKeys('/'); // check if share key for admin and recovery exists - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey')); - $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey')); + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); + $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); // cleanup $this->view->unlink('/admin/files/' . $this->filename); - $this->view->unlink('/admin/files/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename); + $this->view->unlink('/admin/files/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); // check if share key for recovery not exists - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey')); - $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey')); + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); } function testRecoveryForUser() @@ -648,7 +648,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase // save file with content $cryptedFile1 = file_put_contents('crypt://' . $this->filename, $this->dataShort); - $cryptedFile2 = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename, $this->dataShort); + $cryptedFile2 = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename, $this->dataShort); // test that data was successfully written $this->assertTrue(is_int($cryptedFile1)); @@ -656,9 +656,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase // check if share key for user and recovery exists $this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.user1.shareKey')); - $this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey')); - $this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.user1.shareKey')); - $this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey')); + $this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); + $this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey')); + $this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); // login as admin $this->loginHelper('admin'); @@ -671,7 +671,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase // get file contents $retrievedCryptedFile1 = file_get_contents('crypt://' . $this->filename); - $retrievedCryptedFile2 = file_get_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename); + $retrievedCryptedFile2 = file_get_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); // check if data is the same as we previously written $this->assertEquals($this->dataShort, $retrievedCryptedFile1); @@ -683,9 +683,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase // check if share key for user and recovery exists $this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.user1.shareKey')); - $this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey')); - $this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.user1.shareKey')); - $this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey')); + $this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); + $this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey')); + $this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); // enable recovery for admin $this->assertTrue($util->setRecoveryForUser(0)); @@ -697,23 +697,23 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase * @param bool $password */ function loginHelper($user, $create = false, $password = false) - { - if ($create) { - \OC_User::createUser($user, $user); - } + { + if ($create) { + \OC_User::createUser($user, $user); + } - if($password === false) { + if ($password === false) { $password = $user; } - \OC_Util::tearDownFS(); - \OC_User::setUserId(''); - \OC\Files\Filesystem::tearDown(); - \OC_Util::setupFS($user); - \OC_User::setUserId($user); + \OC_Util::tearDownFS(); + \OC_User::setUserId(''); + \OC\Files\Filesystem::tearDown(); + \OC_Util::setupFS($user); + \OC_User::setUserId($user); - $params['uid'] = $user; - $params['password'] = $password; - OCA\Encryption\Hooks::login($params); - } + $params['uid'] = $user; + $params['password'] = $password; + OCA\Encryption\Hooks::login($params); + } } diff --git a/apps/files_encryption/tests/util.php b/apps/files_encryption/tests/util.php index 53ac8ee8d63..57ec395342a 100755 --- a/apps/files_encryption/tests/util.php +++ b/apps/files_encryption/tests/util.php @@ -6,20 +6,21 @@ * See the COPYING-README file. */ -require_once realpath( dirname(__FILE__).'/../../../lib/base.php' ); -require_once realpath( dirname(__FILE__).'/../lib/crypt.php' ); -require_once realpath( dirname(__FILE__).'/../lib/keymanager.php' ); -require_once realpath( dirname(__FILE__).'/../lib/proxy.php' ); -require_once realpath( dirname(__FILE__).'/../lib/stream.php' ); -require_once realpath( dirname(__FILE__).'/../lib/util.php' ); -require_once realpath( dirname(__FILE__).'/../appinfo/app.php' ); +require_once realpath(dirname(__FILE__) . '/../../../lib/base.php'); +require_once realpath(dirname(__FILE__) . '/../lib/crypt.php'); +require_once realpath(dirname(__FILE__) . '/../lib/keymanager.php'); +require_once realpath(dirname(__FILE__) . '/../lib/proxy.php'); +require_once realpath(dirname(__FILE__) . '/../lib/stream.php'); +require_once realpath(dirname(__FILE__) . '/../lib/util.php'); +require_once realpath(dirname(__FILE__) . '/../appinfo/app.php'); use OCA\Encryption; /** * Class Test_Encryption_Util */ -class Test_Encryption_Util extends \PHPUnit_Framework_TestCase { +class Test_Encryption_Util extends \PHPUnit_Framework_TestCase +{ public $userId; public $encryptionDir; @@ -38,132 +39,139 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase { public $util; public $dataShort; - function setUp() { - // reset backend - \OC_User::useBackend('database'); + function setUp() + { + // reset backend + \OC_User::useBackend('database'); - \OC_User::setUserId( 'admin' ); - $this->userId = 'admin'; - $this->pass = 'admin'; + \OC_User::setUserId('admin'); + $this->userId = 'admin'; + $this->pass = 'admin'; - // set content for encrypting / decrypting in tests - $this->dataUrl = realpath( dirname(__FILE__).'/../lib/crypt.php' ); + // set content for encrypting / decrypting in tests + $this->dataUrl = realpath(dirname(__FILE__) . '/../lib/crypt.php'); $this->dataShort = 'hats'; - $this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) ); - $this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' ); - $this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' ); + $this->dataLong = file_get_contents(realpath(dirname(__FILE__) . '/../lib/crypt.php')); + $this->legacyData = realpath(dirname(__FILE__) . '/legacy-text.txt'); + $this->legacyEncryptedData = realpath(dirname(__FILE__) . '/legacy-encrypted-text.txt'); $keypair = Encryption\Crypt::createKeypair(); - - $this->genPublicKey = $keypair['publicKey']; + + $this->genPublicKey = $keypair['publicKey']; $this->genPrivateKey = $keypair['privateKey']; - - $this->publicKeyDir = '/' . 'public-keys'; - $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption'; + + $this->publicKeyDir = '/' . 'public-keys'; + $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption'; $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key $this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key - $this->view = new \OC_FilesystemView( '/' ); + $this->view = new \OC_FilesystemView('/'); - $userHome = \OC_User::getHome($this->userId); - $this->dataDir = str_replace('/'.$this->userId, '', $userHome); + $userHome = \OC_User::getHome($this->userId); + $this->dataDir = str_replace('/' . $this->userId, '', $userHome); - // Filesystem related hooks - \OCA\Encryption\Helper::registerFilesystemHooks(); + // Filesystem related hooks + \OCA\Encryption\Helper::registerFilesystemHooks(); - \OC_FileProxy::register(new OCA\Encryption\Proxy()); + \OC_FileProxy::register(new OCA\Encryption\Proxy()); - \OC_Util::tearDownFS(); - \OC_User::setUserId(''); - \OC\Files\Filesystem::tearDown(); - \OC_Util::setupFS($this->userId); - \OC_User::setUserId($this->userId); + \OC_Util::tearDownFS(); + \OC_User::setUserId(''); + \OC\Files\Filesystem::tearDown(); + \OC_Util::setupFS($this->userId); + \OC_User::setUserId($this->userId); - $params['uid'] = $this->userId; - $params['password'] = $this->pass; - OCA\Encryption\Hooks::login($params); + $params['uid'] = $this->userId; + $params['password'] = $this->pass; + OCA\Encryption\Hooks::login($params); - $this->util = new Encryption\Util( $this->view, $this->userId ); + $this->util = new Encryption\Util($this->view, $this->userId); } - - function tearDown(){ - + + function tearDown() + { + \OC_FileProxy::clearProxies(); } - + /** * @brief test that paths set during User construction are correct */ - function testKeyPaths() { - - $util = new Encryption\Util( $this->view, $this->userId ); - - $this->assertEquals( $this->publicKeyDir, $util->getPath( 'publicKeyDir' ) ); - $this->assertEquals( $this->encryptionDir, $util->getPath( 'encryptionDir' ) ); - $this->assertEquals( $this->keyfilesPath, $util->getPath( 'keyfilesPath' ) ); - $this->assertEquals( $this->publicKeyPath, $util->getPath( 'publicKeyPath' ) ); - $this->assertEquals( $this->privateKeyPath, $util->getPath( 'privateKeyPath' ) ); - + function testKeyPaths() + { + + $util = new Encryption\Util($this->view, $this->userId); + + $this->assertEquals($this->publicKeyDir, $util->getPath('publicKeyDir')); + $this->assertEquals($this->encryptionDir, $util->getPath('encryptionDir')); + $this->assertEquals($this->keyfilesPath, $util->getPath('keyfilesPath')); + $this->assertEquals($this->publicKeyPath, $util->getPath('publicKeyPath')); + $this->assertEquals($this->privateKeyPath, $util->getPath('privateKeyPath')); + } - + /** * @brief test setup of encryption directories */ - function testSetupServerSide() { - - $this->assertEquals( true, $this->util->setupServerSide( $this->pass ) ); + function testSetupServerSide() + { + + $this->assertEquals(true, $this->util->setupServerSide($this->pass)); } - + /** * @brief test checking whether account is ready for encryption, */ - function testUserIsReady() { - - $this->assertEquals( true, $this->util->ready() ); + function testUserIsReady() + { + + $this->assertEquals(true, $this->util->ready()); } - - function testRecoveryEnabledForUser() { - - $util = new Encryption\Util( $this->view, $this->userId ); - + + function testRecoveryEnabledForUser() + { + + $util = new Encryption\Util($this->view, $this->userId); + // Record the value so we can return it to it's original state later $enabled = $util->recoveryEnabledForUser(); - - $this->assertTrue( $util->setRecoveryForUser( 1 ) ); - - $this->assertEquals( 1, $util->recoveryEnabledForUser() ); - - $this->assertTrue( $util->setRecoveryForUser( 0 ) ); - - $this->assertEquals( 0, $util->recoveryEnabledForUser() ); - + + $this->assertTrue($util->setRecoveryForUser(1)); + + $this->assertEquals(1, $util->recoveryEnabledForUser()); + + $this->assertTrue($util->setRecoveryForUser(0)); + + $this->assertEquals(0, $util->recoveryEnabledForUser()); + // Return the setting to it's previous state - $this->assertTrue( $util->setRecoveryForUser( $enabled ) ); - + $this->assertTrue($util->setRecoveryForUser($enabled)); + } - - function testGetUidAndFilename() { - - \OC_User::setUserId( 'admin' ); - $filename = 'tmp-'.time().'.test'; + function testGetUidAndFilename() + { + + \OC_User::setUserId('admin'); + + $filename = 'tmp-' . time() . '.test'; - // Disable encryption proxy to prevent recursive calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - $this->view->file_put_contents($this->userId . '/files/' . $filename, $this->dataShort); + $this->view->file_put_contents($this->userId . '/files/' . $filename, $this->dataShort); - // Re-enable proxy - our work is done - \OC_FileProxy::$enabled = $proxyStatus; + // Re-enable proxy - our work is done + \OC_FileProxy::$enabled = $proxyStatus; - $util = new Encryption\Util( $this->view, $this->userId ); + $util = new Encryption\Util($this->view, $this->userId); - list($fileOwnerUid, $file) = $util->getUidAndFilename( $filename ); + list($fileOwnerUid, $file) = $util->getUidAndFilename($filename); - $this->assertEquals('admin', $fileOwnerUid); + $this->assertEquals('admin', $fileOwnerUid); - $this->assertEquals($file, $filename); + $this->assertEquals($file, $filename); } } \ No newline at end of file -- cgit v1.2.3 From 8e0540d0e45db9470ff0d17869bab6df41bd389a Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Mon, 20 May 2013 21:22:03 +0200 Subject: key creation should never override a private or public key --- apps/files_encryption/lib/util.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 9ba7b3b3a31..8147982d483 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -212,9 +212,10 @@ class Util } // Create user keypair + // we should never override a keyfile if ( !$this->view->file_exists($this->publicKeyPath) - or !$this->view->file_exists($this->privateKeyPath) + && !$this->view->file_exists($this->privateKeyPath) ) { // Generate keypair @@ -233,6 +234,15 @@ class Util \OC_FileProxy::$enabled = true; + } else { + // check if public-key exists but private-key is missing + if($this->view->file_exists($this->publicKeyPath) && !$this->view->file_exists($this->privateKeyPath)) { + \OC_Log::write('Encryption library', 'public key exists but private key is missing for "' . $this->userId . '"', \OC_Log::FATAL); + return false; + } else if(!$this->view->file_exists($this->publicKeyPath) && $this->view->file_exists($this->privateKeyPath)) { + \OC_Log::write('Encryption library', 'private key exists but public key is missing for "' . $this->userId . '"', \OC_Log::FATAL); + return false; + } } // If there's no record for this user's encryption preferences -- cgit v1.2.3 From 1fa2f19ee44cc4a25bda784aee46ab2dac28e658 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Mon, 20 May 2013 21:24:39 +0200 Subject: removed dead code for delShareKey --- apps/files_encryption/hooks/hooks.php | 26 ++++++-------------------- apps/files_encryption/lib/keymanager.php | 26 +++++++++----------------- 2 files changed, 15 insertions(+), 37 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 087ba3d893c..90a93b4c52d 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -67,13 +67,13 @@ class Hooks { // If migration not yet done if ( ! $migrationCompleted ) { - $view1 = new \OC_FilesystemView( '/' . $params['uid'] ); + $userView = new \OC_FilesystemView( '/' . $params['uid'] ); // Set legacy encryption key if it exists, to support // depreciated encryption system - if ( - $view1->file_exists( 'encryption.key' ) - && $encLegacyKey = $view1->file_get_contents( 'encryption.key' ) + if ( + $userView->file_exists( 'encryption.key' ) + && $encLegacyKey = $userView->file_get_contents( 'encryption.key' ) ) { $plainLegacyKey = Crypt::legacyDecrypt( $encLegacyKey, $params['password'] ); @@ -412,25 +412,11 @@ class Hooks { // Unshare every user who no longer has access to the file $delUsers = array_diff( $userIds, $sharingUsers); - - if ( !Keymanager::delShareKey( $view, $delUsers, $path ) ) { - - $failed[] = $path; - - } + // delete share key + Keymanager::delShareKey( $view, $delUsers, $path ); } - // If no attempts to set keyfiles failed - if ( empty( $failed ) ) { - - return true; - - } else { - - return false; - - } } } diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 1bc334e7a17..542b1cf2876 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -540,32 +540,23 @@ class Keymanager $shareKeyPath = '/' . $owner . '/files_encryption/share-keys/' . $filename; - $result = false; - if ($view->is_dir($shareKeyPath)) { - $localPath = \OC_Filesystem::normalizePath($view->getLocalFolder($shareKeyPath)); - $result = self::recursiveDelShareKeys($localPath, $userIds); + $localPath = \OC\Files\Filesystem::normalizePath($view->getLocalFolder($shareKeyPath)); + self::recursiveDelShareKeys($localPath, $userIds); } else { foreach ($userIds as $userId) { - $view->unlink($shareKeyPath . '.' . $userId . '.shareKey'); - } - - $result = true; - } - - if (!$result) { - \OC_Log::write('Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath, \OC_Log::ERROR); + if (!$view->unlink($shareKeyPath . '.' . $userId . '.shareKey')) { + \OC_Log::write('Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath . '.' . $userId . '.shareKey"', \OC_Log::ERROR); + } + } } \OC_FileProxy::$enabled = $proxyStatus; - - return $result; - } /** @@ -582,13 +573,14 @@ class Keymanager } /** @var $matches array */ foreach ($matches as $ma) { - unlink($ma); + if (!unlink($ma)) { + \OC_Log::write('Encryption library', 'Could not delete shareKey; does not exist: "' . $ma . '"', \OC_Log::ERROR); + } } $subdirs = $directories = glob(preg_quote($dir) . '/*', GLOB_ONLYDIR); foreach ($subdirs as $subdir) { self::recursiveDelShareKeys($subdir, $userIds); } - return true; } /** -- cgit v1.2.3 From 4bf840e2cabd6402d2f8f3b67118d6661b0c5833 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Tue, 21 May 2013 00:00:55 +0200 Subject: cleanup unused code optimize tests --- apps/files_encryption/appinfo/app.php | 3 --- apps/files_encryption/lib/helper.php | 10 ---------- apps/files_encryption/tests/share.php | 19 +++++++++++++++++-- 3 files changed, 17 insertions(+), 15 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index e56d012fee9..7d01696e08a 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -18,9 +18,6 @@ OCA\Encryption\Helper::registerUserHooks(); // Sharing related hooks OCA\Encryption\Helper::registerShareHooks(); -// Webdav related hooks -OCA\Encryption\Helper::registerWebdavHooks(); - // Filesystem related hooks OCA\Encryption\Helper::registerFilesystemHooks(); diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php index c57f0bc0092..e4bf2c1226a 100755 --- a/apps/files_encryption/lib/helper.php +++ b/apps/files_encryption/lib/helper.php @@ -58,16 +58,6 @@ class Helper \OCP\Util::connectHook('OC_User', 'post_deleteUser', 'OCA\Encryption\Hooks', 'postDeleteUser'); } - /** - * @brief register webdav related hooks - * - */ - public static function registerWebdavHooks() - { - - - } - /** * @brief register filesystem related hooks * diff --git a/apps/files_encryption/tests/share.php b/apps/files_encryption/tests/share.php index f302aa0a3ef..0b806394eb3 100755 --- a/apps/files_encryption/tests/share.php +++ b/apps/files_encryption/tests/share.php @@ -557,8 +557,14 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase function testRecoveryFile() { - // login as admin - $this->loginHelper('admin'); + // disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $this->view->unlink('/owncloud_private_key'); + $this->view->unlink('/public-keys'); + + \OC_FileProxy::$enabled = $proxyStatus; \OCA\Encryption\Helper::adminEnableRecovery(null, 'test123'); $recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); @@ -566,6 +572,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase // check if control file created $this->assertTrue($this->view->file_exists('/control-file/controlfile.enc')); + // login as admin + $this->loginHelper('admin'); + $util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), 'admin'); // check if recovery password match @@ -620,6 +629,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase // check if share key for recovery not exists $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); + + \OCA\Encryption\Helper::adminDisableRecovery('test123'); + $this->assertEquals(0, \OC_Appconfig::getValue('files_encryption', 'recoveryAdminEnabled')); } function testRecoveryForUser() @@ -689,6 +701,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase // enable recovery for admin $this->assertTrue($util->setRecoveryForUser(0)); + + \OCA\Encryption\Helper::adminDisableRecovery('test123'); + $this->assertEquals(0, \OC_Appconfig::getValue('files_encryption', 'recoveryAdminEnabled')); } function testFailShareFile() -- cgit v1.2.3 From 64591cf7547258aa15136329d8ed582701b4107a Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Tue, 21 May 2013 10:30:24 +0200 Subject: move 3rdparty dependencies to app --- .../3rdparty/Crypt_Blowfish/Blowfish.php | 317 ++++++++++++++++++++ .../Crypt_Blowfish/Blowfish/DefaultKey.php | 327 +++++++++++++++++++++ apps/files_encryption/lib/crypt.php | 2 +- apps/files_encryption/tests/crypt.php | 2 +- apps/files_encryption/tests/share.php | 2 +- 5 files changed, 647 insertions(+), 3 deletions(-) create mode 100644 apps/files_encryption/3rdparty/Crypt_Blowfish/Blowfish.php create mode 100644 apps/files_encryption/3rdparty/Crypt_Blowfish/Blowfish/DefaultKey.php (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/3rdparty/Crypt_Blowfish/Blowfish.php b/apps/files_encryption/3rdparty/Crypt_Blowfish/Blowfish.php new file mode 100644 index 00000000000..4ccacb963e3 --- /dev/null +++ b/apps/files_encryption/3rdparty/Crypt_Blowfish/Blowfish.php @@ -0,0 +1,317 @@ + + * @copyright 2005 Matthew Fonda + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Blowfish.php,v 1.81 2005/05/30 18:40:36 mfonda Exp $ + * @link http://pear.php.net/package/Crypt_Blowfish + */ + + +require_once 'PEAR.php'; + + +/** + * + * Example usage: + * $bf = new Crypt_Blowfish('some secret key!'); + * $encrypted = $bf->encrypt('this is some example plain text'); + * $plaintext = $bf->decrypt($encrypted); + * echo "plain text: $plaintext"; + * + * + * @category Encryption + * @package Crypt_Blowfish + * @author Matthew Fonda + * @copyright 2005 Matthew Fonda + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @link http://pear.php.net/package/Crypt_Blowfish + * @version @package_version@ + * @access public + */ +class Crypt_Blowfish +{ + /** + * P-Array contains 18 32-bit subkeys + * + * @var array + * @access private + */ + var $_P = array(); + + + /** + * Array of four S-Blocks each containing 256 32-bit entries + * + * @var array + * @access private + */ + var $_S = array(); + + /** + * Mcrypt td resource + * + * @var resource + * @access private + */ + var $_td = null; + + /** + * Initialization vector + * + * @var string + * @access private + */ + var $_iv = null; + + + /** + * Crypt_Blowfish Constructor + * Initializes the Crypt_Blowfish object, and gives a sets + * the secret key + * + * @param string $key + * @access public + */ + function Crypt_Blowfish($key) + { + if (extension_loaded('mcrypt')) { + $this->_td = mcrypt_module_open(MCRYPT_BLOWFISH, '', 'ecb', ''); + $this->_iv = mcrypt_create_iv(8, MCRYPT_RAND); + } + $this->setKey($key); + } + + /** + * Deprecated isReady method + * + * @return bool + * @access public + * @deprecated + */ + function isReady() + { + return true; + } + + /** + * Deprecated init method - init is now a private + * method and has been replaced with _init + * + * @return bool + * @access public + * @deprecated + * @see Crypt_Blowfish::_init() + */ + function init() + { + $this->_init(); + } + + /** + * Initializes the Crypt_Blowfish object + * + * @access private + */ + function _init() + { + $defaults = new Crypt_Blowfish_DefaultKey(); + $this->_P = $defaults->P; + $this->_S = $defaults->S; + } + + /** + * Enciphers a single 64 bit block + * + * @param int &$Xl + * @param int &$Xr + * @access private + */ + function _encipher(&$Xl, &$Xr) + { + for ($i = 0; $i < 16; $i++) { + $temp = $Xl ^ $this->_P[$i]; + $Xl = ((($this->_S[0][($temp>>24) & 255] + + $this->_S[1][($temp>>16) & 255]) ^ + $this->_S[2][($temp>>8) & 255]) + + $this->_S[3][$temp & 255]) ^ $Xr; + $Xr = $temp; + } + $Xr = $Xl ^ $this->_P[16]; + $Xl = $temp ^ $this->_P[17]; + } + + + /** + * Deciphers a single 64 bit block + * + * @param int &$Xl + * @param int &$Xr + * @access private + */ + function _decipher(&$Xl, &$Xr) + { + for ($i = 17; $i > 1; $i--) { + $temp = $Xl ^ $this->_P[$i]; + $Xl = ((($this->_S[0][($temp>>24) & 255] + + $this->_S[1][($temp>>16) & 255]) ^ + $this->_S[2][($temp>>8) & 255]) + + $this->_S[3][$temp & 255]) ^ $Xr; + $Xr = $temp; + } + $Xr = $Xl ^ $this->_P[1]; + $Xl = $temp ^ $this->_P[0]; + } + + + /** + * Encrypts a string + * + * @param string $plainText + * @return string Returns cipher text on success, PEAR_Error on failure + * @access public + */ + function encrypt($plainText) + { + if (!is_string($plainText)) { + PEAR::raiseError('Plain text must be a string', 0, PEAR_ERROR_DIE); + } + + if (extension_loaded('mcrypt')) { + return mcrypt_generic($this->_td, $plainText); + } + + $cipherText = ''; + $len = strlen($plainText); + $plainText .= str_repeat(chr(0),(8 - ($len%8))%8); + for ($i = 0; $i < $len; $i += 8) { + list(,$Xl,$Xr) = unpack("N2",substr($plainText,$i,8)); + $this->_encipher($Xl, $Xr); + $cipherText .= pack("N2", $Xl, $Xr); + } + return $cipherText; + } + + + /** + * Decrypts an encrypted string + * + * @param string $cipherText + * @return string Returns plain text on success, PEAR_Error on failure + * @access public + */ + function decrypt($cipherText) + { + if (!is_string($cipherText)) { + PEAR::raiseError('Cipher text must be a string', 1, PEAR_ERROR_DIE); + } + + if (extension_loaded('mcrypt')) { + return mdecrypt_generic($this->_td, $cipherText); + } + + $plainText = ''; + $len = strlen($cipherText); + $cipherText .= str_repeat(chr(0),(8 - ($len%8))%8); + for ($i = 0; $i < $len; $i += 8) { + list(,$Xl,$Xr) = unpack("N2",substr($cipherText,$i,8)); + $this->_decipher($Xl, $Xr); + $plainText .= pack("N2", $Xl, $Xr); + } + return $plainText; + } + + + /** + * Sets the secret key + * The key must be non-zero, and less than or equal to + * 56 characters in length. + * + * @param string $key + * @return bool Returns true on success, PEAR_Error on failure + * @access public + */ + function setKey($key) + { + if (!is_string($key)) { + PEAR::raiseError('Key must be a string', 2, PEAR_ERROR_DIE); + } + + $len = strlen($key); + + if ($len > 56 || $len == 0) { + PEAR::raiseError('Key must be less than 56 characters and non-zero. Supplied key length: ' . $len, 3, PEAR_ERROR_DIE); + } + + if (extension_loaded('mcrypt')) { + mcrypt_generic_init($this->_td, $key, $this->_iv); + return true; + } + + require_once 'Blowfish/DefaultKey.php'; + $this->_init(); + + $k = 0; + $data = 0; + $datal = 0; + $datar = 0; + + for ($i = 0; $i < 18; $i++) { + $data = 0; + for ($j = 4; $j > 0; $j--) { + $data = $data << 8 | ord($key{$k}); + $k = ($k+1) % $len; + } + $this->_P[$i] ^= $data; + } + + for ($i = 0; $i <= 16; $i += 2) { + $this->_encipher($datal, $datar); + $this->_P[$i] = $datal; + $this->_P[$i+1] = $datar; + } + for ($i = 0; $i < 256; $i += 2) { + $this->_encipher($datal, $datar); + $this->_S[0][$i] = $datal; + $this->_S[0][$i+1] = $datar; + } + for ($i = 0; $i < 256; $i += 2) { + $this->_encipher($datal, $datar); + $this->_S[1][$i] = $datal; + $this->_S[1][$i+1] = $datar; + } + for ($i = 0; $i < 256; $i += 2) { + $this->_encipher($datal, $datar); + $this->_S[2][$i] = $datal; + $this->_S[2][$i+1] = $datar; + } + for ($i = 0; $i < 256; $i += 2) { + $this->_encipher($datal, $datar); + $this->_S[3][$i] = $datal; + $this->_S[3][$i+1] = $datar; + } + + return true; + } + +} + +?> diff --git a/apps/files_encryption/3rdparty/Crypt_Blowfish/Blowfish/DefaultKey.php b/apps/files_encryption/3rdparty/Crypt_Blowfish/Blowfish/DefaultKey.php new file mode 100644 index 00000000000..2ff8ac788a6 --- /dev/null +++ b/apps/files_encryption/3rdparty/Crypt_Blowfish/Blowfish/DefaultKey.php @@ -0,0 +1,327 @@ + + * @copyright 2005 Matthew Fonda + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: DefaultKey.php,v 1.81 2005/05/30 18:40:37 mfonda Exp $ + * @link http://pear.php.net/package/Crypt_Blowfish + */ + + +/** + * Class containing default key + * + * @category Encryption + * @package Crypt_Blowfish + * @author Matthew Fonda + * @copyright 2005 Matthew Fonda + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @link http://pear.php.net/package/Crypt_Blowfish + * @version @package_version@ + * @access public + */ +class Crypt_Blowfish_DefaultKey +{ + var $P = array(); + + var $S = array(); + + function Crypt_Blowfish_DefaultKey() + { + $this->P = array( + 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, + 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, + 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, + 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, + 0x9216D5D9, 0x8979FB1B + ); + + $this->S = array( + array( + 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, + 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, + 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, + 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, + 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, + 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, + 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, + 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, + 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, + 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, + 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, + 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, + 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, + 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, + 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, + 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, + 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, + 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, + 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, + 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, + 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, + 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, + 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, + 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, + 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, + 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, + 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, + 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, + 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, + 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, + 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, + 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09, + 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, + 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, + 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, + 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, + 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, + 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, + 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, + 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, + 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, + 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, + 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, + 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, + 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, + 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, + 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, + 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, + 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, + 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, + 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, + 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, + 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, + 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, + 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, + 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, + 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, + 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, + 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, + 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, + 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, + 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, + 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, + 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A + ), + array( + 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, + 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, + 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, + 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, + 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, + 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, + 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, + 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, + 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, + 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, + 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, + 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, + 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, + 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, + 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, + 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331, + 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, + 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, + 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, + 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, + 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, + 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, + 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, + 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, + 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, + 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, + 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, + 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, + 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, + 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, + 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, + 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, + 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, + 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, + 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, + 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, + 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, + 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, + 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, + 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, + 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, + 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, + 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, + 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, + 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, + 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, + 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, + 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, + 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, + 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, + 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, + 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250, + 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, + 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, + 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, + 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, + 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, + 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, + 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, + 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, + 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, + 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, + 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, + 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7 + ), + array( + 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, + 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, + 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, + 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, + 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, + 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, + 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, + 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, + 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, + 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, + 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, + 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, + 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, + 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, + 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, + 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, + 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, + 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, + 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, + 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, + 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, + 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, + 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, + 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, + 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, + 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, + 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, + 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, + 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, + 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, + 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, + 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, + 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, + 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, + 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, + 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, + 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, + 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, + 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, + 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, + 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, + 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, + 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, + 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, + 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, + 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, + 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, + 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C, + 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, + 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, + 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, + 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, + 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, + 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, + 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, + 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, + 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, + 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, + 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, + 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, + 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, + 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, + 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, + 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0 + ), + array( + 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, + 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, + 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, + 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, + 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, + 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, + 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, + 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, + 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, + 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, + 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, + 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, + 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, + 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, + 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, + 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, + 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, + 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, + 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, + 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, + 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, + 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, + 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, + 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, + 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, + 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, + 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, + 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, + 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, + 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, + 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, + 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47, + 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, + 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, + 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, + 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, + 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, + 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, + 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, + 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, + 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, + 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, + 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, + 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, + 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, + 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, + 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, + 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, + 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, + 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, + 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, + 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, + 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, + 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, + 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, + 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, + 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, + 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, + 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, + 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, + 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, + 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, + 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, + 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 + ) + ); + } + +} + +?> diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 783c19d2542..8ff9fc5ff5b 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -25,7 +25,7 @@ namespace OCA\Encryption; -require_once 'Crypt_Blowfish/Blowfish.php'; +require_once '../3rdparty/Crypt_Blowfish/Blowfish.php'; /** * Class for common cryptography functionality diff --git a/apps/files_encryption/tests/crypt.php b/apps/files_encryption/tests/crypt.php index 049f3fb5d98..eaedc485413 100755 --- a/apps/files_encryption/tests/crypt.php +++ b/apps/files_encryption/tests/crypt.php @@ -7,7 +7,7 @@ * See the COPYING-README file. */ -require_once realpath(dirname(__FILE__) . '/../../../3rdparty/Crypt_Blowfish/Blowfish.php'); +require_once realpath(dirname(__FILE__) . '/../3rdparty/Crypt_Blowfish/Blowfish.php'); require_once realpath(dirname(__FILE__) . '/../../../lib/base.php'); require_once realpath(dirname(__FILE__) . '/../lib/crypt.php'); require_once realpath(dirname(__FILE__) . '/../lib/keymanager.php'); diff --git a/apps/files_encryption/tests/share.php b/apps/files_encryption/tests/share.php index 849f16c696d..e205ff2b62e 100755 --- a/apps/files_encryption/tests/share.php +++ b/apps/files_encryption/tests/share.php @@ -20,7 +20,7 @@ * */ -require_once realpath(dirname(__FILE__) . '/../../../3rdparty/Crypt_Blowfish/Blowfish.php'); +require_once realpath(dirname(__FILE__) . '/../3rdparty/Crypt_Blowfish/Blowfish.php'); require_once realpath(dirname(__FILE__) . '/../../../lib/base.php'); require_once realpath(dirname(__FILE__) . '/../lib/crypt.php'); require_once realpath(dirname(__FILE__) . '/../lib/keymanager.php'); -- cgit v1.2.3 From 4c27c7e1994e863926edaad6e682b3f889075e2f Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Tue, 21 May 2013 12:22:03 +0200 Subject: fix path, needs to be relative to data/ --- apps/files_encryption/lib/proxy.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 55ad882a8f9..ea6b3bf345c 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -484,7 +484,7 @@ class Proxy extends \OC_FileProxy $fileInfo['unencrypted_size'] = $size; // put file info - $view->putFileInfo($path_f, $fileInfo); + $view->putFileInfo($path, $fileInfo); } } } -- cgit v1.2.3 From 9d324db05481620fd9a6883c1315e0b31fc21c45 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Tue, 21 May 2013 12:33:32 +0200 Subject: fix path to 3rdparty apps --- apps/files_encryption/lib/crypt.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 8ff9fc5ff5b..1a5c9300a27 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -25,7 +25,8 @@ namespace OCA\Encryption; -require_once '../3rdparty/Crypt_Blowfish/Blowfish.php'; +//require_once '../3rdparty/Crypt_Blowfish/Blowfish.php'; +require_once realpath(dirname(__FILE__) . '/../3rdparty/Crypt_Blowfish/Blowfish.php'); /** * Class for common cryptography functionality -- cgit v1.2.3 From 1deeec93b74c5adde44bcac30538caf75442a1da Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Tue, 21 May 2013 21:09:25 +0200 Subject: fixed postFileSize --- apps/files_encryption/lib/proxy.php | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index ea6b3bf345c..7419a85e9ba 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -465,28 +465,36 @@ class Proxy extends \OC_FileProxy return $size; } - // get file info from database/cache - $fileInfo = \OC\Files\Filesystem::getFileInfo($path_f); + $fileInfo = false; + // get file info from database/cache if not .part file + if(!Keymanager::isPartialFilePath($path)) { + $fileInfo = $view->getFileInfo($path); + } // if file is encrypted return real file size if (is_array($fileInfo) && $fileInfo['encrypted'] === true) { $size = $fileInfo['unencrypted_size']; } else { // self healing if file was removed from file cache - if (is_array($fileInfo)) { - $userId = \OCP\User::getUser(); - $util = new Util($view, $userId); - $fixSize = $util->getFileSize($path); - if ($fixSize > 0) { - $size = $fixSize; + if (!is_array($fileInfo)) { + $fileInfo = array(); + } - $fileInfo['encrypted'] = true; - $fileInfo['unencrypted_size'] = $size; + $userId = \OCP\User::getUser(); + $util = new Util($view, $userId); + $fixSize = $util->getFileSize($path); + if ($fixSize > 0) { + $size = $fixSize; - // put file info + $fileInfo['encrypted'] = true; + $fileInfo['unencrypted_size'] = $size; + + // put file info if not .part file + if(!Keymanager::isPartialFilePath($path_f)) { $view->putFileInfo($path, $fileInfo); } } + } return $size; } -- cgit v1.2.3 From 9ca9a22c6a6495e657290195c97282aee8976282 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Wed, 22 May 2013 00:53:07 +0200 Subject: fixed finding encrypted files in subfolders and removed unused code --- apps/files_encryption/lib/keymanager.php | 58 +--------------- apps/files_encryption/lib/proxy.php | 50 +++++++------- apps/files_encryption/lib/stream.php | 113 +++++++++---------------------- apps/files_encryption/lib/util.php | 40 ++--------- 4 files changed, 61 insertions(+), 200 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 542b1cf2876..ddd8f0ad6e2 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -326,44 +326,6 @@ class Keymanager } - /** - * @brief store private keys from the user - * - * @param string $privatekey - * @param string $publickey - * @return bool true/false - */ - public static function setUserKeys($privatekey, $publickey) - { - - return (self::setPrivateKey($privatekey) && self::setPublicKey($publickey)); - - } - - /** - * @brief store public key of the user - * - * @param string $key - * @return bool true/false - */ - public static function setPublicKey($key) - { - - $view = new \OC_FilesystemView('/public-keys'); - - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - - if (!$view->file_exists('')) $view->mkdir(''); - - $result = $view->file_put_contents(\OCP\User::getUser() . '.public.key', $key); - - \OC_FileProxy::$enabled = $proxyStatus; - - return $result; - - } - /** * @brief store share key * @@ -538,7 +500,7 @@ class Keymanager list($owner, $filename) = $util->getUidAndFilename($filePath); - $shareKeyPath = '/' . $owner . '/files_encryption/share-keys/' . $filename; + $shareKeyPath = \OC\Files\Filesystem::normalizePath('/' . $owner . '/files_encryption/share-keys/' . $filename); if ($view->is_dir($shareKeyPath)) { @@ -611,22 +573,4 @@ class Keymanager return $targetPath; } - - /** - * @brief Fetch the legacy encryption key from user files - * @internal param string $login used to locate the legacy key - * @internal param string $passphrase used to decrypt the legacy key - * @return boolean - * - * if the key is left out, the default handeler will be used - */ - public function getLegacyKey() - { - - $user = \OCP\User::getUser(); - $view = new \OC_FilesystemView('/' . $user); - return $view->file_get_contents('encryption.key'); - - } - } \ No newline at end of file diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 7419a85e9ba..f29e893f12a 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -170,7 +170,7 @@ class Proxy extends \OC_FileProxy $data = $encData; // Update the file cache with file info - \OC\Files\Filesystem::putFileInfo($filePath, array('encrypted' => true, 'size' => strlen($size), 'unencrypted_size' => $size), ''); + \OC\Files\Filesystem::putFileInfo($filePath, array('encrypted' => true, 'size' => strlen($data), 'unencrypted_size' => $size), ''); // Re-enable proxy - our work is done \OC_FileProxy::$enabled = $proxyStatus; @@ -189,28 +189,25 @@ class Proxy extends \OC_FileProxy public function postFile_get_contents($path, $data) { - // FIXME: $path for shared files is just /uid/files/Shared/filepath - $userId = \OCP\USER::getUser(); $view = new \OC_FilesystemView('/'); $util = new Util($view, $userId); $relPath = $util->stripUserFilesPath($path); - - // TODO check for existing key file and reuse it if possible to avoid problems with versioning etc. // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; + // init session + $session = new Session($view); + // If data is a catfile if ( Crypt::mode() == 'server' - && Crypt::isCatfileContent($data) // TODO: Do we really need this check? Can't we assume it is properly encrypted? + && Crypt::isCatfileContent($data) ) { - // TODO: use get owner to find correct location of key files for shared files - $session = new Session($view); $privateKey = $session->getPrivateKey($userId); // Get the encrypted keyfile @@ -229,9 +226,7 @@ class Proxy extends \OC_FileProxy && isset($_SESSION['legacyenckey']) && Crypt::isEncryptedMeta($path) ) { - $plainData = Crypt::legacyDecrypt($data, $session->getLegacyKey()); - } \OC_FileProxy::$enabled = $proxyStatus; @@ -292,19 +287,6 @@ class Proxy extends \OC_FileProxy } - /** - * @brief When a file is renamed, rename its keyfile also - * @param $path - * @return bool Result of rename() - * @note This is pre rather than post because using post didn't work - */ - public function postWrite($path) - { - $this->handleFile($path); - - return true; - } - /** * @param $path * @return bool @@ -362,7 +344,6 @@ class Proxy extends \OC_FileProxy // protocol and let it do the decryption work instead $result = fopen('crypt://' . $path_f, $meta['mode']); - } elseif ( self::shouldEncrypt($path) and $meta ['mode'] != 'r' @@ -428,11 +409,28 @@ class Proxy extends \OC_FileProxy */ public function postStat($path, $data) { + $content = ''; + $view = new \OC_FilesystemView('/'); + if($view->file_exists($path)) { + // disable encryption proxy + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + // we only need 24 byte from the last chunk + $handle = $view->fopen($path, 'r'); + if (!fseek($handle, -24, SEEK_END)) { + $content = fgets($handle); + } + + // re-enable proxy + \OC_FileProxy::$enabled = $proxyStatus; + } + // check if file is encrypted - if (Crypt::isCatfileContent($path)) { + if (Crypt::isCatfileContent($content)) { // get file info from cache - $cached = \OC\Files\Filesystem::getFileInfo($path, ''); + $cached = $view->getFileInfo($path); // set the real file size $data['size'] = $cached['unencrypted_size']; diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 31546a2cc50..b143b62827f 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -50,8 +50,6 @@ namespace OCA\Encryption; */ class Stream { - - public static $sourceStreams = array(); private $plainKey; private $encKeyfiles; @@ -96,57 +94,41 @@ class Stream // rawPath is relative to the data directory $this->rawPath = $util->getUserFilesDir() . $this->relPath; + // Disable fileproxies so we can get the file size and open the source file without recursive encryption + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + if ( - dirname($this->rawPath) == 'streams' - and isset(self::$sourceStreams[basename($this->rawPath)]) + $mode == 'w' + or $mode == 'w+' + or $mode == 'wb' + or $mode == 'wb+' ) { - // Is this just for unit testing purposes? - - $this->handle = self::$sourceStreams[basename($this->rawPath)]['stream']; - - $this->path = self::$sourceStreams[basename($this->rawPath)]['path']; - - $this->size = self::$sourceStreams[basename($this->rawPath)]['size']; + // We're writing a new file so start write counter with 0 bytes + $this->size = 0; + $this->unencryptedSize = 0; } else { - // Disable fileproxies so we can get the file size and open the source file without recursive encryption - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - - if ( - $mode == 'w' - or $mode == 'w+' - 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 { + $this->size = $this->rootView->filesize($this->rawPath, $mode); + } - $this->size = $this->rootView->filesize($this->rawPath, $mode); + $this->handle = $this->rootView->fopen($this->rawPath, $mode); - } + \OC_FileProxy::$enabled = $proxyStatus; - $this->handle = $this->rootView->fopen($this->rawPath, $mode); + if (!is_resource($this->handle)) { - \OC_FileProxy::$enabled = $proxyStatus; + \OCP\Util::writeLog('files_encryption', 'failed to open file "' . $this->rawPath . '"', \OCP\Util::ERROR); - if (!is_resource($this->handle)) { + } else { - \OCP\Util::writeLog('files_encryption', 'failed to open file "' . $this->rawPath . '"', \OCP\Util::ERROR); + $this->meta = stream_get_meta_data($this->handle); - } else { + } - $this->meta = stream_get_meta_data($this->handle); - } - - } return is_resource($this->handle); @@ -165,14 +147,6 @@ class Stream } - /** - * @return int - */ - public function stream_tell() - { - return ftell($this->handle); - } - /** * @param $count * @return bool|string @@ -259,7 +233,6 @@ class Stream // If a keyfile already exists if ($this->encKeyfile) { - $this->setUserProperty(); $session = new Session($this->rootView); @@ -279,23 +252,6 @@ class Stream } - public function setUserProperty() - { - - // Only get the user again if it isn't already set - if (empty($this->userId)) { - - // TODO: Move this user call out of here - it belongs - // elsewhere - $this->userId = \OCP\User::getUser(); - - } - - // TODO: Add a method for getting the user in case OCP\User:: - // getUser() doesn't work (can that scenario ever occur?) - - } - /** * @brief Handle plain data from the stream, and write it in 8192 byte blocks * @param string $data data to be written to disk @@ -318,16 +274,10 @@ class Stream // Get the length of the unencrypted data that we are handling $length = strlen($data); - // So far this round, no data has been written - $written = 0; - - // Find out where we are up to in the writing of data to the + // Find out where we are up to in the writing of data to the // file $pointer = ftell($this->handle); - // Make sure the userId is set - $this->setUserProperty(); - // Get / generate the keyfile for the file we're handling // If we're writing a new file (not overwriting an existing // one), save the newly generated keyfile @@ -337,7 +287,6 @@ class Stream } - // If extra data is left over from the last round, make sure it // is integrated into the next 6126 / 8192 block if ($this->writeCache) { @@ -351,17 +300,16 @@ class Stream } - // While there still remains somed data to be processed & written while (strlen($data) > 0) { // Remaining length for this iteration, not of the // entire file (may be greater than 8192 bytes) - $remainingLength = strlen( $data ); + $remainingLength = strlen($data); // If data remaining to be written is less than the // size of 1 6126 byte block - if (strlen($data) < 6126) { + if ($remainingLength < 6126) { // Set writeCache to contents of $data // The writeCache will be carried over to the @@ -388,9 +336,7 @@ class Stream // being handled totals more than 6126 bytes fwrite($this->handle, $encrypted); - $writtenLen = strlen($encrypted); - - // Remove the chunk we just processed from + // Remove the chunk we just processed from // $data, leaving only unprocessed data in $data // var, for handling on the next round $data = substr($data, 6126); @@ -416,16 +362,19 @@ class Stream */ public function stream_set_option($option, $arg1, $arg2) { + $return = false; switch ($option) { case STREAM_OPTION_BLOCKING: - stream_set_blocking($this->handle, $arg1); + $return = stream_set_blocking($this->handle, $arg1); break; case STREAM_OPTION_READ_TIMEOUT: - stream_set_timeout($this->handle, $arg1, $arg2); + $return = stream_set_timeout($this->handle, $arg1, $arg2); break; case STREAM_OPTION_WRITE_BUFFER: - stream_set_write_buffer($this->handle, $arg1, $arg2); + $return = stream_set_write_buffer($this->handle, $arg1); } + + return $return; } /** @@ -441,7 +390,7 @@ class Stream */ public function stream_lock($mode) { - flock($this->handle, $mode); + return flock($this->handle, $mode); } /** diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 8147982d483..1f4609ae2f6 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -367,14 +367,16 @@ class Util * @note $directory needs to be a path relative to OC data dir. e.g. * /admin/files NOT /backup OR /home/www/oc/data/admin/files */ - public function findEncFiles($directory) + public function findEncFiles($directory, &$found = false) { // Disable proxy - we don't want files to be decrypted before // we handle them \OC_FileProxy::$enabled = false; - $found = array('plain' => array(), 'encrypted' => array(), 'legacy' => array()); + if($found == false) { + $found = array('plain' => array(), 'encrypted' => array(), 'legacy' => array()); + } if ( $this->view->is_dir($directory) @@ -395,7 +397,7 @@ class Util // its contents if ($this->view->is_dir($filePath)) { - $this->findEncFiles($filePath); + $this->findEncFiles($filePath, $found); // If the path is a file, determine // its encryption status @@ -636,38 +638,6 @@ class Util } - /** - * @brief Format a path to be relative to the /user directory - * @note e.g. turns '/admin/files/test.txt' into 'files/test.txt' - */ - public function stripFilesPath($path) - { - - $trimmed = ltrim($path, '/'); - $split = explode('/', $trimmed); - $sliced = array_slice($split, 1); - $relPath = implode('/', $sliced); - - return $relPath; - - } - - /** - * @brief Format a shared path to be relative to the /user/files/ directory - * @note Expects a path like /uid/files/Shared/filepath - */ - public function stripSharedFilePath($path) - { - - $trimmed = ltrim($path, '/'); - $split = explode('/', $trimmed); - $sliced = array_slice($split, 3); - $relPath = implode('/', $sliced); - - return $relPath; - - } - /** * @param $path * @return bool -- cgit v1.2.3 From afbfa742d7848089523262f5c234035db1b20d3b Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Wed, 22 May 2013 00:55:16 +0200 Subject: improved tests --- apps/files_encryption/lib/proxy.php | 55 ---- apps/files_encryption/tests/crypt.php | 89 +------ apps/files_encryption/tests/keymanager.php | 77 ++++-- apps/files_encryption/tests/share.php | 5 +- apps/files_encryption/tests/stream.php | 406 +++++++++++++---------------- apps/files_encryption/tests/util.php | 57 ++++ 6 files changed, 301 insertions(+), 388 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index f29e893f12a..cc9d239b256 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -359,24 +359,6 @@ class Proxy extends \OC_FileProxy } - /** - * @param $path - * @param $mime - * @return string - */ - public function postGetMimeType($path, $mime) - { - - if (Crypt::isCatfileContent($path)) { - - $mime = \OCP\Files::getMimeType('crypt://' . $path, 'w'); - - } - - return $mime; - - } - /** * @param $path * @param $data @@ -402,43 +384,6 @@ class Proxy extends \OC_FileProxy return $data; } - /** - * @param $path - * @param $data - * @return mixed - */ - public function postStat($path, $data) - { - $content = ''; - $view = new \OC_FilesystemView('/'); - if($view->file_exists($path)) { - // disable encryption proxy - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - - // we only need 24 byte from the last chunk - $handle = $view->fopen($path, 'r'); - if (!fseek($handle, -24, SEEK_END)) { - $content = fgets($handle); - } - - // re-enable proxy - \OC_FileProxy::$enabled = $proxyStatus; - } - - // check if file is encrypted - if (Crypt::isCatfileContent($content)) { - - // get file info from cache - $cached = $view->getFileInfo($path); - - // set the real file size - $data['size'] = $cached['unencrypted_size']; - } - - return $data; - } - /** * @param $path * @param $size diff --git a/apps/files_encryption/tests/crypt.php b/apps/files_encryption/tests/crypt.php index eaedc485413..621941c52a1 100755 --- a/apps/files_encryption/tests/crypt.php +++ b/apps/files_encryption/tests/crypt.php @@ -432,29 +432,6 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase $this->view->unlink($this->userId . '/files/' . $filename); } - // Is this test still necessary? -// function testSymmetricBlockStreamDecryptFileContent() { -// -// \OC_User::setUserId( 'admin' ); -// -// // Disable encryption proxy to prevent unwanted en/decryption -// \OC_FileProxy::$enabled = false; -// -// $cryptedFile = file_put_contents( 'crypt://' . '/blockEncrypt', $this->dataUrl ); -// -// // Disable encryption proxy to prevent unwanted en/decryption -// \OC_FileProxy::$enabled = false; -// -// echo "\n\n\$cryptedFile = " . $this->view->file_get_contents( '/blockEncrypt' ); -// -// $retreivedCryptedFile = file_get_contents( 'crypt://' . '/blockEncrypt' ); -// -// $this->assertEquals( $this->dataUrl, $retreivedCryptedFile ); -// -// \OC_FileProxy::$enabled = false; -// -// } - function testSymmetricEncryptFileContentKeyfile() { @@ -585,6 +562,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase $this->assertEquals($this->dataLong, $decrypted); + $this->assertFalse(Encryption\Crypt::getBlowfish('')); } /** @@ -852,69 +830,4 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase // tear down $view->unlink($filename); } - -// function testEncryption(){ -// -// $key=uniqid(); -// $file=OC::$SERVERROOT.'/3rdparty/MDB2.php'; -// $source=file_get_contents($file); //nice large text file -// $encrypted=OC_Encryption\Crypt::encrypt($source,$key); -// $decrypted=OC_Encryption\Crypt::decrypt($encrypted,$key); -// $decrypted=rtrim($decrypted, "\0"); -// $this->assertNotEquals($encrypted,$source); -// $this->assertEquals($decrypted,$source); -// -// $chunk=substr($source,0,8192); -// $encrypted=OC_Encryption\Crypt::encrypt($chunk,$key); -// $this->assertEquals(strlen($chunk),strlen($encrypted)); -// $decrypted=OC_Encryption\Crypt::decrypt($encrypted,$key); -// $decrypted=rtrim($decrypted, "\0"); -// $this->assertEquals($decrypted,$chunk); -// -// $encrypted=OC_Encryption\Crypt::blockEncrypt($source,$key); -// $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key); -// $this->assertNotEquals($encrypted,$source); -// $this->assertEquals($decrypted,$source); -// -// $tmpFileEncrypted=OCP\Files::tmpFile(); -// OC_Encryption\Crypt::encryptfile($file,$tmpFileEncrypted,$key); -// $encrypted=file_get_contents($tmpFileEncrypted); -// $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key); -// $this->assertNotEquals($encrypted,$source); -// $this->assertEquals($decrypted,$source); -// -// $tmpFileDecrypted=OCP\Files::tmpFile(); -// OC_Encryption\Crypt::decryptfile($tmpFileEncrypted,$tmpFileDecrypted,$key); -// $decrypted=file_get_contents($tmpFileDecrypted); -// $this->assertEquals($decrypted,$source); -// -// $file=OC::$SERVERROOT.'/core/img/weather-clear.png'; -// $source=file_get_contents($file); //binary file -// $encrypted=OC_Encryption\Crypt::encrypt($source,$key); -// $decrypted=OC_Encryption\Crypt::decrypt($encrypted,$key); -// $decrypted=rtrim($decrypted, "\0"); -// $this->assertEquals($decrypted,$source); -// -// $encrypted=OC_Encryption\Crypt::blockEncrypt($source,$key); -// $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key); -// $this->assertEquals($decrypted,$source); -// -// } -// -// function testBinary(){ -// $key=uniqid(); -// -// $file=__DIR__.'/binary'; -// $source=file_get_contents($file); //binary file -// $encrypted=OC_Encryption\Crypt::encrypt($source,$key); -// $decrypted=OC_Encryption\Crypt::decrypt($encrypted,$key); -// -// $decrypted=rtrim($decrypted, "\0"); -// $this->assertEquals($decrypted,$source); -// -// $encrypted=OC_Encryption\Crypt::blockEncrypt($source,$key); -// $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key,strlen($source)); -// $this->assertEquals($decrypted,$source); -// } - } diff --git a/apps/files_encryption/tests/keymanager.php b/apps/files_encryption/tests/keymanager.php index 334cc743f2c..b1bae673e82 100644 --- a/apps/files_encryption/tests/keymanager.php +++ b/apps/files_encryption/tests/keymanager.php @@ -31,6 +31,7 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase */ public $view; public $randomKey; + public $dataShort; function setUp() { @@ -150,34 +151,18 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase //$view = new \OC_FilesystemView( '/' . $this->userId . '/files_encryption/keyfiles' ); Encryption\Keymanager::setFileKey($this->view, $file, $this->userId, $key['key']); - // Disable encryption proxy to prevent recursive calls + // enable encryption proxy $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = true; // cleanup $this->view->unlink('/' . $this->userId . '/files/' . $file); - // Re-enable proxy - our work is done + // change encryption proxy to previous state \OC_FileProxy::$enabled = $proxyStatus; } -// /** -// * @depends testGetPrivateKey -// */ -// function testGetPrivateKey_decrypt() { -// -// $key = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId ); -// -// # TODO: replace call to Crypt with a mock object? -// $decrypted = Encryption\Crypt::symmetricDecryptFileContent( $key, $this->passphrase ); -// -// $this->assertEquals( 1704, strlen( $decrypted ) ); -// -// $this->assertEquals( '-----BEGIN PRIVATE KEY-----', substr( $decrypted, 0, 27 ) ); -// -// } - function testGetUserKeys() { @@ -201,4 +186,60 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase $this->assertArrayHasKey('key', $sslInfoPrivate); } + + function testFixPartialFilePath() + { + + $partFilename = 'testfile.txt.part'; + $filename = 'testfile.txt'; + + $this->assertTrue(Encryption\Keymanager::isPartialFilePath($partFilename)); + + $this->assertEquals('testfile.txt', Encryption\Keymanager::fixPartialFilePath($partFilename)); + + $this->assertFalse(Encryption\Keymanager::isPartialFilePath($filename)); + + $this->assertEquals('testfile.txt', Encryption\Keymanager::fixPartialFilePath($filename)); + } + + function testRecursiveDelShareKeys() + { + + // generate filename + $filename = '/tmp-' . time() . '.txt'; + + // create folder structure + $this->view->mkdir('/admin/files/folder1'); + $this->view->mkdir('/admin/files/folder1/subfolder'); + $this->view->mkdir('/admin/files/folder1/subfolder/subsubfolder'); + + // enable encryption proxy + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = true; + + // save file with content + $cryptedFile = file_put_contents('crypt:///folder1/subfolder/subsubfolder/' . $filename, $this->dataShort); + + // test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); + + // change encryption proxy to previous state + \OC_FileProxy::$enabled = $proxyStatus; + + // recursive delete keys + Encryption\Keymanager::delShareKey($this->view, array('admin'), '/folder1/'); + + // check if share key not exists + $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/folder1/subfolder/subsubfolder/' . $filename . '.admin.shareKey')); + + // enable encryption proxy + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = true; + + // cleanup + $this->view->unlink('/admin/files/folder1'); + + // change encryption proxy to previous state + \OC_FileProxy::$enabled = $proxyStatus; + } } diff --git a/apps/files_encryption/tests/share.php b/apps/files_encryption/tests/share.php index e205ff2b62e..1d0cbfbc1de 100755 --- a/apps/files_encryption/tests/share.php +++ b/apps/files_encryption/tests/share.php @@ -312,7 +312,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey')); // cleanup - $this->view->unlink('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename); + $this->view->unlink('/admin/files' . $this->folder1); // check if share key not exists $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey')); @@ -621,7 +621,8 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey')); - \OCA\Encryption\Helper::adminDisableRecovery('test123'); + $this->assertTrue(\OCA\Encryption\Helper::adminEnableRecovery(null, 'test123')); + $this->assertTrue(\OCA\Encryption\Helper::adminDisableRecovery('test123')); $this->assertEquals(0, \OC_Appconfig::getValue('files_encryption', 'recoveryAdminEnabled')); } diff --git a/apps/files_encryption/tests/stream.php b/apps/files_encryption/tests/stream.php index 633cc9e4fce..3765d986e12 100644 --- a/apps/files_encryption/tests/stream.php +++ b/apps/files_encryption/tests/stream.php @@ -1,226 +1,182 @@ -// * This file is licensed under the Affero General Public License version 3 or -// * later. -// * See the COPYING-README file. -// */ -// -// namespace OCA\Encryption; -// -// class Test_Stream extends \PHPUnit_Framework_TestCase { -// -// function setUp() { -// -// \OC_Filesystem::mount( 'OC_Filestorage_Local', array(), '/' ); -// -// $this->empty = ''; -// -// $this->stream = new Stream(); -// -// $this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) ); -// $this->dataShort = 'hats'; -// -// $this->emptyTmpFilePath = \OCP\Files::tmpFile(); -// -// $this->dataTmpFilePath = \OCP\Files::tmpFile(); -// -// file_put_contents( $this->dataTmpFilePath, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est." ); -// -// } -// -// function testStreamOpen() { -// -// $stream1 = new Stream(); -// -// $handle1 = $stream1->stream_open( $this->emptyTmpFilePath, 'wb', array(), $this->empty ); -// -// // Test that resource was returned successfully -// $this->assertTrue( $handle1 ); -// -// // Test that file has correct size -// $this->assertEquals( 0, $stream1->size ); -// -// // Test that path is correct -// $this->assertEquals( $this->emptyTmpFilePath, $stream1->rawPath ); -// -// $stream2 = new Stream(); -// -// $handle2 = $stream2->stream_open( 'crypt://' . $this->emptyTmpFilePath, 'wb', array(), $this->empty ); -// -// // Test that protocol identifier is removed from path -// $this->assertEquals( $this->emptyTmpFilePath, $stream2->rawPath ); -// -// // "Stat failed error" prevents this test from executing -// // $stream3 = new Stream(); -// // -// // $handle3 = $stream3->stream_open( $this->dataTmpFilePath, 'r', array(), $this->empty ); -// // -// // $this->assertEquals( 0, $stream3->size ); -// -// } -// -// function testStreamWrite() { -// -// $stream1 = new Stream(); -// -// $handle1 = $stream1->stream_open( $this->emptyTmpFilePath, 'r+b', array(), $this->empty ); -// -// # what about the keymanager? there is no key for the newly created temporary file! -// -// $stream1->stream_write( $this->dataShort ); -// -// } -// -// // function getStream( $id, $mode, $size ) { -// // -// // if ( $id === '' ) { -// // -// // $id = uniqid(); -// // } -// // -// // -// // if ( !isset( $this->tmpFiles[$id] ) ) { -// // -// // // If tempfile with given name does not already exist, create it -// // -// // $file = OCP\Files::tmpFile(); -// // -// // $this->tmpFiles[$id] = $file; -// // -// // } else { -// // -// // $file = $this->tmpFiles[$id]; -// // -// // } -// // -// // $stream = fopen( $file, $mode ); -// // -// // Stream::$sourceStreams[$id] = array( 'path' => 'dummy' . $id, 'stream' => $stream, 'size' => $size ); -// // -// // return fopen( 'crypt://streams/'.$id, $mode ); -// // -// // } -// // -// // function testStream( ){ -// // -// // $stream = $this->getStream( 'test1', 'w', strlen( 'foobar' ) ); -// // -// // fwrite( $stream, 'foobar' ); -// // -// // fclose( $stream ); -// // -// // -// // $stream = $this->getStream( 'test1', 'r', strlen( 'foobar' ) ); -// // -// // $data = fread( $stream, 6 ); -// // -// // fclose( $stream ); -// // -// // $this->assertEquals( 'foobar', $data ); -// // -// // -// // $file = OC::$SERVERROOT.'/3rdparty/MDB2.php'; -// // -// // $source = fopen( $file, 'r' ); -// // -// // $target = $this->getStream( 'test2', 'w', 0 ); -// // -// // OCP\Files::streamCopy( $source, $target ); -// // -// // fclose( $target ); -// // -// // fclose( $source ); -// // -// // -// // $stream = $this->getStream( 'test2', 'r', filesize( $file ) ); -// // -// // $data = stream_get_contents( $stream ); -// // -// // $original = file_get_contents( $file ); -// // -// // $this->assertEquals( strlen( $original ), strlen( $data ) ); -// // -// // $this->assertEquals( $original, $data ); -// // -// // } -// -// } -// -// // class Test_CryptStream extends PHPUnit_Framework_TestCase { -// // private $tmpFiles=array(); -// // -// // function testStream(){ -// // $stream=$this->getStream('test1','w',strlen('foobar')); -// // fwrite($stream,'foobar'); -// // fclose($stream); -// // -// // $stream=$this->getStream('test1','r',strlen('foobar')); -// // $data=fread($stream,6); -// // fclose($stream); -// // $this->assertEquals('foobar',$data); -// // -// // $file=OC::$SERVERROOT.'/3rdparty/MDB2.php'; -// // $source=fopen($file,'r'); -// // $target=$this->getStream('test2','w',0); -// // OCP\Files::streamCopy($source,$target); -// // fclose($target); -// // fclose($source); -// // -// // $stream=$this->getStream('test2','r',filesize($file)); -// // $data=stream_get_contents($stream); -// // $original=file_get_contents($file); -// // $this->assertEquals(strlen($original),strlen($data)); -// // $this->assertEquals($original,$data); -// // } -// // -// // /** -// // * get a cryptstream to a temporary file -// // * @param string $id -// // * @param string $mode -// // * @param int size -// // * @return resource -// // */ -// // function getStream($id,$mode,$size){ -// // if($id===''){ -// // $id=uniqid(); -// // } -// // if(!isset($this->tmpFiles[$id])){ -// // $file=OCP\Files::tmpFile(); -// // $this->tmpFiles[$id]=$file; -// // }else{ -// // $file=$this->tmpFiles[$id]; -// // } -// // $stream=fopen($file,$mode); -// // OC_CryptStream::$sourceStreams[$id]=array('path'=>'dummy'.$id,'stream'=>$stream,'size'=>$size); -// // return fopen('crypt://streams/'.$id,$mode); -// // } -// // -// // function testBinary(){ -// // $file=__DIR__.'/binary'; -// // $source=file_get_contents($file); -// // -// // $stream=$this->getStream('test','w',strlen($source)); -// // fwrite($stream,$source); -// // fclose($stream); -// // -// // $stream=$this->getStream('test','r',strlen($source)); -// // $data=stream_get_contents($stream); -// // fclose($stream); -// // $this->assertEquals(strlen($data),strlen($source)); -// // $this->assertEquals($source,$data); -// // -// // $file=__DIR__.'/zeros'; -// // $source=file_get_contents($file); -// // -// // $stream=$this->getStream('test2','w',strlen($source)); -// // fwrite($stream,$source); -// // fclose($stream); -// // -// // $stream=$this->getStream('test2','r',strlen($source)); -// // $data=stream_get_contents($stream); -// // fclose($stream); -// // $this->assertEquals(strlen($data),strlen($source)); -// // $this->assertEquals($source,$data); -// // } -// // } +/** + * ownCloud + * + * @author Florin Peter + * @copyright 2013 Florin Peter + * + * 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 . + * + */ + +require_once realpath(dirname(__FILE__) . '/../../../lib/base.php'); +require_once realpath(dirname(__FILE__) . '/../lib/crypt.php'); +require_once realpath(dirname(__FILE__) . '/../lib/keymanager.php'); +require_once realpath(dirname(__FILE__) . '/../lib/proxy.php'); +require_once realpath(dirname(__FILE__) . '/../lib/stream.php'); +require_once realpath(dirname(__FILE__) . '/../lib/util.php'); +require_once realpath(dirname(__FILE__) . '/../appinfo/app.php'); + +use OCA\Encryption; + +/** + * Class Test_Encryption_Stream + * @brief this class provide basic stream tests + */ +class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase +{ + + public $userId; + public $pass; + /** + * @var \OC_FilesystemView + */ + public $view; + public $dataShort; + public $stateFilesTrashbin; + + function setUp() + { + // reset backend + \OC_User::useBackend('database'); + + // set user id + \OC_User::setUserId('admin'); + $this->userId = 'admin'; + $this->pass = 'admin'; + + // init filesystem view + $this->view = new \OC_FilesystemView('/'); + + // init short data + $this->dataShort = 'hats'; + + // init filesystem related hooks + \OCA\Encryption\Helper::registerFilesystemHooks(); + + // register encryption file proxy + \OC_FileProxy::register(new OCA\Encryption\Proxy()); + + // remember files_trashbin state + $this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin'); + + // we don't want to tests with app files_trashbin enabled + \OC_App::disable('files_trashbin'); + + // init filesystem for user + \OC_Util::tearDownFS(); + \OC_User::setUserId(''); + \OC\Files\Filesystem::tearDown(); + \OC_Util::setupFS($this->userId); + \OC_User::setUserId($this->userId); + + // login user + $params['uid'] = $this->userId; + $params['password'] = $this->pass; + OCA\Encryption\Hooks::login($params); + } + + function tearDown() + { + // reset app files_trashbin + if ($this->stateFilesTrashbin) { + OC_App::enable('files_trashbin'); + } else { + OC_App::disable('files_trashbin'); + } + + // clear all proxies + \OC_FileProxy::clearProxies(); + } + + function testStreamOptions() { + $filename = '/tmp-' . time(); + $view = new \OC\Files\View('/' . $this->userId . '/files'); + + // Save short data as encrypted file using stream wrapper + $cryptedFile = $view->file_put_contents($filename, $this->dataShort); + + // Test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); + + $handle = $view->fopen($filename, 'r'); + + // check if stream is at position zero + $this->assertEquals(0,ftell($handle)); + + // set stream options + $this->assertTrue(flock($handle, LOCK_SH)); + $this->assertTrue(flock($handle, LOCK_UN)); + + // tear down + $view->unlink($filename); + } + + function testStreamSetBlocking() { + $filename = '/tmp-' . time(); + $view = new \OC\Files\View('/' . $this->userId . '/files'); + + // Save short data as encrypted file using stream wrapper + $cryptedFile = $view->file_put_contents($filename, $this->dataShort); + + // Test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); + + $handle = $view->fopen($filename, 'r'); + + // set stream options + $this->assertTrue(stream_set_blocking($handle,1)); + + // tear down + $view->unlink($filename); + } + + function testStreamSetTimeout() { + $filename = '/tmp-' . time(); + $view = new \OC\Files\View('/' . $this->userId . '/files'); + + // Save short data as encrypted file using stream wrapper + $cryptedFile = $view->file_put_contents($filename, $this->dataShort); + + // Test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); + + $handle = $view->fopen($filename, 'r'); + + // set stream options + $this->assertFalse(stream_set_timeout($handle,1)); + + // tear down + $view->unlink($filename); + } + + function testStreamSetWriteBuffer() { + $filename = '/tmp-' . time(); + $view = new \OC\Files\View('/' . $this->userId . '/files'); + + // Save short data as encrypted file using stream wrapper + $cryptedFile = $view->file_put_contents($filename, $this->dataShort); + + // Test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); + + $handle = $view->fopen($filename, 'r'); + + // set stream options + $this->assertEquals(0, stream_set_write_buffer($handle,1024)); + + // tear down + $view->unlink($filename); + } +} \ No newline at end of file diff --git a/apps/files_encryption/tests/util.php b/apps/files_encryption/tests/util.php index 667ee24f04a..a2be8a40417 100755 --- a/apps/files_encryption/tests/util.php +++ b/apps/files_encryption/tests/util.php @@ -217,4 +217,61 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase $this->assertEquals($file, $filename); } + + function testIsSharedPath() { + $sharedPath = '/user1/files/Shared/test'; + $path = '/user1/files/test'; + + $this->assertTrue($this->util->isSharedPath($sharedPath)); + + $this->assertFalse($this->util->isSharedPath($path)); + } + + function testEncryptLagacyFiles() + { + $userView = new \OC_FilesystemView( '/' . $this->userId); + $view = new \OC_FilesystemView( '/' . $this->userId . '/files' ); + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $encryptionKeyContent = file_get_contents($this->legacyEncryptedDataKey); + $userView->file_put_contents('/encryption.key', $encryptionKeyContent); + + $legacyEncryptedData = file_get_contents($this->legacyEncryptedData); + $view->mkdir('/test/'); + $view->mkdir('/test/subtest/'); + $view->file_put_contents('/test/subtest/legacy-encrypted-text.txt', $legacyEncryptedData); + + $fileInfo = $view->getFileInfo('/test/subtest/legacy-encrypted-text.txt'); + $fileInfo['encrypted'] = true; + $view->putFileInfo('/test/subtest/legacy-encrypted-text.txt', $fileInfo); + + \OC_FileProxy::$enabled = $proxyStatus; + + $params['uid'] = $this->userId; + $params['password'] = $this->pass; + + $util = new Encryption\Util($this->view, $this->userId); + $util->setMigrationStatus(0); + + $this->assertTrue(OCA\Encryption\Hooks::login($params)); + + $this->assertEquals($this->lagacyKey, $_SESSION['legacyKey']); + + $files = $util->findEncFiles('/' . $this->userId . '/files/'); + + $this->assertTrue(is_array($files)); + + $found = false; + foreach($files['encrypted'] as $encryptedFile) { + if($encryptedFile['name'] === 'legacy-encrypted-text.txt') { + $found = true; + break; + } + } + + $this->assertTrue($found); + } } \ No newline at end of file -- cgit v1.2.3 From c6722581f982d05909664171bd66cc7ec2a2a67b Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Wed, 22 May 2013 02:02:42 +0200 Subject: fix pgsql error --- apps/files_encryption/lib/util.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 1f4609ae2f6..784d74bd759 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -706,13 +706,16 @@ class Util // NOTE: Stream{} will be invoked for handling // the encryption, and should handle all keys // and their generation etc. automatically - $size = stream_copy_to_stream($plainHandle2, $encHandle); + stream_copy_to_stream($plainHandle2, $encHandle); + + // get file size + $size = $this->view->filesize($rawPath . '.plaintmp'); // Delete temporary plain copy of file $this->view->unlink($rawPath . '.plaintmp'); // Add the file to the cache - \OC\Files\Filesystem::putFileInfo($plainFile['path'], array('encrypted' => true, 'size' => $size), ''); + \OC\Files\Filesystem::putFileInfo($plainFile['path'], array('encrypted' => true, 'size' => $size, 'unencrypted_size' => $size)); } // Encrypt legacy encrypted files -- cgit v1.2.3 From a9ebf2aabe0297e2bd02a07018d6bac3b2de65c6 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Thu, 23 May 2013 20:30:07 +0200 Subject: fix public link share if a user is logged in --- apps/files_encryption/lib/keymanager.php | 19 ++++++++++++++----- apps/files_encryption/lib/session.php | 4 +++- apps/files_encryption/lib/util.php | 16 +++++++++++++++- 3 files changed, 32 insertions(+), 7 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index ddd8f0ad6e2..58c1d4b24ad 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -237,10 +237,15 @@ class Keymanager } $util = new Util($view, \OCP\User::getUser()); - list($owner, $filename) = $util->getUidAndFilename($filePath); - $filePath_f = ltrim($filename, '/'); - $keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key'; + if ($util->isPublic()) { + $keyfilePath = $util->getKeyfilePath() . $filePath . '.key'; + } else { + list($owner, $filename) = $util->getUidAndFilename($filePath); + $filePath_f = ltrim($filename, '/'); + + $keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key'; + } $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; @@ -447,9 +452,13 @@ class Keymanager //here we need the currently logged in user, while userId can be a different user $util = new Util($view, \OCP\User::getUser()); - list($owner, $filename) = $util->getUidAndFilename($filePath); + if ($util->isPublic()) { + $shareKeyPath = $util->getSharekeyPath() . $filePath . '.' . $userId . '.shareKey'; + } else { + list($owner, $filename) = $util->getUidAndFilename($filePath); + $shareKeyPath = \OC\Files\Filesystem::normalizePath('/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey'); + } - $shareKeyPath = \OC\Files\Filesystem::normalizePath('/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey'); if ($view->file_exists($shareKeyPath)) { $result = $view->file_get_contents($shareKeyPath); diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index 8425cedd99f..86f56e56766 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -84,7 +84,9 @@ class Session } - if (\OCP\USER::getUser() === false) { + if (\OCP\USER::getUser() === false || + (isset($_GET['service']) && $_GET['service'] == 'files' && + isset($_GET['t']))) { // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 784d74bd759..e327c3403bb 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -129,7 +129,9 @@ class Util $this->recoveryKeyId = \OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); // if we are anonymous/public - if ($this->userId === false) { + if ($this->userId === false || + (isset($_GET['service']) && $_GET['service'] == 'files' && + isset($_GET['t']))) { $this->userId = $this->publicShareKeyId; // only handle for files_sharing app @@ -1491,4 +1493,16 @@ class Util $this->recoverAllFiles('/', $privateKey); } + + public function isPublic() { + return $this->isPublic; + } + + public function getKeyfilePath() { + return $this->keyfilesPath; + } + + public function getSharekeyPath() { + return $this->shareKeysPath; + } } -- cgit v1.2.3 From 7b07168c46d860583f112df4b25120be296b686d Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Thu, 23 May 2013 21:18:31 +0200 Subject: code clean up; nicer solution to solve the public link share problem if a user is logged in --- apps/files_encryption/lib/keymanager.php | 18 +++++------------- apps/files_encryption/lib/util.php | 13 +------------ 2 files changed, 6 insertions(+), 25 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 58c1d4b24ad..a8cbc19d401 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -238,14 +238,10 @@ class Keymanager $util = new Util($view, \OCP\User::getUser()); - if ($util->isPublic()) { - $keyfilePath = $util->getKeyfilePath() . $filePath . '.key'; - } else { - list($owner, $filename) = $util->getUidAndFilename($filePath); - $filePath_f = ltrim($filename, '/'); + list($owner, $filename) = $util->getUidAndFilename($filePath); + $filePath_f = ltrim($filename, '/'); - $keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key'; - } + $keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key'; $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; @@ -452,12 +448,8 @@ class Keymanager //here we need the currently logged in user, while userId can be a different user $util = new Util($view, \OCP\User::getUser()); - if ($util->isPublic()) { - $shareKeyPath = $util->getSharekeyPath() . $filePath . '.' . $userId . '.shareKey'; - } else { - list($owner, $filename) = $util->getUidAndFilename($filePath); - $shareKeyPath = \OC\Files\Filesystem::normalizePath('/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey'); - } + list($owner, $filename) = $util->getUidAndFilename($filePath); + $shareKeyPath = \OC\Files\Filesystem::normalizePath('/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey'); if ($view->file_exists($shareKeyPath)) { diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index e327c3403bb..d42fe9953b5 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -1139,7 +1139,7 @@ class Util $fileOwnerUid = $view->getOwner($path); // handle public access - if ($fileOwnerUid === false && $this->isPublic) { + if ($this->isPublic) { $filename = $path; $fileOwnerUid = $GLOBALS['fileOwner']; @@ -1494,15 +1494,4 @@ class Util $this->recoverAllFiles('/', $privateKey); } - public function isPublic() { - return $this->isPublic; - } - - public function getKeyfilePath() { - return $this->keyfilesPath; - } - - public function getSharekeyPath() { - return $this->shareKeysPath; - } } -- cgit v1.2.3 From 6c8de5ae6d11886d498e810808484a2bdfeaef12 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Thu, 23 May 2013 23:56:31 +0200 Subject: fixes after review from @DeepDiver1975 --- apps/files_encryption/hooks/hooks.php | 2 +- apps/files_encryption/js/settings-admin.js | 2 +- apps/files_encryption/js/settings-personal.js | 2 +- apps/files_encryption/lib/crypt.php | 246 ++++----- apps/files_encryption/lib/helper.php | 92 ++-- apps/files_encryption/lib/keymanager.php | 230 ++++---- apps/files_encryption/lib/proxy.php | 204 ++++--- apps/files_encryption/lib/session.php | 64 +-- apps/files_encryption/lib/stream.php | 170 +++--- apps/files_encryption/lib/util.php | 601 ++++++++++----------- apps/files_encryption/settings-admin.php | 1 - apps/files_encryption/settings-personal.php | 1 - .../templates/settings-personal.php | 13 - 13 files changed, 752 insertions(+), 876 deletions(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 53afefc721b..2066300a163 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -189,7 +189,7 @@ class Hooks { // Save public key $view->file_put_contents( '/public-keys/'.$user.'.public.key', $keypair['publicKey'] ); - // Encrypt private key empthy passphrase + // Encrypt private key empty passphrase $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], $newUserPassword ); // Save private key diff --git a/apps/files_encryption/js/settings-admin.js b/apps/files_encryption/js/settings-admin.js index c58d75341df..7c1866445ee 100644 --- a/apps/files_encryption/js/settings-admin.js +++ b/apps/files_encryption/js/settings-admin.js @@ -99,4 +99,4 @@ $(document).ready(function(){ ); }); -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/apps/files_encryption/js/settings-personal.js b/apps/files_encryption/js/settings-personal.js index 3b9b00dc797..312b672ad46 100644 --- a/apps/files_encryption/js/settings-personal.js +++ b/apps/files_encryption/js/settings-personal.js @@ -57,4 +57,4 @@ $(document).ready(function(){ } ); -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 1a5c9300a27..f5b7a8a0a40 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -26,7 +26,7 @@ namespace OCA\Encryption; //require_once '../3rdparty/Crypt_Blowfish/Blowfish.php'; -require_once realpath(dirname(__FILE__) . '/../3rdparty/Crypt_Blowfish/Blowfish.php'); +require_once realpath( dirname( __FILE__ ) . '/../3rdparty/Crypt_Blowfish/Blowfish.php' ); /** * Class for common cryptography functionality @@ -40,8 +40,7 @@ class Crypt * @param string $user name (use system wide setting if name=null) * @return string 'client' or 'server' */ - public static function mode($user = null) - { + public static function mode( $user = null ) { return 'server'; @@ -51,20 +50,19 @@ class Crypt * @brief Create a new encryption keypair * @return array publicKey, privatekey */ - public static function createKeypair() - { + public static function createKeypair() { - $res = openssl_pkey_new(array('private_key_bits' => 4096)); + $res = openssl_pkey_new( array( 'private_key_bits' => 4096 ) ); // Get private key - openssl_pkey_export($res, $privateKey); + openssl_pkey_export( $res, $privateKey ); // Get public key - $publicKey = openssl_pkey_get_details($res); + $publicKey = openssl_pkey_get_details( $res ); $publicKey = $publicKey['key']; - return (array('publicKey' => $publicKey, 'privateKey' => $privateKey)); + return ( array( 'publicKey' => $publicKey, 'privateKey' => $privateKey ) ); } @@ -77,8 +75,7 @@ class Crypt * blocks with encryption alone, hence padding is added to achieve the * required length. */ - public static function addPadding($data) - { + public static function addPadding( $data ) { $padded = $data . 'xx'; @@ -91,12 +88,11 @@ class Crypt * @param string $padded padded data to remove padding from * @return string unpadded data on success, false on error */ - public static function removePadding($padded) - { + public static function removePadding( $padded ) { - if (substr($padded, -2) == 'xx') { + if ( substr( $padded, -2 ) == 'xx' ) { - $data = substr($padded, 0, -2); + $data = substr( $padded, 0, -2 ); return $data; @@ -115,27 +111,26 @@ class Crypt * @return boolean * @note see also OCA\Encryption\Util->isEncryptedPath() */ - public static function isCatfileContent($content) - { + public static function isCatfileContent( $content ) { - if (!$content) { + if ( !$content ) { return false; } - $noPadding = self::removePadding($content); + $noPadding = self::removePadding( $content ); // Fetch encryption metadata from end of file - $meta = substr($noPadding, -22); + $meta = substr( $noPadding, -22 ); // Fetch IV from end of file - $iv = substr($meta, -16); + $iv = substr( $meta, -16 ); // Fetch identifier from start of metadata - $identifier = substr($meta, 0, 6); + $identifier = substr( $meta, 0, 6 ); - if ($identifier == '00iv00') { + if ( $identifier == '00iv00' ) { return true; @@ -152,16 +147,15 @@ class Crypt * @param string $path * @return bool */ - public static function isEncryptedMeta($path) - { + public static function isEncryptedMeta( $path ) { // TODO: Use DI to get \OC\Files\Filesystem out of here // Fetch all file metadata from DB - $metadata = \OC\Files\Filesystem::getFileInfo($path); + $metadata = \OC\Files\Filesystem::getFileInfo( $path ); // Return encryption status - return isset($metadata['encrypted']) and ( bool )$metadata['encrypted']; + return isset( $metadata['encrypted'] ) and ( bool )$metadata['encrypted']; } @@ -172,19 +166,18 @@ class Crypt * e.g. filename or /Docs/filename, NOT admin/files/filename * @return boolean */ - public static function isLegacyEncryptedContent($data, $relPath) - { + public static function isLegacyEncryptedContent( $data, $relPath ) { // Fetch all file metadata from DB - $metadata = \OC\Files\Filesystem::getFileInfo($relPath, ''); + $metadata = \OC\Files\Filesystem::getFileInfo( $relPath, '' ); // If a file is flagged with encryption in DB, but isn't a // valid content + IV combination, it's probably using the // legacy encryption system if ( - isset($metadata['encrypted']) + isset( $metadata['encrypted'] ) and $metadata['encrypted'] === true - and !self::isCatfileContent($data) + and !self::isCatfileContent( $data ) ) { return true; @@ -199,18 +192,20 @@ class Crypt /** * @brief Symmetrically encrypt a string + * @param $plainContent + * @param $iv + * @param string $passphrase * @return string encrypted file content */ - public static function encrypt($plainContent, $iv, $passphrase = '') - { + public static function encrypt( $plainContent, $iv, $passphrase = '' ) { - if ($encryptedContent = openssl_encrypt($plainContent, 'AES-128-CFB', $passphrase, false, $iv)) { + if ( $encryptedContent = openssl_encrypt( $plainContent, 'AES-128-CFB', $passphrase, false, $iv ) ) { return $encryptedContent; } else { - \OC_Log::write('Encryption library', 'Encryption (symmetric) of content failed', \OC_Log::ERROR); + \OC_Log::write( 'Encryption library', 'Encryption (symmetric) of content failed', \OC_Log::ERROR ); return false; @@ -220,21 +215,21 @@ class Crypt /** * @brief Symmetrically decrypt a string + * @param $encryptedContent + * @param $iv + * @param $passphrase + * @throws \Exception * @return string decrypted file content */ - public static function decrypt($encryptedContent, $iv, $passphrase) - { + public static function decrypt( $encryptedContent, $iv, $passphrase ) { - if ($plainContent = openssl_decrypt($encryptedContent, 'AES-128-CFB', $passphrase, false, $iv)) { + if ( $plainContent = openssl_decrypt( $encryptedContent, 'AES-128-CFB', $passphrase, false, $iv ) ) { return $plainContent; - } else { - throw new \Exception('Encryption library: Decryption (symmetric) of content failed'); - - return false; + throw new \Exception( 'Encryption library: Decryption (symmetric) of content failed' ); } @@ -246,8 +241,7 @@ class Crypt * @param string $iv IV to be concatenated * @returns string concatenated content */ - public static function concatIv($content, $iv) - { + public static function concatIv( $content, $iv ) { $combined = $content . '00iv00' . $iv; @@ -260,17 +254,16 @@ class Crypt * @param string $catFile concatenated data to be split * @returns array keys: encrypted, iv */ - public static function splitIv($catFile) - { + public static function splitIv( $catFile ) { // Fetch encryption metadata from end of file - $meta = substr($catFile, -22); + $meta = substr( $catFile, -22 ); // Fetch IV from end of file - $iv = substr($meta, -16); + $iv = substr( $meta, -16 ); // Remove IV and IV identifier text to expose encrypted content - $encrypted = substr($catFile, 0, -22); + $encrypted = substr( $catFile, 0, -22 ); $split = array( 'encrypted' => $encrypted @@ -290,10 +283,9 @@ class Crypt * @note IV need not be specified, as it will be stored in the returned keyfile * and remain accessible therein. */ - public static function symmetricEncryptFileContent($plainContent, $passphrase = '') - { + public static function symmetricEncryptFileContent( $plainContent, $passphrase = '' ) { - if (!$plainContent) { + if ( !$plainContent ) { return false; @@ -301,18 +293,18 @@ class Crypt $iv = self::generateIv(); - if ($encryptedContent = self::encrypt($plainContent, $iv, $passphrase)) { + if ( $encryptedContent = self::encrypt( $plainContent, $iv, $passphrase ) ) { // Combine content to encrypt with IV identifier and actual IV - $catfile = self::concatIv($encryptedContent, $iv); + $catfile = self::concatIv( $encryptedContent, $iv ); - $padded = self::addPadding($catfile); + $padded = self::addPadding( $catfile ); return $padded; } else { - \OC_Log::write('Encryption library', 'Encryption (symmetric) of keyfile content failed', \OC_Log::ERROR); + \OC_Log::write( 'Encryption library', 'Encryption (symmetric) of keyfile content failed', \OC_Log::ERROR ); return false; @@ -334,25 +326,26 @@ class Crypt * * This function decrypts a file */ - public static function symmetricDecryptFileContent($keyfileContent, $passphrase = '') - { + public static function symmetricDecryptFileContent( $keyfileContent, $passphrase = '' ) { - if (!$keyfileContent) { + if ( !$keyfileContent ) { - throw new \Exception('Encryption library: no data provided for decryption'); + throw new \Exception( 'Encryption library: no data provided for decryption' ); } // Remove padding - $noPadding = self::removePadding($keyfileContent); + $noPadding = self::removePadding( $keyfileContent ); // Split into enc data and catfile - $catfile = self::splitIv($noPadding); + $catfile = self::splitIv( $noPadding ); - if ($plainContent = self::decrypt($catfile['encrypted'], $catfile['iv'], $passphrase)) { + if ( $plainContent = self::decrypt( $catfile['encrypted'], $catfile['iv'], $passphrase ) ) { return $plainContent; + } else { + return false; } } @@ -365,16 +358,15 @@ class Crypt * * This function decrypts a file */ - public static function symmetricEncryptFileContentKeyfile($plainContent) - { + public static function symmetricEncryptFileContentKeyfile( $plainContent ) { $key = self::generateKey(); - if ($encryptedContent = self::symmetricEncryptFileContent($plainContent, $key)) { + if ( $encryptedContent = self::symmetricEncryptFileContent( $plainContent, $key ) ) { return array( - 'key' => $key - , 'encrypted' => $encryptedContent + 'key' => $key, + 'encrypted' => $encryptedContent ); } else { @@ -392,29 +384,28 @@ class Crypt * @returns array keys: keys (array, key = userId), data * @note symmetricDecryptFileContent() can decrypt files created using this method */ - public static function multiKeyEncrypt($plainContent, array $publicKeys) - { + public static function multiKeyEncrypt( $plainContent, array $publicKeys ) { // openssl_seal returns false without errors if $plainContent // is empty, so trigger our own error - if (empty($plainContent)) { + if ( empty( $plainContent ) ) { - trigger_error("Cannot mutliKeyEncrypt empty plain content"); - throw new \Exception('Cannot mutliKeyEncrypt empty plain content'); + throw new \Exception( 'Cannot mutliKeyEncrypt empty plain content' ); } // Set empty vars to be set by openssl by reference $sealed = ''; $shareKeys = array(); + $mappedShareKeys = array(); - if (openssl_seal($plainContent, $sealed, $shareKeys, $publicKeys)) { + if ( openssl_seal( $plainContent, $sealed, $shareKeys, $publicKeys ) ) { $i = 0; // Ensure each shareKey is labelled with its // corresponding userId - foreach ($publicKeys as $userId => $publicKey) { + foreach ( $publicKeys as $userId => $publicKey ) { $mappedShareKeys[$userId] = $shareKeys[$i]; $i++; @@ -422,8 +413,8 @@ class Crypt } return array( - 'keys' => $mappedShareKeys - , 'data' => $sealed + 'keys' => $mappedShareKeys, + 'data' => $sealed ); } else { @@ -446,22 +437,21 @@ class Crypt * * This function decrypts a file */ - public static function multiKeyDecrypt($encryptedContent, $shareKey, $privateKey) - { + public static function multiKeyDecrypt( $encryptedContent, $shareKey, $privateKey ) { - if (!$encryptedContent) { + if ( !$encryptedContent ) { return false; } - if (openssl_open($encryptedContent, $plainContent, $shareKey, $privateKey)) { + if ( openssl_open( $encryptedContent, $plainContent, $shareKey, $privateKey ) ) { return $plainContent; } else { - \OC_Log::write('Encryption library', 'Decryption (asymmetric) of sealed content failed', \OC_Log::ERROR); + \OC_Log::write( 'Encryption library', 'Decryption (asymmetric) of sealed content failed', \OC_Log::ERROR ); return false; @@ -473,10 +463,9 @@ class Crypt * @brief Asymetrically encrypt a string using a public key * @return string encrypted file */ - public static function keyEncrypt($plainContent, $publicKey) - { + public static function keyEncrypt( $plainContent, $publicKey ) { - openssl_public_encrypt($plainContent, $encryptedContent, $publicKey); + openssl_public_encrypt( $plainContent, $encryptedContent, $publicKey ); return $encryptedContent; @@ -486,12 +475,11 @@ class Crypt * @brief Asymetrically decrypt a file using a private key * @return string decrypted file */ - public static function keyDecrypt($encryptedContent, $privatekey) - { + public static function keyDecrypt( $encryptedContent, $privatekey ) { - $result = @openssl_private_decrypt($encryptedContent, $plainContent, $privatekey); + $result = @openssl_private_decrypt( $encryptedContent, $plainContent, $privatekey ); - if ($result) { + if ( $result ) { return $plainContent; } @@ -503,27 +491,26 @@ class Crypt * @brief Generates a pseudo random initialisation vector * @return String $iv generated IV */ - public static function generateIv() - { + public static function generateIv() { - if ($random = openssl_random_pseudo_bytes(12, $strong)) { + if ( $random = openssl_random_pseudo_bytes( 12, $strong ) ) { - if (!$strong) { + if ( !$strong ) { // If OpenSSL indicates randomness is insecure, log error - \OC_Log::write('Encryption library', 'Insecure symmetric key was generated using openssl_random_pseudo_bytes()', \OC_Log::WARN); + \OC_Log::write( 'Encryption library', 'Insecure symmetric key was generated using openssl_random_pseudo_bytes()', \OC_Log::WARN ); } // We encode the iv purely for string manipulation // purposes - it gets decoded before use - $iv = base64_encode($random); + $iv = base64_encode( $random ); return $iv; } else { - throw new \Exception('Generating IV failed'); + throw new \Exception( 'Generating IV failed' ); } @@ -533,16 +520,15 @@ class Crypt * @brief Generate a pseudo random 1024kb ASCII key * @returns $key Generated key */ - public static function generateKey() - { + public static function generateKey() { // Generate key - if ($key = base64_encode(openssl_random_pseudo_bytes(183, $strong))) { + if ( $key = base64_encode( openssl_random_pseudo_bytes( 183, $strong ) ) ) { - if (!$strong) { + if ( !$strong ) { // If OpenSSL indicates randomness is insecure, log error - throw new \Exception('Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()'); + throw new \Exception( 'Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()' ); } @@ -563,12 +549,11 @@ class Crypt * * if the key is left out, the default handeler will be used */ - public static function getBlowfish($key = '') - { + public static function getBlowfish( $key = '' ) { - if ($key) { + if ( $key ) { - return new \Crypt_Blowfish($key); + return new \Crypt_Blowfish( $key ); } else { @@ -582,14 +567,13 @@ class Crypt * @param $passphrase * @return mixed */ - public static function legacyCreateKey($passphrase) - { + public static function legacyCreateKey( $passphrase ) { // Generate a random integer - $key = mt_rand(10000, 99999) . mt_rand(10000, 99999) . mt_rand(10000, 99999) . mt_rand(10000, 99999); + $key = mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ); // Encrypt the key with the passphrase - $legacyEncKey = self::legacyEncrypt($key, $passphrase); + $legacyEncKey = self::legacyEncrypt( $key, $passphrase ); return $legacyEncKey; @@ -605,12 +589,11 @@ class Crypt * * This function encrypts an content */ - public static function legacyEncrypt($content, $passphrase = '') - { + public static function legacyEncrypt( $content, $passphrase = '' ) { - $bf = self::getBlowfish($passphrase); + $bf = self::getBlowfish( $passphrase ); - return $bf->encrypt($content); + return $bf->encrypt( $content ); } @@ -624,14 +607,13 @@ class Crypt * * This function decrypts an content */ - public static function legacyDecrypt($content, $passphrase = '') - { + public static function legacyDecrypt( $content, $passphrase = '' ) { - $bf = self::getBlowfish($passphrase); + $bf = self::getBlowfish( $passphrase ); - $decrypted = $bf->decrypt($content); + $decrypted = $bf->decrypt( $content ); - return rtrim($decrypted, "\0");; + return rtrim( $decrypted, "\0" );; } @@ -641,17 +623,16 @@ class Crypt * @param int $maxLength * @return string */ - private static function legacyBlockDecrypt($data, $key = '', $maxLength = 0) - { + private static function legacyBlockDecrypt( $data, $key = '', $maxLength = 0 ) { $result = ''; - while (strlen($data)) { - $result .= self::legacyDecrypt(substr($data, 0, 8192), $key); - $data = substr($data, 8192); + while ( strlen( $data ) ) { + $result .= self::legacyDecrypt( substr( $data, 0, 8192 ), $key ); + $data = substr( $data, 8192 ); } - if ($maxLength > 0) { - return substr($result, 0, $maxLength); + if ( $maxLength > 0 ) { + return substr( $result, 0, $maxLength ); } else { - return rtrim($result, "\0"); + return rtrim( $result, "\0" ); } } @@ -663,18 +644,17 @@ class Crypt * @param $path * @return array */ - public static function legacyKeyRecryptKeyfile($legacyEncryptedContent, $legacyPassphrase, $publicKeys, $newPassphrase, $path) - { + public static function legacyKeyRecryptKeyfile( $legacyEncryptedContent, $legacyPassphrase, $publicKeys, $newPassphrase, $path ) { - $decrypted = self::legacyBlockDecrypt($legacyEncryptedContent, $legacyPassphrase); + $decrypted = self::legacyBlockDecrypt( $legacyEncryptedContent, $legacyPassphrase ); // Encrypt plain data, generate keyfile & encrypted file - $cryptedData = self::symmetricEncryptFileContentKeyfile($decrypted); + $cryptedData = self::symmetricEncryptFileContentKeyfile( $decrypted ); // Encrypt plain keyfile to multiple sharefiles - $multiEncrypted = Crypt::multiKeyEncrypt($cryptedData['key'], $publicKeys); + $multiEncrypted = Crypt::multiKeyEncrypt( $cryptedData['key'], $publicKeys ); - return array('data' => $cryptedData['encrypted'], 'filekey' => $multiEncrypted['data'], 'sharekeys' => $multiEncrypted['keys']); + return array( 'data' => $cryptedData['encrypted'], 'filekey' => $multiEncrypted['data'], 'sharekeys' => $multiEncrypted['keys'] ); } diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php index e4bf2c1226a..43f573c16b9 100755 --- a/apps/files_encryption/lib/helper.php +++ b/apps/files_encryption/lib/helper.php @@ -37,35 +37,32 @@ class Helper * @brief register share related hooks * */ - public static function registerShareHooks() - { + public static function registerShareHooks() { - \OCP\Util::connectHook('OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared'); - \OCP\Util::connectHook('OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared'); - \OCP\Util::connectHook('OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare'); + \OCP\Util::connectHook( 'OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared' ); + \OCP\Util::connectHook( 'OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared' ); + \OCP\Util::connectHook( 'OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare' ); } /** * @brief register user related hooks * */ - public static function registerUserHooks() - { + public static function registerUserHooks() { - \OCP\Util::connectHook('OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login'); - \OCP\Util::connectHook('OC_User', 'post_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase'); - \OCP\Util::connectHook('OC_User', 'post_createUser', 'OCA\Encryption\Hooks', 'postCreateUser'); - \OCP\Util::connectHook('OC_User', 'post_deleteUser', 'OCA\Encryption\Hooks', 'postDeleteUser'); + \OCP\Util::connectHook( 'OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login' ); + \OCP\Util::connectHook( 'OC_User', 'post_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase' ); + \OCP\Util::connectHook( 'OC_User', 'post_createUser', 'OCA\Encryption\Hooks', 'postCreateUser' ); + \OCP\Util::connectHook( 'OC_User', 'post_deleteUser', 'OCA\Encryption\Hooks', 'postDeleteUser' ); } /** * @brief register filesystem related hooks * */ - public static function registerFilesystemHooks() - { + public static function registerFilesystemHooks() { - \OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename'); + \OCP\Util::connectHook( 'OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename' ); } /** @@ -75,14 +72,13 @@ class Helper * @param string $password * @return bool */ - public static function setupUser($util, $password) - { + public static function setupUser( $util, $password ) { // Check files_encryption infrastructure is ready for action - if (!$util->ready()) { + if ( !$util->ready() ) { - \OC_Log::write('Encryption library', 'User account "' . $util->getUserId() . '" is not ready for encryption; configuration started', \OC_Log::DEBUG); + \OC_Log::write( 'Encryption library', 'User account "' . $util->getUserId() . '" is not ready for encryption; configuration started', \OC_Log::DEBUG ); - if (!$util->setupServerSide($password)) { + if ( !$util->setupServerSide( $password ) ) { return false; } } @@ -99,22 +95,21 @@ class Helper * @internal param string $password * @return bool */ - public static function adminEnableRecovery($recoveryKeyId, $recoveryPassword) - { - $view = new \OC\Files\View('/'); + public static function adminEnableRecovery( $recoveryKeyId, $recoveryPassword ) { + $view = new \OC\Files\View( '/' ); - if ($recoveryKeyId === null) { - $recoveryKeyId = 'recovery_' . substr(md5(time()), 0, 8); - \OC_Appconfig::setValue('files_encryption', 'recoveryKeyId', $recoveryKeyId); + if ( $recoveryKeyId === null ) { + $recoveryKeyId = 'recovery_' . substr( md5( time() ), 0, 8 ); + \OC_Appconfig::setValue( 'files_encryption', 'recoveryKeyId', $recoveryKeyId ); } - if (!$view->is_dir('/owncloud_private_key')) { - $view->mkdir('/owncloud_private_key'); + if ( !$view->is_dir( '/owncloud_private_key' ) ) { + $view->mkdir( '/owncloud_private_key' ); } if ( - (!$view->file_exists("/public-keys/" . $recoveryKeyId . ".public.key") - || !$view->file_exists("/owncloud_private_key/" . $recoveryKeyId . ".private.key")) + ( !$view->file_exists( "/public-keys/" . $recoveryKeyId . ".public.key" ) + || !$view->file_exists( "/owncloud_private_key/" . $recoveryKeyId . ".private.key" ) ) ) { $keypair = \OCA\Encryption\Crypt::createKeypair(); @@ -123,37 +118,37 @@ class Helper // Save public key - if (!$view->is_dir('/public-keys')) { - $view->mkdir('/public-keys'); + if ( !$view->is_dir( '/public-keys' ) ) { + $view->mkdir( '/public-keys' ); } - $view->file_put_contents('/public-keys/' . $recoveryKeyId . '.public.key', $keypair['publicKey']); + $view->file_put_contents( '/public-keys/' . $recoveryKeyId . '.public.key', $keypair['publicKey'] ); // Encrypt private key empthy passphrase - $encryptedPrivateKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($keypair['privateKey'], $recoveryPassword); + $encryptedPrivateKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent( $keypair['privateKey'], $recoveryPassword ); // Save private key - $view->file_put_contents('/owncloud_private_key/' . $recoveryKeyId . '.private.key', $encryptedPrivateKey); + $view->file_put_contents( '/owncloud_private_key/' . $recoveryKeyId . '.private.key', $encryptedPrivateKey ); // create control file which let us check later on if the entered password was correct. - $encryptedControlData = \OCA\Encryption\Crypt::keyEncrypt("ownCloud", $keypair['publicKey']); - if (!$view->is_dir('/control-file')) { - $view->mkdir('/control-file'); + $encryptedControlData = \OCA\Encryption\Crypt::keyEncrypt( "ownCloud", $keypair['publicKey'] ); + if ( !$view->is_dir( '/control-file' ) ) { + $view->mkdir( '/control-file' ); } - $view->file_put_contents('/control-file/controlfile.enc', $encryptedControlData); + $view->file_put_contents( '/control-file/controlfile.enc', $encryptedControlData ); \OC_FileProxy::$enabled = true; // Set recoveryAdmin as enabled - \OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); + \OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminEnabled', 1 ); $return = true; } else { // get recovery key and check the password - $util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \OCP\User::getUser()); - $return = $util->checkRecoveryPassword($_POST['recoveryPassword']); - if ($return) { - \OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); + $util = new \OCA\Encryption\Util( new \OC_FilesystemView( '/' ), \OCP\User::getUser() ); + $return = $util->checkRecoveryPassword( $_POST['recoveryPassword'] ); + if ( $return ) { + \OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminEnabled', 1 ); } } @@ -167,14 +162,13 @@ class Helper * @param $recoveryPassword * @return bool */ - public static function adminDisableRecovery($recoveryPassword) - { - $util = new Util(new \OC_FilesystemView('/'), \OCP\User::getUser()); - $return = $util->checkRecoveryPassword($recoveryPassword); + public static function adminDisableRecovery( $recoveryPassword ) { + $util = new Util( new \OC_FilesystemView( '/' ), \OCP\User::getUser() ); + $return = $util->checkRecoveryPassword( $recoveryPassword ); - if ($return) { + if ( $return ) { // Set recoveryAdmin as disabled - \OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 0); + \OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminEnabled', 0 ); } return $return; diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index a8cbc19d401..aaa2e4ba1b5 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -38,15 +38,14 @@ class Keymanager * @return string private key or false (hopefully) * @note the key returned by this method must be decrypted before use */ - public static function getPrivateKey(\OC_FilesystemView $view, $user) - { + public static function getPrivateKey( \OC_FilesystemView $view, $user ) { $path = '/' . $user . '/' . 'files_encryption' . '/' . $user . '.private.key'; $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $key = $view->file_get_contents($path); + $key = $view->file_get_contents( $path ); \OC_FileProxy::$enabled = $proxyStatus; @@ -59,13 +58,12 @@ class Keymanager * @param $userId * @return string public key or false */ - public static function getPublicKey(\OC_FilesystemView $view, $userId) - { + public static function getPublicKey( \OC_FilesystemView $view, $userId ) { $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $result = $view->file_get_contents('/public-keys/' . $userId . '.public.key'); + $result = $view->file_get_contents( '/public-keys/' . $userId . '.public.key' ); \OC_FileProxy::$enabled = $proxyStatus; @@ -79,12 +77,11 @@ class Keymanager * @param $userId * @return array keys: privateKey, publicKey */ - public static function getUserKeys(\OC_FilesystemView $view, $userId) - { + public static function getUserKeys( \OC_FilesystemView $view, $userId ) { return array( - 'publicKey' => self::getPublicKey($view, $userId) - , 'privateKey' => self::getPrivateKey($view, $userId) + 'publicKey' => self::getPublicKey( $view, $userId ) + , 'privateKey' => self::getPrivateKey( $view, $userId ) ); } @@ -95,14 +92,13 @@ class Keymanager * @param array $userIds * @return array of public keys for the specified users */ - public static function getPublicKeys(\OC_FilesystemView $view, array $userIds) - { + public static function getPublicKeys( \OC_FilesystemView $view, array $userIds ) { $keys = array(); - foreach ($userIds as $userId) { + foreach ( $userIds as $userId ) { - $keys[$userId] = self::getPublicKey($view, $userId); + $keys[$userId] = self::getPublicKey( $view, $userId ); } @@ -122,41 +118,40 @@ class Keymanager * @note The keyfile is not encrypted here. Client code must * asymmetrically encrypt the keyfile before passing it to this method */ - public static function setFileKey(\OC_FilesystemView $view, $path, $userId, $catfile) - { + public static function setFileKey( \OC_FilesystemView $view, $path, $userId, $catfile ) { $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; //here we need the currently logged in user, while userId can be a different user - $util = new Util($view, \OCP\User::getUser()); - list($owner, $filename) = $util->getUidAndFilename($path); + $util = new Util( $view, \OCP\User::getUser() ); + list( $owner, $filename ) = $util->getUidAndFilename( $path ); $basePath = '/' . $owner . '/files_encryption/keyfiles'; - $targetPath = self::keySetPreparation($view, $filename, $basePath, $owner); + $targetPath = self::keySetPreparation( $view, $filename, $basePath, $owner ); - if (!$view->is_dir($basePath . '/' . $targetPath)) { + if ( !$view->is_dir( $basePath . '/' . $targetPath ) ) { // create all parent folders - $info = pathinfo($basePath . '/' . $targetPath); - $keyfileFolderName = $view->getLocalFolder($info['dirname']); + $info = pathinfo( $basePath . '/' . $targetPath ); + $keyfileFolderName = $view->getLocalFolder( $info['dirname'] ); - if (!file_exists($keyfileFolderName)) { + if ( !file_exists( $keyfileFolderName ) ) { - mkdir($keyfileFolderName, 0750, true); + mkdir( $keyfileFolderName, 0750, true ); } } // try reusing key file if part file - if (self::isPartialFilePath($targetPath)) { + if ( self::isPartialFilePath( $targetPath ) ) { - $result = $view->file_put_contents($basePath . '/' . self::fixPartialFilePath($targetPath) . '.key', $catfile); + $result = $view->file_put_contents( $basePath . '/' . self::fixPartialFilePath( $targetPath ) . '.key', $catfile ); } else { - $result = $view->file_put_contents($basePath . '/' . $targetPath . '.key', $catfile); + $result = $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); } @@ -172,13 +167,12 @@ class Keymanager * @return string File path without .part extension * @note this is needed for reusing keys */ - public static function fixPartialFilePath($path) - { + public static function fixPartialFilePath( $path ) { - if (preg_match('/\.part$/', $path)) { + if ( preg_match( '/\.part$/', $path ) ) { - $newLength = strlen($path) - 5; - $fPath = substr($path, 0, $newLength); + $newLength = strlen( $path ) - 5; + $fPath = substr( $path, 0, $newLength ); return $fPath; @@ -195,10 +189,9 @@ class Keymanager * @param string $path Path that may identify a .part file * @return bool */ - public static function isPartialFilePath($path) - { + public static function isPartialFilePath( $path ) { - if (preg_match('/\.part$/', $path)) { + if ( preg_match( '/\.part$/', $path ) ) { return true; @@ -220,15 +213,14 @@ class Keymanager * @note The keyfile returned is asymmetrically encrypted. Decryption * of the keyfile must be performed by client code */ - public static function getFileKey(\OC_FilesystemView $view, $userId, $filePath) - { + public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) { // try reusing key file if part file - if (self::isPartialFilePath($filePath)) { + if ( self::isPartialFilePath( $filePath ) ) { - $result = self::getFileKey($view, $userId, self::fixPartialFilePath($filePath)); + $result = self::getFileKey( $view, $userId, self::fixPartialFilePath( $filePath ) ); - if ($result) { + if ( $result ) { return $result; @@ -236,19 +228,19 @@ class Keymanager } - $util = new Util($view, \OCP\User::getUser()); + $util = new Util( $view, \OCP\User::getUser() ); - list($owner, $filename) = $util->getUidAndFilename($filePath); - $filePath_f = ltrim($filename, '/'); + list( $owner, $filename ) = $util->getUidAndFilename( $filePath ); + $filePath_f = ltrim( $filename, '/' ); $keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key'; $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - if ($view->file_exists($keyfilePath)) { + if ( $view->file_exists( $keyfilePath ) ) { - $result = $view->file_get_contents($keyfilePath); + $result = $view->file_get_contents( $keyfilePath ); } else { @@ -272,27 +264,26 @@ class Keymanager * @note $path must be relative to data/user/files. e.g. mydoc.txt NOT * /data/admin/files/mydoc.txt */ - public static function deleteFileKey(\OC_FilesystemView $view, $userId, $path) - { + public static function deleteFileKey( \OC_FilesystemView $view, $userId, $path ) { - $trimmed = ltrim($path, '/'); + $trimmed = ltrim( $path, '/' ); $keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed; $result = false; - if ($view->is_dir($keyPath)) { + if ( $view->is_dir( $keyPath ) ) { - $result = $view->unlink($keyPath); + $result = $view->unlink( $keyPath ); - } else if ($view->file_exists($keyPath . '.key')) { + } else if ( $view->file_exists( $keyPath . '.key' ) ) { - $result = $view->unlink($keyPath . '.key'); + $result = $view->unlink( $keyPath . '.key' ); } - if (!$result) { + if ( !$result ) { - \OC_Log::write('Encryption library', 'Could not delete keyfile; does not exist: "' . $keyPath, \OC_Log::ERROR); + \OC_Log::write( 'Encryption library', 'Could not delete keyfile; does not exist: "' . $keyPath, \OC_Log::ERROR ); } @@ -307,19 +298,19 @@ class Keymanager * @note Encryption of the private key must be performed by client code * as no encryption takes place here */ - public static function setPrivateKey($key) - { + public static function setPrivateKey( $key ) { $user = \OCP\User::getUser(); - $view = new \OC_FilesystemView('/' . $user . '/files_encryption'); + $view = new \OC_FilesystemView( '/' . $user . '/files_encryption' ); $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - if (!$view->file_exists('')) $view->mkdir(''); + if ( !$view->file_exists( '' ) ) + $view->mkdir( '' ); - $result = $view->file_put_contents($user . '.private.key', $key); + $result = $view->file_put_contents( $user . '.private.key', $key ); \OC_FileProxy::$enabled = $proxyStatus; @@ -340,22 +331,21 @@ class Keymanager * @note The keyfile is not encrypted here. Client code must * asymmetrically encrypt the keyfile before passing it to this method */ - public static function setShareKey(\OC_FilesystemView $view, $path, $userId, $shareKey) - { + public static function setShareKey( \OC_FilesystemView $view, $path, $userId, $shareKey ) { // Here we need the currently logged in user, while userId can be a different user - $util = new Util($view, \OCP\User::getUser()); + $util = new Util( $view, \OCP\User::getUser() ); - list($owner, $filename) = $util->getUidAndFilename($path); + list( $owner, $filename ) = $util->getUidAndFilename( $path ); $basePath = '/' . $owner . '/files_encryption/share-keys'; - $shareKeyPath = self::keySetPreparation($view, $filename, $basePath, $owner); + $shareKeyPath = self::keySetPreparation( $view, $filename, $basePath, $owner ); // try reusing key file if part file - if (self::isPartialFilePath($shareKeyPath)) { + if ( self::isPartialFilePath( $shareKeyPath ) ) { - $writePath = $basePath . '/' . self::fixPartialFilePath($shareKeyPath) . '.' . $userId . '.shareKey'; + $writePath = $basePath . '/' . self::fixPartialFilePath( $shareKeyPath ) . '.' . $userId . '.shareKey'; } else { @@ -366,12 +356,12 @@ class Keymanager $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $result = $view->file_put_contents($writePath, $shareKey); + $result = $view->file_put_contents( $writePath, $shareKey ); \OC_FileProxy::$enabled = $proxyStatus; if ( - is_int($result) + is_int( $result ) && $result > 0 ) { @@ -392,17 +382,16 @@ class Keymanager * @param array $shareKeys * @return bool */ - public static function setShareKeys(\OC_FilesystemView $view, $path, array $shareKeys) - { + public static function setShareKeys( \OC_FilesystemView $view, $path, array $shareKeys ) { // $shareKeys must be an array with the following format: // [userId] => [encrypted key] $result = true; - foreach ($shareKeys as $userId => $shareKey) { + foreach ( $shareKeys as $userId => $shareKey ) { - if (!self::setShareKey($view, $path, $userId, $shareKey)) { + if ( !self::setShareKey( $view, $path, $userId, $shareKey ) ) { // If any of the keys are not set, flag false $result = false; @@ -426,15 +415,14 @@ class Keymanager * @note The sharekey returned is encrypted. Decryption * of the keyfile must be performed by client code */ - public static function getShareKey(\OC_FilesystemView $view, $userId, $filePath) - { + public static function getShareKey( \OC_FilesystemView $view, $userId, $filePath ) { // try reusing key file if part file - if (self::isPartialFilePath($filePath)) { + if ( self::isPartialFilePath( $filePath ) ) { - $result = self::getShareKey($view, $userId, self::fixPartialFilePath($filePath)); + $result = self::getShareKey( $view, $userId, self::fixPartialFilePath( $filePath ) ); - if ($result) { + if ( $result ) { return $result; @@ -446,14 +434,14 @@ class Keymanager \OC_FileProxy::$enabled = false; //here we need the currently logged in user, while userId can be a different user - $util = new Util($view, \OCP\User::getUser()); + $util = new Util( $view, \OCP\User::getUser() ); - list($owner, $filename) = $util->getUidAndFilename($filePath); - $shareKeyPath = \OC\Files\Filesystem::normalizePath('/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey'); + list( $owner, $filename ) = $util->getUidAndFilename( $filePath ); + $shareKeyPath = \OC\Files\Filesystem::normalizePath( '/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey' ); - if ($view->file_exists($shareKeyPath)) { + if ( $view->file_exists( $shareKeyPath ) ) { - $result = $view->file_get_contents($shareKeyPath); + $result = $view->file_get_contents( $shareKeyPath ); } else { @@ -473,16 +461,18 @@ class Keymanager * @param string $userId owner of the file * @param string $filePath path to the file, relative to the owners file dir */ - public static function delAllShareKeys(\OC_FilesystemView $view, $userId, $filePath) - { + public static function delAllShareKeys( \OC_FilesystemView $view, $userId, $filePath ) { - if ($view->is_dir($userId . '/files/' . $filePath)) { - $view->unlink($userId . '/files_encryption/share-keys/' . $filePath); + if ( $view->is_dir( $userId . '/files/' . $filePath ) ) { + $view->unlink( $userId . '/files_encryption/share-keys/' . $filePath ); } else { - $localKeyPath = $view->getLocalFile($userId . '/files_encryption/share-keys/' . $filePath); - $matches = glob(preg_quote($localKeyPath) . '*.shareKey'); - foreach ($matches as $ma) { - unlink($ma); + $localKeyPath = $view->getLocalFile( $userId . '/files_encryption/share-keys/' . $filePath ); + $matches = glob( preg_quote( $localKeyPath ) . '*.shareKey' ); + foreach ( $matches as $ma ) { + $result = unlink( $ma ); + if ( !$result ) { + \OC_Log::write( 'Encryption library', 'Keyfile or shareKey could not be deleted for file "' . $filePath . '"', \OC_Log::ERROR ); + } } } } @@ -490,30 +480,29 @@ class Keymanager /** * @brief Delete a single user's shareKey for a single file */ - public static function delShareKey(\OC_FilesystemView $view, $userIds, $filePath) - { + public static function delShareKey( \OC_FilesystemView $view, $userIds, $filePath ) { $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; //here we need the currently logged in user, while userId can be a different user - $util = new Util($view, \OCP\User::getUser()); + $util = new Util( $view, \OCP\User::getUser() ); - list($owner, $filename) = $util->getUidAndFilename($filePath); + list( $owner, $filename ) = $util->getUidAndFilename( $filePath ); - $shareKeyPath = \OC\Files\Filesystem::normalizePath('/' . $owner . '/files_encryption/share-keys/' . $filename); + $shareKeyPath = \OC\Files\Filesystem::normalizePath( '/' . $owner . '/files_encryption/share-keys/' . $filename ); - if ($view->is_dir($shareKeyPath)) { + if ( $view->is_dir( $shareKeyPath ) ) { - $localPath = \OC\Files\Filesystem::normalizePath($view->getLocalFolder($shareKeyPath)); - self::recursiveDelShareKeys($localPath, $userIds); + $localPath = \OC\Files\Filesystem::normalizePath( $view->getLocalFolder( $shareKeyPath ) ); + self::recursiveDelShareKeys( $localPath, $userIds ); } else { - foreach ($userIds as $userId) { + foreach ( $userIds as $userId ) { - if (!$view->unlink($shareKeyPath . '.' . $userId . '.shareKey')) { - \OC_Log::write('Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath . '.' . $userId . '.shareKey"', \OC_Log::ERROR); + if ( !$view->unlink( $shareKeyPath . '.' . $userId . '.shareKey' ) ) { + \OC_Log::write( 'Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath . '.' . $userId . '.shareKey"', \OC_Log::ERROR ); } } @@ -528,45 +517,42 @@ class Keymanager * @param string $dir directory * @param array $userIds user ids for which the share keys should be deleted */ - private static function recursiveDelShareKeys($dir, $userIds) - { - foreach ($userIds as $userId) { - $completePath = $dir . '/.*' . '.' . $userId . '.shareKey'; - $matches = glob(preg_quote($dir) . '/*' . preg_quote('.' . $userId . '.shareKey')); + private static function recursiveDelShareKeys( $dir, $userIds ) { + foreach ( $userIds as $userId ) { + $matches = glob( preg_quote( $dir ) . '/*' . preg_quote( '.' . $userId . '.shareKey' ) ); } /** @var $matches array */ - foreach ($matches as $ma) { - if (!unlink($ma)) { - \OC_Log::write('Encryption library', 'Could not delete shareKey; does not exist: "' . $ma . '"', \OC_Log::ERROR); + foreach ( $matches as $ma ) { + if ( !unlink( $ma ) ) { + \OC_Log::write( 'Encryption library', 'Could not delete shareKey; does not exist: "' . $ma . '"', \OC_Log::ERROR ); } } - $subdirs = $directories = glob(preg_quote($dir) . '/*', GLOB_ONLYDIR); - foreach ($subdirs as $subdir) { - self::recursiveDelShareKeys($subdir, $userIds); + $subdirs = $directories = glob( preg_quote( $dir ) . '/*', GLOB_ONLYDIR ); + foreach ( $subdirs as $subdir ) { + self::recursiveDelShareKeys( $subdir, $userIds ); } } /** * @brief Make preparations to vars and filesystem for saving a keyfile */ - public static function keySetPreparation(\OC_FilesystemView $view, $path, $basePath, $userId) - { + public static function keySetPreparation( \OC_FilesystemView $view, $path, $basePath, $userId ) { - $targetPath = ltrim($path, '/'); + $targetPath = ltrim( $path, '/' ); - $path_parts = pathinfo($targetPath); + $path_parts = pathinfo( $targetPath ); // If the file resides within a subdirectory, create it if ( - isset($path_parts['dirname']) - && !$view->file_exists($basePath . '/' . $path_parts['dirname']) + isset( $path_parts['dirname'] ) + && !$view->file_exists( $basePath . '/' . $path_parts['dirname'] ) ) { - $sub_dirs = explode(DIRECTORY_SEPARATOR, $basePath . '/' . $path_parts['dirname']); + $sub_dirs = explode( DIRECTORY_SEPARATOR, $basePath . '/' . $path_parts['dirname'] ); $dir = ''; - foreach ($sub_dirs as $sub_dir) { + foreach ( $sub_dirs as $sub_dir ) { $dir .= '/' . $sub_dir; - if (!$view->is_dir($dir)) { - $view->mkdir($dir); + if ( !$view->is_dir( $dir ) ) { + $view->mkdir( $dir ); } } } diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index cc9d239b256..eaaeae9b619 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -48,13 +48,12 @@ class Proxy extends \OC_FileProxy * * Tests if server side encryption is enabled, and file is allowed by blacklists */ - private static function shouldEncrypt($path) - { + private static function shouldEncrypt( $path ) { - if (is_null(self::$enableEncryption)) { + if ( is_null( self::$enableEncryption ) ) { if ( - \OCP\Config::getAppValue('files_encryption', 'enable_encryption', 'true') == 'true' + \OCP\Config::getAppValue( 'files_encryption', 'enable_encryption', 'true' ) == 'true' && Crypt::mode() == 'server' ) { @@ -68,27 +67,27 @@ class Proxy extends \OC_FileProxy } - if (!self::$enableEncryption) { + if ( !self::$enableEncryption ) { return false; } - if (is_null(self::$blackList)) { + if ( is_null( self::$blackList ) ) { - self::$blackList = explode(',', \OCP\Config::getAppValue('files_encryption', 'type_blacklist', '')); + self::$blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) ); } - if (Crypt::isCatfileContent($path)) { + if ( Crypt::isCatfileContent( $path ) ) { return true; } - $extension = substr($path, strrpos($path, '.') + 1); + $extension = substr( $path, strrpos( $path, '.' ) + 1 ); - if (array_search($extension, self::$blackList) === false) { + if ( array_search( $extension, self::$blackList ) === false ) { return true; @@ -102,35 +101,34 @@ class Proxy extends \OC_FileProxy * @param $data * @return bool */ - public function preFile_put_contents($path, &$data) - { + public function preFile_put_contents( $path, &$data ) { - if (self::shouldEncrypt($path)) { + if ( self::shouldEncrypt( $path ) ) { // Stream put contents should have been converted to fopen - if (!is_resource($data)) { + if ( !is_resource( $data ) ) { $userId = \OCP\USER::getUser(); - $view = new \OC_FilesystemView('/'); - $util = new Util($view, $userId); - $session = new Session($view); + $view = new \OC_FilesystemView( '/' ); + $util = new Util( $view, $userId ); + $session = new Session( $view ); $privateKey = $session->getPrivateKey(); - $filePath = $util->stripUserFilesPath($path); + $filePath = $util->stripUserFilesPath( $path ); // Set the filesize for userland, before encrypting - $size = strlen($data); + $size = strlen( $data ); // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; // Check if there is an existing key we can reuse - if ($encKeyfile = Keymanager::getFileKey($view, $userId, $filePath)) { + if ( $encKeyfile = Keymanager::getFileKey( $view, $userId, $filePath ) ) { // Fetch shareKey - $shareKey = Keymanager::getShareKey($view, $userId, $filePath); + $shareKey = Keymanager::getShareKey( $view, $userId, $filePath ); // Decrypt the keyfile - $plainKey = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + $plainKey = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); } else { @@ -140,37 +138,37 @@ class Proxy extends \OC_FileProxy } // Encrypt data - $encData = Crypt::symmetricEncryptFileContent($data, $plainKey); + $encData = Crypt::symmetricEncryptFileContent( $data, $plainKey ); $sharingEnabled = \OCP\Share::isEnabled(); // if file exists try to get sharing users - if ($view->file_exists($path)) { - $uniqueUserIds = $util->getSharingUsersArray($sharingEnabled, $filePath, $userId); + if ( $view->file_exists( $path ) ) { + $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $filePath, $userId ); } else { $uniqueUserIds[] = $userId; } // Fetch public keys for all users who will share the file - $publicKeys = Keymanager::getPublicKeys($view, $uniqueUserIds); + $publicKeys = Keymanager::getPublicKeys( $view, $uniqueUserIds ); // Encrypt plain keyfile to multiple sharefiles - $multiEncrypted = Crypt::multiKeyEncrypt($plainKey, $publicKeys); + $multiEncrypted = Crypt::multiKeyEncrypt( $plainKey, $publicKeys ); // Save sharekeys to user folders - Keymanager::setShareKeys($view, $filePath, $multiEncrypted['keys']); + Keymanager::setShareKeys( $view, $filePath, $multiEncrypted['keys'] ); // Set encrypted keyfile as common varname $encKey = $multiEncrypted['data']; // Save keyfile for newly encrypted file in parallel directory tree - Keymanager::setFileKey($view, $filePath, $userId, $encKey); + Keymanager::setFileKey( $view, $filePath, $userId, $encKey ); // Replace plain content with encrypted content by reference $data = $encData; // Update the file cache with file info - \OC\Files\Filesystem::putFileInfo($filePath, array('encrypted' => true, 'size' => strlen($data), 'unencrypted_size' => $size), ''); + \OC\Files\Filesystem::putFileInfo( $filePath, array( 'encrypted' => true, 'size' => strlen( $data ), 'unencrypted_size' => $size ), '' ); // Re-enable proxy - our work is done \OC_FileProxy::$enabled = $proxyStatus; @@ -186,52 +184,51 @@ class Proxy extends \OC_FileProxy * @param string $path Path of file from which has been read * @param string $data Data that has been read from file */ - public function postFile_get_contents($path, $data) - { + public function postFile_get_contents( $path, $data ) { $userId = \OCP\USER::getUser(); - $view = new \OC_FilesystemView('/'); - $util = new Util($view, $userId); + $view = new \OC_FilesystemView( '/' ); + $util = new Util( $view, $userId ); - $relPath = $util->stripUserFilesPath($path); + $relPath = $util->stripUserFilesPath( $path ); // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; // init session - $session = new Session($view); + $session = new Session( $view ); // If data is a catfile if ( Crypt::mode() == 'server' - && Crypt::isCatfileContent($data) + && Crypt::isCatfileContent( $data ) ) { - $privateKey = $session->getPrivateKey($userId); + $privateKey = $session->getPrivateKey( $userId ); // Get the encrypted keyfile - $encKeyfile = Keymanager::getFileKey($view, $userId, $relPath); + $encKeyfile = Keymanager::getFileKey( $view, $userId, $relPath ); // Attempt to fetch the user's shareKey - $shareKey = Keymanager::getShareKey($view, $userId, $relPath); + $shareKey = Keymanager::getShareKey( $view, $userId, $relPath ); // Decrypt keyfile with shareKey - $plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); - $plainData = Crypt::symmetricDecryptFileContent($data, $plainKeyfile); + $plainData = Crypt::symmetricDecryptFileContent( $data, $plainKeyfile ); } elseif ( Crypt::mode() == 'server' - && isset($_SESSION['legacyenckey']) - && Crypt::isEncryptedMeta($path) + && isset( $_SESSION['legacyenckey'] ) + && Crypt::isEncryptedMeta( $path ) ) { - $plainData = Crypt::legacyDecrypt($data, $session->getLegacyKey()); + $plainData = Crypt::legacyDecrypt( $data, $session->getLegacyKey() ); } \OC_FileProxy::$enabled = $proxyStatus; - if (!isset($plainData)) { + if ( !isset( $plainData ) ) { $plainData = $data; @@ -244,11 +241,10 @@ class Proxy extends \OC_FileProxy /** * @brief When a file is deleted, remove its keyfile also */ - public function preUnlink($path) - { + public function preUnlink( $path ) { // let the trashbin handle this - if (\OCP\App::isEnabled('files_trashbin')) { + if ( \OCP\App::isEnabled( 'files_trashbin' ) ) { return true; } @@ -256,29 +252,24 @@ class Proxy extends \OC_FileProxy $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $view = new \OC_FilesystemView('/'); + $view = new \OC_FilesystemView( '/' ); $userId = \OCP\USER::getUser(); - $util = new Util($view, $userId); + $util = new Util( $view, $userId ); // Format path to be relative to user files dir - $relPath = $util->stripUserFilesPath($path); + $relPath = $util->stripUserFilesPath( $path ); - list($owner, $ownerPath) = $util->getUidAndFilename($relPath); + list( $owner, $ownerPath ) = $util->getUidAndFilename( $relPath ); // Delete keyfile & shareKey so it isn't orphaned - if ( - !( - Keymanager::deleteFileKey($view, $owner, $ownerPath) - && Keymanager::delAllShareKeys($view, $owner, $ownerPath) - ) - ) { - - \OC_Log::write('Encryption library', 'Keyfile or shareKey could not be deleted for file "' . $ownerPath . '"', \OC_Log::ERROR); - + if ( !Keymanager::deleteFileKey( $view, $owner, $ownerPath ) ) { + \OC_Log::write( 'Encryption library', 'Keyfile or shareKey could not be deleted for file "' . $ownerPath . '"', \OC_Log::ERROR ); } + Keymanager::delAllShareKeys( $view, $owner, $ownerPath ); + \OC_FileProxy::$enabled = $proxyStatus; // If we don't return true then file delete will fail; better @@ -291,9 +282,8 @@ class Proxy extends \OC_FileProxy * @param $path * @return bool */ - public function postTouch($path) - { - $this->handleFile($path); + public function postTouch( $path ) { + $this->handleFile( $path ); return true; } @@ -303,21 +293,20 @@ class Proxy extends \OC_FileProxy * @param $result * @return resource */ - public function postFopen($path, &$result) - { + public function postFopen( $path, &$result ) { - if (!$result) { + if ( !$result ) { return $result; } // Reformat path for use with OC_FSV - $path_split = explode('/', $path); - $path_f = implode('/', array_slice($path_split, 3)); + $path_split = explode( '/', $path ); + $path_f = implode( '/', array_slice( $path_split, 3 ) ); // FIXME: handling for /userId/cache used by webdav for chunking. The cache chunks are NOT encrypted - if ($path_split[2] == 'cache') { + if ( count($path_split) >= 2 && $path_split[2] == 'cache' ) { return $result; } @@ -325,31 +314,31 @@ class Proxy extends \OC_FileProxy $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $meta = stream_get_meta_data($result); + $meta = stream_get_meta_data( $result ); - $view = new \OC_FilesystemView(''); + $view = new \OC_FilesystemView( '' ); - $util = new Util($view, \OCP\USER::getUser()); + $util = new Util( $view, \OCP\USER::getUser() ); // If file is already encrypted, decrypt using crypto protocol if ( Crypt::mode() == 'server' - && $util->isEncryptedPath($path) + && $util->isEncryptedPath( $path ) ) { // Close the original encrypted file - fclose($result); + fclose( $result ); // Open the file using the crypto stream wrapper // protocol and let it do the decryption work instead - $result = fopen('crypt://' . $path_f, $meta['mode']); + $result = fopen( 'crypt://' . $path_f, $meta['mode'] ); } elseif ( - self::shouldEncrypt($path) + self::shouldEncrypt( $path ) and $meta ['mode'] != 'r' and $meta['mode'] != 'rb' ) { - $result = fopen('crypt://' . $path_f, $meta['mode']); + $result = fopen( 'crypt://' . $path_f, $meta['mode'] ); } // Re-enable the proxy @@ -364,18 +353,17 @@ class Proxy extends \OC_FileProxy * @param $data * @return array */ - public function postGetFileInfo($path, $data) - { + public function postGetFileInfo( $path, $data ) { // if path is a folder do nothing - if (is_array($data) && array_key_exists('size', $data)) { + if ( is_array( $data ) && array_key_exists( 'size', $data ) ) { // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; // get file size - $data['size'] = self::postFileSize($path, $data['size']); + $data['size'] = self::postFileSize( $path, $data['size'] ); // Re-enable the proxy \OC_FileProxy::$enabled = $proxyStatus; @@ -389,52 +377,51 @@ class Proxy extends \OC_FileProxy * @param $size * @return bool */ - public function postFileSize($path, $size) - { + public function postFileSize( $path, $size ) { - $view = new \OC_FilesystemView('/'); + $view = new \OC_FilesystemView( '/' ); // if path is a folder do nothing - if ($view->is_dir($path)) { + if ( $view->is_dir( $path ) ) { return $size; } // Reformat path for use with OC_FSV - $path_split = explode('/', $path); - $path_f = implode('/', array_slice($path_split, 3)); + $path_split = explode( '/', $path ); + $path_f = implode( '/', array_slice( $path_split, 3 ) ); // if path is empty we cannot resolve anything - if (empty($path_f)) { + if ( empty( $path_f ) ) { return $size; } $fileInfo = false; // get file info from database/cache if not .part file - if(!Keymanager::isPartialFilePath($path)) { - $fileInfo = $view->getFileInfo($path); + if ( !Keymanager::isPartialFilePath( $path ) ) { + $fileInfo = $view->getFileInfo( $path ); } // if file is encrypted return real file size - if (is_array($fileInfo) && $fileInfo['encrypted'] === true) { + if ( is_array( $fileInfo ) && $fileInfo['encrypted'] === true ) { $size = $fileInfo['unencrypted_size']; } else { // self healing if file was removed from file cache - if (!is_array($fileInfo)) { + if ( !is_array( $fileInfo ) ) { $fileInfo = array(); } $userId = \OCP\User::getUser(); - $util = new Util($view, $userId); - $fixSize = $util->getFileSize($path); - if ($fixSize > 0) { + $util = new Util( $view, $userId ); + $fixSize = $util->getFileSize( $path ); + if ( $fixSize > 0 ) { $size = $fixSize; $fileInfo['encrypted'] = true; $fileInfo['unencrypted_size'] = $size; // put file info if not .part file - if(!Keymanager::isPartialFilePath($path_f)) { - $view->putFileInfo($path, $fileInfo); + if ( !Keymanager::isPartialFilePath( $path_f ) ) { + $view->putFileInfo( $path, $fileInfo ); } } @@ -445,33 +432,32 @@ class Proxy extends \OC_FileProxy /** * @param $path */ - public function handleFile($path) - { + public function handleFile( $path ) { // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $view = new \OC_FilesystemView('/'); - $session = new Session($view); + $view = new \OC_FilesystemView( '/' ); + $session = new Session( $view ); $userId = \OCP\User::getUser(); - $util = new Util($view, $userId); + $util = new Util( $view, $userId ); // Reformat path for use with OC_FSV - $path_split = explode('/', $path); - $path_f = implode('/', array_slice($path_split, 3)); + $path_split = explode( '/', $path ); + $path_f = implode( '/', array_slice( $path_split, 3 ) ); // only if file is on 'files' folder fix file size and sharing - if ($path_split[2] == 'files' && $util->fixFileSize($path)) { + if ( count($path_split) >= 2 && $path_split[2] == 'files' && $util->fixFileSize( $path ) ) { // get sharing app state $sharingEnabled = \OCP\Share::isEnabled(); // get users - $usersSharing = $util->getSharingUsersArray($sharingEnabled, $path_f); + $usersSharing = $util->getSharingUsersArray( $sharingEnabled, $path_f ); // update sharing-keys - $util->setSharedFileKeyfiles($session, $usersSharing, $path_f); + $util->setSharedFileKeyfiles( $session, $usersSharing, $path_f ); } \OC_FileProxy::$enabled = $proxyStatus; diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index 86f56e56766..2ddad0a15da 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -37,27 +37,26 @@ class Session * * @note The ownCloud key pair is used to allow public link sharing even if encryption is enabled */ - public function __construct($view) - { + public function __construct( $view ) { $this->view = $view; - if (!$this->view->is_dir('owncloud_private_key')) { + if ( !$this->view->is_dir( 'owncloud_private_key' ) ) { - $this->view->mkdir('owncloud_private_key'); + $this->view->mkdir( 'owncloud_private_key' ); } - $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); + $publicShareKeyId = \OC_Appconfig::getValue( 'files_encryption', 'publicShareKeyId' ); - if ($publicShareKeyId === null) { - $publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8); - \OC_Appconfig::setValue('files_encryption', 'publicShareKeyId', $publicShareKeyId); + if ( $publicShareKeyId === null ) { + $publicShareKeyId = 'pubShare_' . substr( md5( time() ), 0, 8 ); + \OC_Appconfig::setValue( 'files_encryption', 'publicShareKeyId', $publicShareKeyId ); } if ( - !$this->view->file_exists("/public-keys/" . $publicShareKeyId . ".public.key") - || !$this->view->file_exists("/owncloud_private_key/" . $publicShareKeyId . ".private.key") + !$this->view->file_exists( "/public-keys/" . $publicShareKeyId . ".public.key" ) + || !$this->view->file_exists( "/owncloud_private_key/" . $publicShareKeyId . ".private.key" ) ) { $keypair = Crypt::createKeypair(); @@ -68,32 +67,33 @@ class Session // Save public key - if (!$view->is_dir('/public-keys')) { - $view->mkdir('/public-keys'); + if ( !$view->is_dir( '/public-keys' ) ) { + $view->mkdir( '/public-keys' ); } - $this->view->file_put_contents('/public-keys/' . $publicShareKeyId . '.public.key', $keypair['publicKey']); + $this->view->file_put_contents( '/public-keys/' . $publicShareKeyId . '.public.key', $keypair['publicKey'] ); - // Encrypt private key empthy passphrase - $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], ''); + // Encrypt private key empty passphrase + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], '' ); // Save private key - $this->view->file_put_contents('/owncloud_private_key/' . $publicShareKeyId . '.private.key', $encryptedPrivateKey); + $this->view->file_put_contents( '/owncloud_private_key/' . $publicShareKeyId . '.private.key', $encryptedPrivateKey ); \OC_FileProxy::$enabled = $proxyStatus; } - if (\OCP\USER::getUser() === false || - (isset($_GET['service']) && $_GET['service'] == 'files' && - isset($_GET['t']))) { + if ( \OCP\USER::getUser() === false || + ( isset( $_GET['service'] ) && $_GET['service'] == 'files' && + isset( $_GET['t'] ) ) + ) { // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $encryptedKey = $this->view->file_get_contents('/owncloud_private_key/' . $publicShareKeyId . '.private.key'); - $privateKey = Crypt::symmetricDecryptFileContent($encryptedKey, ''); - $this->setPrivateKey($privateKey); + $encryptedKey = $this->view->file_get_contents( '/owncloud_private_key/' . $publicShareKeyId . '.private.key' ); + $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, '' ); + $this->setPrivateKey( $privateKey ); \OC_FileProxy::$enabled = $proxyStatus; } @@ -104,8 +104,7 @@ class Session * @param string $privateKey * @return bool */ - public function setPrivateKey($privateKey) - { + public function setPrivateKey( $privateKey ) { $_SESSION['privateKey'] = $privateKey; @@ -118,12 +117,11 @@ class Session * @returns string $privateKey The user's plaintext private key * */ - public function getPrivateKey() - { + public function getPrivateKey() { if ( - isset($_SESSION['privateKey']) - && !empty($_SESSION['privateKey']) + isset( $_SESSION['privateKey'] ) + && !empty( $_SESSION['privateKey'] ) ) { return $_SESSION['privateKey']; @@ -141,8 +139,7 @@ class Session * @param $legacyKey * @return bool */ - public function setLegacyKey($legacyKey) - { + public function setLegacyKey( $legacyKey ) { $_SESSION['legacyKey'] = $legacyKey; @@ -154,12 +151,11 @@ class Session * @returns string $legacyKey The user's plaintext legacy key * */ - public function getLegacyKey() - { + public function getLegacyKey() { if ( - isset($_SESSION['legacyKey']) - && !empty($_SESSION['legacyKey']) + isset( $_SESSION['legacyKey'] ) + && !empty( $_SESSION['legacyKey'] ) ) { return $_SESSION['legacyKey']; diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index b143b62827f..fa9df02f085 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -77,19 +77,18 @@ class Stream * @param $opened_path * @return bool */ - public function stream_open($path, $mode, $options, &$opened_path) - { + public function stream_open( $path, $mode, $options, &$opened_path ) { - if (!isset($this->rootView)) { - $this->rootView = new \OC_FilesystemView('/'); + if ( !isset( $this->rootView ) ) { + $this->rootView = new \OC_FilesystemView( '/' ); } - $util = new Util($this->rootView, \OCP\USER::getUser()); + $util = new Util( $this->rootView, \OCP\USER::getUser() ); $this->userId = $util->getUserId(); // Strip identifier text from path, this gives us the path relative to data//files - $this->relPath = \OC\Files\Filesystem::normalizePath(str_replace('crypt://', '', $path)); + $this->relPath = \OC\Files\Filesystem::normalizePath( str_replace( 'crypt://', '', $path ) ); // rawPath is relative to the data directory $this->rawPath = $util->getUserFilesDir() . $this->relPath; @@ -111,26 +110,25 @@ class Stream } else { - $this->size = $this->rootView->filesize($this->rawPath, $mode); + $this->size = $this->rootView->filesize( $this->rawPath, $mode ); } - $this->handle = $this->rootView->fopen($this->rawPath, $mode); + $this->handle = $this->rootView->fopen( $this->rawPath, $mode ); \OC_FileProxy::$enabled = $proxyStatus; - if (!is_resource($this->handle)) { + if ( !is_resource( $this->handle ) ) { - \OCP\Util::writeLog('files_encryption', 'failed to open file "' . $this->rawPath . '"', \OCP\Util::ERROR); + \OCP\Util::writeLog( 'files_encryption', 'failed to open file "' . $this->rawPath . '"', \OCP\Util::ERROR ); } else { - $this->meta = stream_get_meta_data($this->handle); + $this->meta = stream_get_meta_data( $this->handle ); } - - return is_resource($this->handle); + return is_resource( $this->handle ); } @@ -138,12 +136,11 @@ class Stream * @param $offset * @param int $whence */ - public function stream_seek($offset, $whence = SEEK_SET) - { + public function stream_seek( $offset, $whence = SEEK_SET ) { $this->flush(); - fseek($this->handle, $offset, $whence); + fseek( $this->handle, $offset, $whence ); } @@ -152,37 +149,36 @@ class Stream * @return bool|string * @throws \Exception */ - public function stream_read($count) - { + public function stream_read( $count ) { $this->writeCache = ''; - if ($count != 8192) { + if ( $count != 8192 ) { // $count will always be 8192 https://bugs.php.net/bug.php?id=21641 // This makes this function a lot simpler, but will break this class if the above 'bug' gets 'fixed' - \OCP\Util::writeLog('files_encryption', 'PHP "bug" 21641 no longer holds, decryption system requires refactoring', \OCP\Util::FATAL); + \OCP\Util::writeLog( 'files_encryption', 'PHP "bug" 21641 no longer holds, decryption system requires refactoring', \OCP\Util::FATAL ); die(); } // Get the data from the file handle - $data = fread($this->handle, 8192); + $data = fread( $this->handle, 8192 ); $result = ''; - if (strlen($data)) { + if ( strlen( $data ) ) { - if (!$this->getKey()) { + if ( !$this->getKey() ) { // Error! We don't have a key to decrypt the file with - throw new \Exception('Encryption key not found for "' . $this->rawPath . '" during attempted read via stream'); + throw new \Exception( 'Encryption key not found for "' . $this->rawPath . '" during attempted read via stream' ); } // Decrypt data - $result = Crypt::symmetricDecryptFileContent($data, $this->plainKey); + $result = Crypt::symmetricDecryptFileContent( $data, $this->plainKey ); } @@ -196,11 +192,10 @@ class Stream * @param string $key key to use for encryption * @return string encrypted data on success, false on failure */ - public function preWriteEncrypt($plainData, $key) - { + public function preWriteEncrypt( $plainData, $key ) { // Encrypt data to 'catfile', which includes IV - if ($encrypted = Crypt::symmetricEncryptFileContent($plainData, $key)) { + if ( $encrypted = Crypt::symmetricEncryptFileContent( $plainData, $key ) ) { return $encrypted; @@ -217,11 +212,10 @@ class Stream * @internal param bool $generate if true, a new key will be generated if none can be found * @return bool true on key found and set, false on key not found and new key generated and set */ - public function getKey() - { + public function getKey() { // Check if key is already set - if (isset($this->plainKey) && isset($this->encKeyfile)) { + if ( isset( $this->plainKey ) && isset( $this->encKeyfile ) ) { return true; @@ -229,18 +223,18 @@ class Stream // Fetch and decrypt keyfile // Fetch existing keyfile - $this->encKeyfile = Keymanager::getFileKey($this->rootView, $this->userId, $this->relPath); + $this->encKeyfile = Keymanager::getFileKey( $this->rootView, $this->userId, $this->relPath ); // If a keyfile already exists - if ($this->encKeyfile) { + if ( $this->encKeyfile ) { - $session = new Session($this->rootView); + $session = new Session( $this->rootView ); - $privateKey = $session->getPrivateKey($this->userId); + $privateKey = $session->getPrivateKey( $this->userId ); - $shareKey = Keymanager::getShareKey($this->rootView, $this->userId, $this->relPath); + $shareKey = Keymanager::getShareKey( $this->rootView, $this->userId, $this->relPath ); - $this->plainKey = Crypt::multiKeyDecrypt($this->encKeyfile, $shareKey, $privateKey); + $this->plainKey = Crypt::multiKeyDecrypt( $this->encKeyfile, $shareKey, $privateKey ); return true; @@ -261,8 +255,7 @@ class Stream * @note Padding is added to each encrypted block to ensure that the resulting block is exactly 8192 bytes. This is removed during stream_read * @note PHP automatically updates the file pointer after writing data to reflect it's length. There is generally no need to update the poitner manually using fseek */ - public function stream_write($data) - { + public function stream_write( $data ) { // Disable the file proxies so that encryption is not // automatically attempted when the file is written to disk - @@ -272,16 +265,16 @@ class Stream \OC_FileProxy::$enabled = false; // Get the length of the unencrypted data that we are handling - $length = strlen($data); + $length = strlen( $data ); // Find out where we are up to in the writing of data to the // file - $pointer = ftell($this->handle); + $pointer = ftell( $this->handle ); // Get / generate the keyfile for the file we're handling // If we're writing a new file (not overwriting an existing // one), save the newly generated keyfile - if (!$this->getKey()) { + if ( !$this->getKey() ) { $this->plainKey = Crypt::generateKey(); @@ -289,27 +282,27 @@ class Stream // If extra data is left over from the last round, make sure it // is integrated into the next 6126 / 8192 block - if ($this->writeCache) { + if ( $this->writeCache ) { // Concat writeCache to start of $data $data = $this->writeCache . $data; - // Clear the write cache, ready for resuse - it has been + // Clear the write cache, ready for reuse - it has been // flushed and its old contents processed $this->writeCache = ''; } - // While there still remains somed data to be processed & written - while (strlen($data) > 0) { + // While there still remains some data to be processed & written + while ( strlen( $data ) > 0 ) { - // Remaining length for this iteration, not of the + // Remaining length for this iteration, not of the // entire file (may be greater than 8192 bytes) - $remainingLength = strlen($data); + $remainingLength = strlen( $data ); - // If data remaining to be written is less than the + // If data remaining to be written is less than the // size of 1 6126 byte block - if ($remainingLength < 6126) { + if ( $remainingLength < 6126 ) { // Set writeCache to contents of $data // The writeCache will be carried over to the @@ -327,25 +320,25 @@ class Stream } else { // Read the chunk from the start of $data - $chunk = substr($data, 0, 6126); + $chunk = substr( $data, 0, 6126 ); - $encrypted = $this->preWriteEncrypt($chunk, $this->plainKey); + $encrypted = $this->preWriteEncrypt( $chunk, $this->plainKey ); // Write the data chunk to disk. This will be // attended to the last data chunk if the file // being handled totals more than 6126 bytes - fwrite($this->handle, $encrypted); + fwrite( $this->handle, $encrypted ); // Remove the chunk we just processed from // $data, leaving only unprocessed data in $data // var, for handling on the next round - $data = substr($data, 6126); + $data = substr( $data, 6126 ); } } - $this->size = max($this->size, $pointer + $length); + $this->size = max( $this->size, $pointer + $length ); $this->unencryptedSize += $length; \OC_FileProxy::$enabled = $proxyStatus; @@ -360,18 +353,17 @@ class Stream * @param $arg1 * @param $arg2 */ - public function stream_set_option($option, $arg1, $arg2) - { + public function stream_set_option( $option, $arg1, $arg2 ) { $return = false; - switch ($option) { + switch ( $option ) { case STREAM_OPTION_BLOCKING: - $return = stream_set_blocking($this->handle, $arg1); + $return = stream_set_blocking( $this->handle, $arg1 ); break; case STREAM_OPTION_READ_TIMEOUT: - $return = stream_set_timeout($this->handle, $arg1, $arg2); + $return = stream_set_timeout( $this->handle, $arg1, $arg2 ); break; case STREAM_OPTION_WRITE_BUFFER: - $return = stream_set_write_buffer($this->handle, $arg1); + $return = stream_set_write_buffer( $this->handle, $arg1 ); } return $return; @@ -380,26 +372,23 @@ class Stream /** * @return array */ - public function stream_stat() - { - return fstat($this->handle); + public function stream_stat() { + return fstat( $this->handle ); } /** * @param $mode */ - public function stream_lock($mode) - { - return flock($this->handle, $mode); + public function stream_lock( $mode ) { + return flock( $this->handle, $mode ); } /** * @return bool */ - public function stream_flush() - { + public function stream_flush() { - return fflush($this->handle); + return fflush( $this->handle ); // Not a typo: http://php.net/manual/en/function.fflush.php } @@ -407,22 +396,20 @@ class Stream /** * @return bool */ - public function stream_eof() - { - return feof($this->handle); + public function stream_eof() { + return feof( $this->handle ); } - private function flush() - { + private function flush() { - if ($this->writeCache) { + if ( $this->writeCache ) { // Set keyfile property for file in question $this->getKey(); - $encrypted = $this->preWriteEncrypt($this->writeCache, $this->plainKey); + $encrypted = $this->preWriteEncrypt( $this->writeCache, $this->plainKey ); - fwrite($this->handle, $encrypted); + fwrite( $this->handle, $encrypted ); $this->writeCache = ''; @@ -433,8 +420,7 @@ class Stream /** * @return bool */ - public function stream_close() - { + public function stream_close() { $this->flush(); @@ -448,33 +434,33 @@ class Stream \OC_FileProxy::$enabled = false; // Fetch user's public key - $this->publicKey = Keymanager::getPublicKey($this->rootView, $this->userId); + $this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId ); // Check if OC sharing api is enabled $sharingEnabled = \OCP\Share::isEnabled(); - $util = new Util($this->rootView, $this->userId); + $util = new Util( $this->rootView, $this->userId ); // Get all users sharing the file includes current user - $uniqueUserIds = $util->getSharingUsersArray($sharingEnabled, $this->relPath, $this->userId); + $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $this->relPath, $this->userId ); // Fetch public keys for all sharing users - $publicKeys = Keymanager::getPublicKeys($this->rootView, $uniqueUserIds); + $publicKeys = Keymanager::getPublicKeys( $this->rootView, $uniqueUserIds ); // Encrypt enc key for all sharing users - $this->encKeyfiles = Crypt::multiKeyEncrypt($this->plainKey, $publicKeys); + $this->encKeyfiles = Crypt::multiKeyEncrypt( $this->plainKey, $publicKeys ); - $view = new \OC_FilesystemView('/'); + $view = new \OC_FilesystemView( '/' ); // Save the new encrypted file key - Keymanager::setFileKey($this->rootView, $this->relPath, $this->userId, $this->encKeyfiles['data']); + Keymanager::setFileKey( $this->rootView, $this->relPath, $this->userId, $this->encKeyfiles['data'] ); // Save the sharekeys - Keymanager::setShareKeys($view, $this->relPath, $this->encKeyfiles['keys']); + Keymanager::setShareKeys( $view, $this->relPath, $this->encKeyfiles['keys'] ); // get file info - $fileInfo = $view->getFileInfo($this->rawPath); - if (!is_array($fileInfo)) { + $fileInfo = $view->getFileInfo( $this->rawPath ); + if ( !is_array( $fileInfo ) ) { $fileInfo = array(); } @@ -487,10 +473,10 @@ class Stream $fileInfo['unencrypted_size'] = $this->unencryptedSize; // set fileinfo - $view->putFileInfo($this->rawPath, $fileInfo); + $view->putFileInfo( $this->rawPath, $fileInfo ); } - return fclose($this->handle); + return fclose( $this->handle ); } diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index d42fe9953b5..2980aa94e0c 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -117,25 +117,25 @@ class Util * @param $userId * @param bool $client */ - public function __construct(\OC_FilesystemView $view, $userId, $client = false) - { + public function __construct( \OC_FilesystemView $view, $userId, $client = false ) { $this->view = $view; $this->userId = $userId; $this->client = $client; $this->isPublic = false; - $this->publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); - $this->recoveryKeyId = \OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); + $this->publicShareKeyId = \OC_Appconfig::getValue( 'files_encryption', 'publicShareKeyId' ); + $this->recoveryKeyId = \OC_Appconfig::getValue( 'files_encryption', 'recoveryKeyId' ); // if we are anonymous/public - if ($this->userId === false || - (isset($_GET['service']) && $_GET['service'] == 'files' && - isset($_GET['t']))) { + if ( $this->userId === false || + ( isset( $_GET['service'] ) && $_GET['service'] == 'files' && + isset( $_GET['t'] ) ) + ) { $this->userId = $this->publicShareKeyId; // only handle for files_sharing app - if ($GLOBALS['app'] === 'files_sharing') { + if ( $GLOBALS['app'] === 'files_sharing' ) { $this->userDir = '/' . $GLOBALS['fileOwner']; $this->fileFolderName = 'files'; $this->userFilesDir = '/' . $GLOBALS['fileOwner'] . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable? @@ -164,15 +164,14 @@ class Util /** * @return bool */ - public function ready() - { + public function ready() { if ( - !$this->view->file_exists($this->encryptionDir) - or !$this->view->file_exists($this->keyfilesPath) - or !$this->view->file_exists($this->shareKeysPath) - or !$this->view->file_exists($this->publicKeyPath) - or !$this->view->file_exists($this->privateKeyPath) + !$this->view->file_exists( $this->encryptionDir ) + or !$this->view->file_exists( $this->keyfilesPath ) + or !$this->view->file_exists( $this->shareKeysPath ) + or !$this->view->file_exists( $this->publicKeyPath ) + or !$this->view->file_exists( $this->privateKeyPath ) ) { return false; @@ -189,8 +188,7 @@ class Util * @brief Sets up user folders and keys for serverside encryption * @param string $passphrase passphrase to encrypt server-stored private key with */ - public function setupServerSide($passphrase = null) - { + public function setupServerSide( $passphrase = null ) { // Set directories to check / create $setUpDirs = array( @@ -203,11 +201,11 @@ class Util ); // Check / create all necessary dirs - foreach ($setUpDirs as $dirPath) { + foreach ( $setUpDirs as $dirPath ) { - if (!$this->view->file_exists($dirPath)) { + if ( !$this->view->file_exists( $dirPath ) ) { - $this->view->mkdir($dirPath); + $this->view->mkdir( $dirPath ); } @@ -216,8 +214,8 @@ class Util // Create user keypair // we should never override a keyfile if ( - !$this->view->file_exists($this->publicKeyPath) - && !$this->view->file_exists($this->privateKeyPath) + !$this->view->file_exists( $this->publicKeyPath ) + && !$this->view->file_exists( $this->privateKeyPath ) ) { // Generate keypair @@ -226,35 +224,35 @@ class Util \OC_FileProxy::$enabled = false; // Save public key - $this->view->file_put_contents($this->publicKeyPath, $keypair['publicKey']); + $this->view->file_put_contents( $this->publicKeyPath, $keypair['publicKey'] ); // Encrypt private key with user pwd as passphrase - $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $passphrase); + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], $passphrase ); // Save private key - $this->view->file_put_contents($this->privateKeyPath, $encryptedPrivateKey); + $this->view->file_put_contents( $this->privateKeyPath, $encryptedPrivateKey ); \OC_FileProxy::$enabled = true; } else { // check if public-key exists but private-key is missing - if($this->view->file_exists($this->publicKeyPath) && !$this->view->file_exists($this->privateKeyPath)) { - \OC_Log::write('Encryption library', 'public key exists but private key is missing for "' . $this->userId . '"', \OC_Log::FATAL); + if ( $this->view->file_exists( $this->publicKeyPath ) && !$this->view->file_exists( $this->privateKeyPath ) ) { + \OC_Log::write( 'Encryption library', 'public key exists but private key is missing for "' . $this->userId . '"', \OC_Log::FATAL ); return false; - } else if(!$this->view->file_exists($this->publicKeyPath) && $this->view->file_exists($this->privateKeyPath)) { - \OC_Log::write('Encryption library', 'private key exists but public key is missing for "' . $this->userId . '"', \OC_Log::FATAL); + } else if ( !$this->view->file_exists( $this->publicKeyPath ) && $this->view->file_exists( $this->privateKeyPath ) ) { + \OC_Log::write( 'Encryption library', 'private key exists but public key is missing for "' . $this->userId . '"', \OC_Log::FATAL ); return false; } } // If there's no record for this user's encryption preferences - if (false === $this->recoveryEnabledForUser()) { + if ( false === $this->recoveryEnabledForUser() ) { // create database configuration $sql = 'INSERT INTO `*PREFIX*encryption` (`uid`,`mode`,`recovery_enabled`) VALUES (?,?,?)'; - $args = array($this->userId, 'server-side', 0); - $query = \OCP\DB::prepare($sql); - $query->execute($args); + $args = array( $this->userId, 'server-side', 0 ); + $query = \OCP\DB::prepare( $sql ); + $query->execute( $args ); } @@ -265,8 +263,7 @@ class Util /** * @return string */ - public function getPublicShareKeyId() - { + public function getPublicShareKeyId() { return $this->publicShareKeyId; } @@ -277,8 +274,7 @@ class Util * @note If records are not being returned, check for a hidden space * at the start of the uid in db */ - public function recoveryEnabledForUser() - { + public function recoveryEnabledForUser() { $sql = 'SELECT recovery_enabled @@ -287,22 +283,22 @@ class Util WHERE uid = ?'; - $args = array($this->userId); + $args = array( $this->userId ); - $query = \OCP\DB::prepare($sql); + $query = \OCP\DB::prepare( $sql ); - $result = $query->execute($args); + $result = $query->execute( $args ); $recoveryEnabled = array(); - while ($row = $result->fetchRow()) { + while ( $row = $result->fetchRow() ) { $recoveryEnabled[] = $row['recovery_enabled']; } // If no record is found - if (empty($recoveryEnabled)) { + if ( empty( $recoveryEnabled ) ) { return false; @@ -320,19 +316,18 @@ class Util * @param bool $enabled Whether to enable or disable recovery * @return bool */ - public function setRecoveryForUser($enabled) - { + public function setRecoveryForUser( $enabled ) { $recoveryStatus = $this->recoveryEnabledForUser(); // If a record for this user already exists, update it - if (false === $recoveryStatus) { + if ( false === $recoveryStatus ) { $sql = 'INSERT INTO `*PREFIX*encryption` (`uid`,`mode`,`recovery_enabled`) VALUES (?,?,?)'; - $args = array($this->userId, 'server-side', $enabled); + $args = array( $this->userId, 'server-side', $enabled ); // Create a new record instead } else { @@ -344,13 +339,13 @@ class Util WHERE uid = ?'; - $args = array($enabled, $this->userId); + $args = array( $enabled, $this->userId ); } - $query = \OCP\DB::prepare($sql); + $query = \OCP\DB::prepare( $sql ); - if ($query->execute($args)) { + if ( $query->execute( $args ) ) { return true; @@ -369,47 +364,46 @@ class Util * @note $directory needs to be a path relative to OC data dir. e.g. * /admin/files NOT /backup OR /home/www/oc/data/admin/files */ - public function findEncFiles($directory, &$found = false) - { + public function findEncFiles( $directory, &$found = false ) { // Disable proxy - we don't want files to be decrypted before // we handle them \OC_FileProxy::$enabled = false; - if($found == false) { - $found = array('plain' => array(), 'encrypted' => array(), 'legacy' => array()); + if ( $found == false ) { + $found = array( 'plain' => array(), 'encrypted' => array(), 'legacy' => array() ); } if ( - $this->view->is_dir($directory) - && $handle = $this->view->opendir($directory) + $this->view->is_dir( $directory ) + && $handle = $this->view->opendir( $directory ) ) { - while (false !== ($file = readdir($handle))) { + while ( false !== ( $file = readdir( $handle ) ) ) { if ( $file != "." && $file != ".." ) { - $filePath = $directory . '/' . $this->view->getRelativePath('/' . $file); - $relPath = $this->stripUserFilesPath($filePath); + $filePath = $directory . '/' . $this->view->getRelativePath( '/' . $file ); + $relPath = $this->stripUserFilesPath( $filePath ); // If the path is a directory, search // its contents - if ($this->view->is_dir($filePath)) { + if ( $this->view->is_dir( $filePath ) ) { - $this->findEncFiles($filePath, $found); + $this->findEncFiles( $filePath, $found ); // If the path is a file, determine // its encryption status - } elseif ($this->view->is_file($filePath)) { + } elseif ( $this->view->is_file( $filePath ) ) { // Disable proxies again, some- // where they got re-enabled :/ \OC_FileProxy::$enabled = false; - $data = $this->view->file_get_contents($filePath); + $data = $this->view->file_get_contents( $filePath ); // If the file is encrypted // NOTE: If the userId is @@ -419,22 +413,22 @@ class Util // scanning every file like this // will eat server resources :( if ( - Keymanager::getFileKey($this->view, $this->userId, $relPath) - && Crypt::isCatfileContent($data) + Keymanager::getFileKey( $this->view, $this->userId, $relPath ) + && Crypt::isCatfileContent( $data ) ) { - $found['encrypted'][] = array('name' => $file, 'path' => $filePath); + $found['encrypted'][] = array( 'name' => $file, 'path' => $filePath ); // If the file uses old // encryption system - } elseif (Crypt::isLegacyEncryptedContent($this->tail($filePath, 3), $relPath)) { + } elseif ( Crypt::isLegacyEncryptedContent( $this->tail( $filePath, 3 ), $relPath ) ) { - $found['legacy'][] = array('name' => $file, 'path' => $filePath); + $found['legacy'][] = array( 'name' => $file, 'path' => $filePath ); // If the file is not encrypted } else { - $found['plain'][] = array('name' => $file, 'path' => $relPath); + $found['plain'][] = array( 'name' => $file, 'path' => $relPath ); } @@ -446,7 +440,7 @@ class Util \OC_FileProxy::$enabled = true; - if (empty($found)) { + if ( empty( $found ) ) { return false; @@ -469,39 +463,38 @@ class Util * @note Safe to use on large files; does not read entire file to memory * @note Derivative of http://tekkie.flashbit.net/php/tail-functionality-in-php */ - public function tail($filename, $numLines) - { + public function tail( $filename, $numLines ) { \OC_FileProxy::$enabled = false; $text = ''; $pos = -1; - $handle = $this->view->fopen($filename, 'r'); + $handle = $this->view->fopen( $filename, 'r' ); - while ($numLines > 0) { + while ( $numLines > 0 ) { --$pos; - if (fseek($handle, $pos, SEEK_END) !== 0) { + if ( fseek( $handle, $pos, SEEK_END ) !== 0 ) { - rewind($handle); + rewind( $handle ); $numLines = 0; - } elseif (fgetc($handle) === "\n") { + } elseif ( fgetc( $handle ) === "\n" ) { --$numLines; } - $block_size = (-$pos) % 8192; - if ($block_size === 0 || $numLines === 0) { + $block_size = ( -$pos ) % 8192; + if ( $block_size === 0 || $numLines === 0 ) { - $text = fread($handle, ($block_size === 0 ? 8192 : $block_size)) . $text; + $text = fread( $handle, ( $block_size === 0 ? 8192 : $block_size ) ) . $text; } } - fclose($handle); + fclose( $handle ); \OC_FileProxy::$enabled = true; @@ -513,8 +506,7 @@ class Util * @param $path * @return boolean */ - public function isEncryptedPath($path) - { + public function isEncryptedPath( $path ) { // Disable encryption proxy so data retrieved is in its // original form @@ -523,15 +515,15 @@ class Util // we only need 24 byte from the last chunk $data = ''; - $handle = $this->view->fopen($path, 'r'); - if (!fseek($handle, -24, SEEK_END)) { - $data = fgets($handle); + $handle = $this->view->fopen( $path, 'r' ); + if ( !fseek( $handle, -24, SEEK_END ) ) { + $data = fgets( $handle ); } // re-enable proxy \OC_FileProxy::$enabled = $proxyStatus; - return Crypt::isCatfileContent($data); + return Crypt::isCatfileContent( $data ); } @@ -540,8 +532,7 @@ class Util * @param string $path absolute path * @return bool */ - public function getFileSize($path) - { + public function getFileSize( $path ) { $result = 0; @@ -550,33 +541,33 @@ class Util \OC_FileProxy::$enabled = false; // Reformat path for use with OC_FSV - $pathSplit = explode('/', $path); - $pathRelative = implode('/', array_slice($pathSplit, 3)); + $pathSplit = explode( '/', $path ); + $pathRelative = implode( '/', array_slice( $pathSplit, 3 ) ); - if ($pathSplit[2] == 'files' && $this->view->file_exists($path) && $this->isEncryptedPath($path)) { + if ( $pathSplit[2] == 'files' && $this->view->file_exists( $path ) && $this->isEncryptedPath( $path ) ) { // get the size from filesystem - $fullPath = $this->view->getLocalFile($path); - $size = filesize($fullPath); + $fullPath = $this->view->getLocalFile( $path ); + $size = filesize( $fullPath ); // calculate last chunk nr - $lastChunckNr = floor($size / 8192); + $lastChunkNr = floor( $size / 8192 ); // open stream - $stream = fopen('crypt://' . $pathRelative, "r"); + $stream = fopen( 'crypt://' . $pathRelative, "r" ); - if (is_resource($stream)) { + if ( is_resource( $stream ) ) { // calculate last chunk position - $lastChunckPos = ($lastChunckNr * 8192); + $lastChunckPos = ( $lastChunkNr * 8192 ); // seek to end - fseek($stream, $lastChunckPos); + fseek( $stream, $lastChunckPos ); // get the content of the last chunk - $lastChunkContent = fread($stream, 8192); + $lastChunkContent = fread( $stream, 8192 ); // calc the real file size with the size of the last chunk - $realSize = (($lastChunckNr * 6126) + strlen($lastChunkContent)); + $realSize = ( ( $lastChunkNr * 6126 ) + strlen( $lastChunkContent ) ); // store file size $result = $realSize; @@ -593,8 +584,7 @@ class Util * @param $path absolute path * @return true / false if file is encrypted */ - public function fixFileSize($path) - { + public function fixFileSize( $path ) { $result = false; @@ -602,18 +592,18 @@ class Util $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $realSize = $this->getFileSize($path); + $realSize = $this->getFileSize( $path ); - if ($realSize > 0) { + if ( $realSize > 0 ) { - $cached = $this->view->getFileInfo($path); + $cached = $this->view->getFileInfo( $path ); $cached['encrypted'] = true; // set the size $cached['unencrypted_size'] = $realSize; // put file info - $this->view->putFileInfo($path, $cached); + $this->view->putFileInfo( $path, $cached ); $result = true; @@ -628,13 +618,12 @@ class Util * @brief Format a path to be relative to the /user/files/ directory * @note e.g. turns '/admin/files/test.txt' into 'test.txt' */ - public function stripUserFilesPath($path) - { + public function stripUserFilesPath( $path ) { - $trimmed = ltrim($path, '/'); - $split = explode('/', $trimmed); - $sliced = array_slice($split, 2); - $relPath = implode('/', $sliced); + $trimmed = ltrim( $path, '/' ); + $split = explode( '/', $trimmed ); + $sliced = array_slice( $split, 2 ); + $relPath = implode( '/', $sliced ); return $relPath; @@ -644,13 +633,12 @@ class Util * @param $path * @return bool */ - public function isSharedPath($path) - { + public function isSharedPath( $path ) { - $trimmed = ltrim($path, '/'); - $split = explode('/', $trimmed); + $trimmed = ltrim( $path, '/' ); + $split = explode( '/', $trimmed ); - if ($split[2] == "Shared") { + if ( $split[2] == "Shared" ) { return true; @@ -670,16 +658,15 @@ class Util * @return bool * @note Encryption is recursive */ - public function encryptAll($dirPath, $legacyPassphrase = null, $newPassphrase = null) - { + public function encryptAll( $dirPath, $legacyPassphrase = null, $newPassphrase = null ) { - if ($found = $this->findEncFiles($dirPath)) { + if ( $found = $this->findEncFiles( $dirPath ) ) { // Disable proxy to prevent file being encrypted twice \OC_FileProxy::$enabled = false; // Encrypt unencrypted files - foreach ($found['plain'] as $plainFile) { + foreach ( $found['plain'] as $plainFile ) { //relative to data//file $relPath = $plainFile['path']; @@ -688,80 +675,80 @@ class Util $rawPath = $this->userId . '/files/' . $plainFile['path']; // Open plain file handle for binary reading - $plainHandle1 = $this->view->fopen($rawPath, 'rb'); + $plainHandle1 = $this->view->fopen( $rawPath, 'rb' ); // 2nd handle for moving plain file - view->rename() doesn't work, this is a workaround - $plainHandle2 = $this->view->fopen($rawPath . '.plaintmp', 'wb'); + $plainHandle2 = $this->view->fopen( $rawPath . '.plaintmp', 'wb' ); // Move plain file to a temporary location - stream_copy_to_stream($plainHandle1, $plainHandle2); + stream_copy_to_stream( $plainHandle1, $plainHandle2 ); // Close access to original file // $this->view->fclose( $plainHandle1 ); // not implemented in view{} // Delete original plain file so we can rename enc file later - $this->view->unlink($rawPath); + $this->view->unlink( $rawPath ); // Open enc file handle for binary writing, with same filename as original plain file - $encHandle = fopen('crypt://' . $relPath, 'wb'); + $encHandle = fopen( 'crypt://' . $relPath, 'wb' ); // Save data from plain stream to new encrypted file via enc stream // NOTE: Stream{} will be invoked for handling // the encryption, and should handle all keys // and their generation etc. automatically - stream_copy_to_stream($plainHandle2, $encHandle); + stream_copy_to_stream( $plainHandle2, $encHandle ); // get file size - $size = $this->view->filesize($rawPath . '.plaintmp'); + $size = $this->view->filesize( $rawPath . '.plaintmp' ); // Delete temporary plain copy of file - $this->view->unlink($rawPath . '.plaintmp'); + $this->view->unlink( $rawPath . '.plaintmp' ); // Add the file to the cache - \OC\Files\Filesystem::putFileInfo($plainFile['path'], array('encrypted' => true, 'size' => $size, 'unencrypted_size' => $size)); + \OC\Files\Filesystem::putFileInfo( $plainFile['path'], array( 'encrypted' => true, 'size' => $size, 'unencrypted_size' => $size ) ); } // Encrypt legacy encrypted files if ( - !empty($legacyPassphrase) - && !empty($newPassphrase) + !empty( $legacyPassphrase ) + && !empty( $newPassphrase ) ) { - foreach ($found['legacy'] as $legacyFile) { + foreach ( $found['legacy'] as $legacyFile ) { // Fetch data from file - $legacyData = $this->view->file_get_contents($legacyFile['path']); + $legacyData = $this->view->file_get_contents( $legacyFile['path'] ); $sharingEnabled = \OCP\Share::isEnabled(); // if file exists try to get sharing users - if ($this->view->file_exists($legacyFile['path'])) { - $uniqueUserIds = $this->getSharingUsersArray($sharingEnabled, $legacyFile['path'], $this->userId); + if ( $this->view->file_exists( $legacyFile['path'] ) ) { + $uniqueUserIds = $this->getSharingUsersArray( $sharingEnabled, $legacyFile['path'], $this->userId ); } else { $uniqueUserIds[] = $this->userId; } // Fetch public keys for all users who will share the file - $publicKeys = Keymanager::getPublicKeys($this->view, $uniqueUserIds); + $publicKeys = Keymanager::getPublicKeys( $this->view, $uniqueUserIds ); // Recrypt data, generate catfile - $recrypted = Crypt::legacyKeyRecryptKeyfile($legacyData, $legacyPassphrase, $publicKeys, $newPassphrase, $legacyFile['path']); + $recrypted = Crypt::legacyKeyRecryptKeyfile( $legacyData, $legacyPassphrase, $publicKeys, $newPassphrase, $legacyFile['path'] ); $rawPath = $legacyFile['path']; - $relPath = $this->stripUserFilesPath($rawPath); + $relPath = $this->stripUserFilesPath( $rawPath ); // Save keyfile - Keymanager::setFileKey($this->view, $relPath, $this->userId, $recrypted['filekey']); + Keymanager::setFileKey( $this->view, $relPath, $this->userId, $recrypted['filekey'] ); // Save sharekeys to user folders - Keymanager::setShareKeys($this->view, $relPath, $recrypted['sharekeys']); + Keymanager::setShareKeys( $this->view, $relPath, $recrypted['sharekeys'] ); // Overwrite the existing file with the encrypted one - $this->view->file_put_contents($rawPath, $recrypted['data']); + $this->view->file_put_contents( $rawPath, $recrypted['data'] ); - $size = strlen($recrypted['data']); + $size = strlen( $recrypted['data'] ); // Add the file to the cache - \OC\Files\Filesystem::putFileInfo($rawPath, array('encrypted' => true, 'size' => $size), ''); + \OC\Files\Filesystem::putFileInfo( $rawPath, array( 'encrypted' => true, 'size' => $size ), '' ); } } @@ -781,10 +768,9 @@ class Util * @param string $pathName Name of the directory to return the path of * @return string path */ - public function getPath($pathName) - { + public function getPath( $pathName ) { - switch ($pathName) { + switch ( $pathName ) { case 'publicKeyDir': @@ -815,9 +801,10 @@ class Util return $this->privateKeyPath; break; - } + return false; + } /** @@ -825,18 +812,17 @@ class Util * @param int $fileId id of the file * @return string path of the file */ - public static function fileIdToPath($fileId) - { + public static function fileIdToPath( $fileId ) { - $query = \OC_DB::prepare('SELECT `path`' + $query = \OC_DB::prepare( 'SELECT `path`' . ' FROM `*PREFIX*filecache`' - . ' WHERE `fileid` = ?'); + . ' WHERE `fileid` = ?' ); - $result = $query->execute(array($fileId)); + $result = $query->execute( array( $fileId ) ); $row = $result->fetchRow(); - return substr($row['path'], 5); + return substr( $row['path'], 5 ); } @@ -845,16 +831,15 @@ class Util * @param array $unfilteredUsers users to be checked for sharing readiness * @return multi-dimensional array. keys: ready, unready */ - public function filterShareReadyUsers($unfilteredUsers) - { + public function filterShareReadyUsers( $unfilteredUsers ) { // This array will collect the filtered IDs $readyIds = $unreadyIds = array(); // Loop through users and create array of UIDs that need new keyfiles - foreach ($unfilteredUsers as $user) { + foreach ( $unfilteredUsers as $user ) { - $util = new Util($this->view, $user); + $util = new Util( $this->view, $user ); // Check that the user is encryption capable, or is the // public system user 'ownCloud' (for public shares) @@ -874,15 +859,15 @@ class Util // Log warning; we can't do necessary setup here // because we don't have the user passphrase - \OC_Log::write('Encryption library', '"' . $user . '" is not setup for encryption', \OC_Log::WARN); + \OC_Log::write( 'Encryption library', '"' . $user . '" is not setup for encryption', \OC_Log::WARN ); } } return array( - 'ready' => $readyIds - , 'unready' => $unreadyIds + 'ready' => $readyIds, + 'unready' => $unreadyIds ); } @@ -897,32 +882,31 @@ class Util * @note This was used when 2 types of encryption for keyfiles was used, * but now we've switched to exclusively using openssl_seal() */ - public function decryptUnknownKeyfile($filePath, $fileOwner, $privateKey) - { + public function decryptUnknownKeyfile( $filePath, $fileOwner, $privateKey ) { // Get the encrypted keyfile // NOTE: the keyfile format depends on how it was encrypted! At // this stage we don't know how it was encrypted - $encKeyfile = Keymanager::getFileKey($this->view, $this->userId, $filePath); + $encKeyfile = Keymanager::getFileKey( $this->view, $this->userId, $filePath ); // We need to decrypt the keyfile // Has the file been shared yet? if ( $this->userId == $fileOwner - && !Keymanager::getShareKey($this->view, $this->userId, $filePath) // NOTE: we can't use isShared() here because it's a post share hook so it always returns true + && !Keymanager::getShareKey( $this->view, $this->userId, $filePath ) // NOTE: we can't use isShared() here because it's a post share hook so it always returns true ) { // The file has no shareKey, and its keyfile must be // decrypted conventionally - $plainKeyfile = Crypt::keyDecrypt($encKeyfile, $privateKey); + $plainKeyfile = Crypt::keyDecrypt( $encKeyfile, $privateKey ); } else { // The file has a shareKey and must use it for decryption - $shareKey = Keymanager::getShareKey($this->view, $this->userId, $filePath); + $shareKey = Keymanager::getShareKey( $this->view, $this->userId, $filePath ); - $plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); } @@ -937,23 +921,22 @@ class Util * @param string $filePath path of the file to be shared * @return bool */ - public function setSharedFileKeyfiles(Session $session, array $users, $filePath) - { + public function setSharedFileKeyfiles( Session $session, array $users, $filePath ) { // Make sure users are capable of sharing - $filteredUids = $this->filterShareReadyUsers($users); + $filteredUids = $this->filterShareReadyUsers( $users ); // If we're attempting to share to unready users - if (!empty($filteredUids['unready'])) { + if ( !empty( $filteredUids['unready'] ) ) { - \OC_Log::write('Encryption library', 'Sharing to these user(s) failed as they are unready for encryption:"' . print_r($filteredUids['unready'], 1), \OC_Log::WARN); + \OC_Log::write( 'Encryption library', 'Sharing to these user(s) failed as they are unready for encryption:"' . print_r( $filteredUids['unready'], 1 ), \OC_Log::WARN ); return false; } // Get public keys for each user, ready for generating sharekeys - $userPubKeys = Keymanager::getPublicKeys($this->view, $filteredUids['ready']); + $userPubKeys = Keymanager::getPublicKeys( $this->view, $filteredUids['ready'] ); // Note proxy status then disable it $proxyStatus = \OC_FileProxy::$enabled; @@ -962,22 +945,22 @@ class Util // Get the current users's private key for decrypting existing keyfile $privateKey = $session->getPrivateKey(); - $fileOwner = \OC\Files\Filesystem::getOwner($filePath); + $fileOwner = \OC\Files\Filesystem::getOwner( $filePath ); // Decrypt keyfile - $plainKeyfile = $this->decryptUnknownKeyfile($filePath, $fileOwner, $privateKey); + $plainKeyfile = $this->decryptUnknownKeyfile( $filePath, $fileOwner, $privateKey ); // Re-enc keyfile to (additional) sharekeys - $multiEncKey = Crypt::multiKeyEncrypt($plainKeyfile, $userPubKeys); + $multiEncKey = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys ); // Save the recrypted key to it's owner's keyfiles directory // Save new sharekeys to all necessary user directory if ( - !Keymanager::setFileKey($this->view, $filePath, $fileOwner, $multiEncKey['data']) - || !Keymanager::setShareKeys($this->view, $filePath, $multiEncKey['keys']) + !Keymanager::setFileKey( $this->view, $filePath, $fileOwner, $multiEncKey['data'] ) + || !Keymanager::setShareKeys( $this->view, $filePath, $multiEncKey['keys'] ) ) { - \OC_Log::write('Encryption library', 'Keyfiles could not be saved for users sharing ' . $filePath, \OC_Log::ERROR); + \OC_Log::write( 'Encryption library', 'Keyfiles could not be saved for users sharing ' . $filePath, \OC_Log::ERROR ); return false; @@ -993,12 +976,11 @@ class Util * @brief Find, sanitise and format users sharing a file * @note This wraps other methods into a portable bundle */ - public function getSharingUsersArray($sharingEnabled, $filePath, $currentUserId = false) - { + public function getSharingUsersArray( $sharingEnabled, $filePath, $currentUserId = false ) { // Check if key recovery is enabled if ( - \OC_Appconfig::getValue('files_encryption', 'recoveryAdminEnabled') + \OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' ) && $this->recoveryEnabledForUser() ) { @@ -1011,14 +993,15 @@ class Util } // Make sure that a share key is generated for the owner too - list($owner, $ownerPath) = $this->getUidAndFilename($filePath); + list( $owner, $ownerPath ) = $this->getUidAndFilename( $filePath ); - if ($sharingEnabled) { + $userIds = array(); + if ( $sharingEnabled ) { // Find out who, if anyone, is sharing the file - $result = \OCP\Share::getUsersSharingFile($ownerPath, $owner, true, true, true); + $result = \OCP\Share::getUsersSharingFile( $ownerPath, $owner, true, true, true ); $userIds = $result['users']; - if ($result['public']) { + if ( $result['public'] ) { $userIds[] = $this->publicShareKeyId; } @@ -1026,10 +1009,10 @@ class Util // If recovery is enabled, add the // Admin UID to list of users to share to - if ($recoveryEnabled) { + if ( $recoveryEnabled ) { // Find recoveryAdmin user ID - $recoveryKeyId = \OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); + $recoveryKeyId = \OC_Appconfig::getValue( 'files_encryption', 'recoveryKeyId' ); // Add recoveryAdmin to list of users sharing $userIds[] = $recoveryKeyId; @@ -1037,14 +1020,14 @@ class Util } // add current user if given - if ($currentUserId != false) { + if ( $currentUserId != false ) { $userIds[] = $currentUserId; } // Remove duplicate UIDs - $uniqueUserIds = array_unique($userIds); + $uniqueUserIds = array_unique( $userIds ); return $uniqueUserIds; @@ -1055,8 +1038,7 @@ class Util * @param $status * @return bool */ - public function setMigrationStatus($status) - { + public function setMigrationStatus( $status ) { $sql = 'UPDATE *PREFIX*encryption @@ -1065,11 +1047,11 @@ class Util WHERE uid = ?'; - $args = array($status, $this->userId); + $args = array( $status, $this->userId ); - $query = \OCP\DB::prepare($sql); + $query = \OCP\DB::prepare( $sql ); - if ($query->execute($args)) { + if ( $query->execute( $args ) ) { return true; @@ -1087,8 +1069,7 @@ class Util * @note If records are not being returned, check for a hidden space * at the start of the uid in db */ - public function getMigrationStatus() - { + public function getMigrationStatus() { $sql = 'SELECT migration_status @@ -1097,22 +1078,21 @@ class Util WHERE uid = ?'; - $args = array($this->userId); + $args = array( $this->userId ); - $query = \OCP\DB::prepare($sql); + $query = \OCP\DB::prepare( $sql ); - $result = $query->execute($args); + $result = $query->execute( $args ); $migrationStatus = array(); - while ($row = $result->fetchRow()) { - + $row = $result->fetchRow(); + if($row) { $migrationStatus[] = $row['migration_status']; - } // If no record is found - if (empty($migrationStatus)) { + if ( empty( $migrationStatus ) ) { return false; @@ -1132,83 +1112,74 @@ class Util * relative to /Shared are also acceptable * @return array */ - public function getUidAndFilename($path) - { + public function getUidAndFilename( $path ) { - $view = new \OC\Files\View($this->userFilesDir); - $fileOwnerUid = $view->getOwner($path); + $view = new \OC\Files\View( $this->userFilesDir ); + $fileOwnerUid = $view->getOwner( $path ); // handle public access - if ($this->isPublic) { + if ( $this->isPublic ) { $filename = $path; $fileOwnerUid = $GLOBALS['fileOwner']; - return array($fileOwnerUid, $filename); + return array( $fileOwnerUid, $filename ); } else { // Check that UID is valid - if (!\OCP\User::userExists($fileOwnerUid)) { - throw new \Exception('Could not find owner (UID = "' . var_export($fileOwnerUid, 1) . '") of file "' . $path . '"'); + if ( !\OCP\User::userExists( $fileOwnerUid ) ) { + throw new \Exception( 'Could not find owner (UID = "' . var_export( $fileOwnerUid, 1 ) . '") of file "' . $path . '"' ); } // NOTE: Bah, this dependency should be elsewhere - \OC\Files\Filesystem::initMountPoints($fileOwnerUid); + \OC\Files\Filesystem::initMountPoints( $fileOwnerUid ); // If the file owner is the currently logged in user - if ($fileOwnerUid == $this->userId) { + if ( $fileOwnerUid == $this->userId ) { // Assume the path supplied is correct $filename = $path; } else { - $info = $view->getFileInfo($path); - $ownerView = new \OC\Files\View('/' . $fileOwnerUid . '/files'); + $info = $view->getFileInfo( $path ); + $ownerView = new \OC\Files\View( '/' . $fileOwnerUid . '/files' ); // Fetch real file path from DB - $filename = $ownerView->getPath($info['fileid']); // TODO: Check that this returns a path without including the user data dir + $filename = $ownerView->getPath( $info['fileid'] ); // TODO: Check that this returns a path without including the user data dir } - return array($fileOwnerUid, $filename); + return array( $fileOwnerUid, $filename ); } } /** - * @brief geo recursively through a dir and collect all files and sub files. + * @brief go recursively through a dir and collect all files and sub files. * @param string $dir relative to the users files folder * @return array with list of files relative to the users files folder */ - public function getAllFiles($dir) - { + public function getAllFiles( $dir ) { $result = array(); - $content = $this->view->getDirectoryContent($this->userFilesDir . $dir); + $content = $this->view->getDirectoryContent( $this->userFilesDir . $dir ); // handling for re shared folders - $path_split = explode('/', $dir); - $shared = ''; - - if ($path_split[1] === 'Shared') { - - $shared = '/Shared'; + $path_split = explode( '/', $dir ); - } - - foreach ($content as $c) { + foreach ( $content as $c ) { - $sharedPart = $path_split[sizeof($path_split) - 1]; - $targetPathSplit = array_reverse(explode('/', $c['path'])); + $sharedPart = $path_split[sizeof( $path_split ) - 1]; + $targetPathSplit = array_reverse( explode( '/', $c['path'] ) ); $path = ''; // rebuild path - foreach ($targetPathSplit as $pathPart) { + foreach ( $targetPathSplit as $pathPart ) { - if ($pathPart !== $sharedPart) { + if ( $pathPart !== $sharedPart ) { $path = '/' . $pathPart . $path; @@ -1222,9 +1193,9 @@ class Util $path = $dir . $path; - if ($c['type'] === "dir") { + if ( $c['type'] === "dir" ) { - $result = array_merge($result, $this->getAllFiles($path)); + $result = array_merge( $result, $this->getAllFiles( $path ) ); } else { @@ -1242,14 +1213,13 @@ class Util * @param int $id of the current share * @return array of the parent */ - public static function getShareParent($id) - { + public static function getShareParent( $id ) { - $query = \OC_DB::prepare('SELECT `file_target`, `item_type`' + $query = \OC_DB::prepare( 'SELECT `file_target`, `item_type`' . ' FROM `*PREFIX*share`' - . ' WHERE `id` = ?'); + . ' WHERE `id` = ?' ); - $result = $query->execute(array($id)); + $result = $query->execute( array( $id ) ); $row = $result->fetchRow(); @@ -1262,14 +1232,13 @@ class Util * @param int $id of the current share * @return array of the parent */ - public static function getParentFromShare($id) - { + public static function getParentFromShare( $id ) { - $query = \OC_DB::prepare('SELECT `parent`' + $query = \OC_DB::prepare( 'SELECT `parent`' . ' FROM `*PREFIX*share`' - . ' WHERE `id` = ?'); + . ' WHERE `id` = ?' ); - $result = $query->execute(array($id)); + $result = $query->execute( array( $id ) ); $row = $result->fetchRow(); @@ -1283,22 +1252,23 @@ class Util * @internal param int $Id of a share * @return string owner */ - public function getOwnerFromSharedFile($id) - { + public function getOwnerFromSharedFile( $id ) { + + $query = \OC_DB::prepare( 'SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1 ); + $source = $query->execute( array( $id ) )->fetchRow(); - $query = \OC_DB::prepare('SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1); - $source = $query->execute(array($id))->fetchRow(); + $fileOwner = false; - if (isset($source['parent'])) { + if ( isset( $source['parent'] ) ) { $parent = $source['parent']; - while (isset($parent)) { + while ( isset( $parent ) ) { - $query = \OC_DB::prepare('SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1); - $item = $query->execute(array($parent))->fetchRow(); + $query = \OC_DB::prepare( 'SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1 ); + $item = $query->execute( array( $parent ) )->fetchRow(); - if (isset($item['parent'])) { + if ( isset( $item['parent'] ) ) { $parent = $item['parent']; @@ -1324,16 +1294,14 @@ class Util /** * @return string */ - public function getUserId() - { + public function getUserId() { return $this->userId; } /** * @return string */ - public function getUserFilesDir() - { + public function getUserFilesDir() { return $this->userFilesDir; } @@ -1341,8 +1309,7 @@ class Util * @param $password * @return bool */ - public function checkRecoveryPassword($password) - { + public function checkRecoveryPassword( $password ) { $pathKey = '/owncloud_private_key/' . $this->recoveryKeyId . ".private.key"; $pathControlData = '/control-file/controlfile.enc'; @@ -1350,16 +1317,16 @@ class Util $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $recoveryKey = $this->view->file_get_contents($pathKey); + $recoveryKey = $this->view->file_get_contents( $pathKey ); - $decryptedRecoveryKey = Crypt::symmetricDecryptFileContent($recoveryKey, $password); + $decryptedRecoveryKey = Crypt::symmetricDecryptFileContent( $recoveryKey, $password ); - $controlData = $this->view->file_get_contents($pathControlData); - $decryptedControlData = Crypt::keyDecrypt($controlData, $decryptedRecoveryKey); + $controlData = $this->view->file_get_contents( $pathControlData ); + $decryptedControlData = Crypt::keyDecrypt( $controlData, $decryptedRecoveryKey ); \OC_FileProxy::$enabled = $proxyStatus; - if ($decryptedControlData === 'ownCloud') { + if ( $decryptedControlData === 'ownCloud' ) { return true; } @@ -1369,27 +1336,26 @@ class Util /** * @return string */ - public function getRecoveryKeyId() - { + public function getRecoveryKeyId() { return $this->recoveryKeyId; } /** * @brief add recovery key to all encrypted files */ - public function addRecoveryKeys($path = '/') - { - $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path); - foreach ($dirContent as $item) { - $filePath = substr($item['path'], 25); - if ($item['type'] == 'dir') { - $this->addRecoveryKeys($filePath . '/'); + public function addRecoveryKeys( $path = '/' ) { + $dirContent = $this->view->getDirectoryContent( $this->keyfilesPath . $path ); + foreach ( $dirContent as $item ) { + // get relative path from files_encryption/keyfiles/ + $filePath = substr( $item['path'], strlen('files_encryption/keyfiles') ); + if ( $item['type'] == 'dir' ) { + $this->addRecoveryKeys( $filePath . '/' ); } else { - $session = new Session(new \OC_FilesystemView('/')); + $session = new Session( new \OC_FilesystemView( '/' ) ); $sharingEnabled = \OCP\Share::isEnabled(); - $file = substr($filePath, 0, -4); - $usersSharing = $this->getSharingUsersArray($sharingEnabled, $file); - $this->setSharedFileKeyfiles($session, $usersSharing, $file); + $file = substr( $filePath, 0, -4 ); + $usersSharing = $this->getSharingUsersArray( $sharingEnabled, $file ); + $this->setSharedFileKeyfiles( $session, $usersSharing, $file ); } } } @@ -1397,16 +1363,16 @@ class Util /** * @brief remove recovery key to all encrypted files */ - public function removeRecoveryKeys($path = '/') - { - $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path); - foreach ($dirContent as $item) { - $filePath = substr($item['path'], 25); - if ($item['type'] == 'dir') { - $this->removeRecoveryKeys($filePath . '/'); + public function removeRecoveryKeys( $path = '/' ) { + $dirContent = $this->view->getDirectoryContent( $this->keyfilesPath . $path ); + foreach ( $dirContent as $item ) { + // get relative path from files_encryption/keyfiles + $filePath = substr( $item['path'], strlen('files_encryption/keyfiles') ); + if ( $item['type'] == 'dir' ) { + $this->removeRecoveryKeys( $filePath . '/' ); } else { - $file = substr($filePath, 0, -4); - $this->view->unlink($this->shareKeysPath . '/' . $file . '.' . $this->recoveryKeyId . '.shareKey'); + $file = substr( $filePath, 0, -4 ); + $this->view->unlink( $this->shareKeysPath . '/' . $file . '.' . $this->recoveryKeyId . '.shareKey' ); } } } @@ -1416,40 +1382,39 @@ class Util * @param string $file * @param string $privateKey recovery key to decrypt the file */ - private function recoverFile($file, $privateKey) - { + private function recoverFile( $file, $privateKey ) { $sharingEnabled = \OCP\Share::isEnabled(); // Find out who, if anyone, is sharing the file - if ($sharingEnabled) { - $result = \OCP\Share::getUsersSharingFile($file, $this->userId, true, true, true); + if ( $sharingEnabled ) { + $result = \OCP\Share::getUsersSharingFile( $file, $this->userId, true, true, true ); $userIds = $result['users']; $userIds[] = $this->recoveryKeyId; - if ($result['public']) { + if ( $result['public'] ) { $userIds[] = $this->publicShareKeyId; } } else { - $userIds = array($this->userId, $this->recoveryKeyId); + $userIds = array( $this->userId, $this->recoveryKeyId ); } - $filteredUids = $this->filterShareReadyUsers($userIds); + $filteredUids = $this->filterShareReadyUsers( $userIds ); $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; //decrypt file key - $encKeyfile = $this->view->file_get_contents($this->keyfilesPath . $file . ".key"); - $shareKey = $this->view->file_get_contents($this->shareKeysPath . $file . "." . $this->recoveryKeyId . ".shareKey"); - $plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + $encKeyfile = $this->view->file_get_contents( $this->keyfilesPath . $file . ".key" ); + $shareKey = $this->view->file_get_contents( $this->shareKeysPath . $file . "." . $this->recoveryKeyId . ".shareKey" ); + $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); // encrypt file key again to all users, this time with the new public key for the recovered use - $userPubKeys = Keymanager::getPublicKeys($this->view, $filteredUids['ready']); - $multiEncKey = Crypt::multiKeyEncrypt($plainKeyfile, $userPubKeys); + $userPubKeys = Keymanager::getPublicKeys( $this->view, $filteredUids['ready'] ); + $multiEncKey = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys ); // write new keys to filesystem TDOO! - $this->view->file_put_contents($this->keyfilesPath . $file . '.key', $multiEncKey['data']); - foreach ($multiEncKey['keys'] as $userId => $shareKey) { + $this->view->file_put_contents( $this->keyfilesPath . $file . '.key', $multiEncKey['data'] ); + foreach ( $multiEncKey['keys'] as $userId => $shareKey ) { $shareKeyPath = $this->shareKeysPath . $file . '.' . $userId . '.shareKey'; - $this->view->file_put_contents($shareKeyPath, $shareKey); + $this->view->file_put_contents( $shareKeyPath, $shareKey ); } // Return proxy to original status @@ -1461,16 +1426,15 @@ class Util * @param string $path to look for files keys * @param string $privateKey private recovery key which is used to decrypt the files */ - private function recoverAllFiles($path, $privateKey) - { - $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path); - foreach ($dirContent as $item) { - $filePath = substr($item['path'], 25); - if ($item['type'] == 'dir') { - $this->recoverAllFiles($filePath . '/', $privateKey); + private function recoverAllFiles( $path, $privateKey ) { + $dirContent = $this->view->getDirectoryContent( $this->keyfilesPath . $path ); + foreach ( $dirContent as $item ) { + $filePath = substr( $item['path'], 25 ); + if ( $item['type'] == 'dir' ) { + $this->recoverAllFiles( $filePath . '/', $privateKey ); } else { - $file = substr($filePath, 0, -4); - $this->recoverFile($file, $privateKey); + $file = substr( $filePath, 0, -4 ); + $this->recoverFile( $file, $privateKey ); } } } @@ -1479,19 +1443,18 @@ class Util * @brief recover users files in case of password lost * @param string $recoveryPassword */ - public function recoverUsersFiles($recoveryPassword) - { + public function recoverUsersFiles( $recoveryPassword ) { // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $encryptedKey = $this->view->file_get_contents('/owncloud_private_key/' . $this->recoveryKeyId . '.private.key'); - $privateKey = Crypt::symmetricDecryptFileContent($encryptedKey, $recoveryPassword); + $encryptedKey = $this->view->file_get_contents( '/owncloud_private_key/' . $this->recoveryKeyId . '.private.key' ); + $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $recoveryPassword ); \OC_FileProxy::$enabled = $proxyStatus; - $this->recoverAllFiles('/', $privateKey); + $this->recoverAllFiles( '/', $privateKey ); } } diff --git a/apps/files_encryption/settings-admin.php b/apps/files_encryption/settings-admin.php index 66efc584367..6cc5b997fdb 100644 --- a/apps/files_encryption/settings-admin.php +++ b/apps/files_encryption/settings-admin.php @@ -15,7 +15,6 @@ $view = new OC_FilesystemView( '' ); $recoveryAdminEnabled = OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' ); -$tmpl->assign( 'encryption_mode', \OC_Appconfig::getValue( 'files_encryption', 'mode', 'none' ) ); $tmpl->assign( 'recoveryEnabled', $recoveryAdminEnabled ); \OCP\Util::addscript( 'files_encryption', 'settings-admin' ); diff --git a/apps/files_encryption/settings-personal.php b/apps/files_encryption/settings-personal.php index ada8ffbc318..57f7f584523 100644 --- a/apps/files_encryption/settings-personal.php +++ b/apps/files_encryption/settings-personal.php @@ -26,4 +26,3 @@ $tmpl->assign( 'recoveryEnabledForUser', $recoveryEnabledForUser ); return $tmpl->fetchPage(); -return null; diff --git a/apps/files_encryption/templates/settings-personal.php b/apps/files_encryption/templates/settings-personal.php index 14e8ce960a2..04d6e79179e 100644 --- a/apps/files_encryption/templates/settings-personal.php +++ b/apps/files_encryption/templates/settings-personal.php @@ -29,18 +29,5 @@


- -- cgit v1.2.3 From f56802a437e47deae84cbd5a337620d79dbae34e Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Fri, 24 May 2013 18:37:58 +0200 Subject: no use the recoveryPassword var instead of accessing the POST array --- apps/files_encryption/lib/helper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apps/files_encryption/lib') diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php index 43f573c16b9..7a2d19eed57 100755 --- a/apps/files_encryption/lib/helper.php +++ b/apps/files_encryption/lib/helper.php @@ -146,7 +146,7 @@ class Helper } else { // get recovery key and check the password $util = new \OCA\Encryption\Util( new \OC_FilesystemView( '/' ), \OCP\User::getUser() ); - $return = $util->checkRecoveryPassword( $_POST['recoveryPassword'] ); + $return = $util->checkRecoveryPassword( $recoveryPassword ); if ( $return ) { \OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminEnabled', 1 ); } -- cgit v1.2.3