From e9f3c5feea94833d686dbc1b99e01b7a06fdaaed Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Mon, 14 Jan 2013 15:39:04 +0000 Subject: [PATCH 001/131] Added creation of dir for shared file env encryption keys Added comment to use multiKeyEncrypt --- apps/files_encryption/lib/crypt.php | 2 ++ apps/files_encryption/lib/util.php | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index fddc89dae54..642187b9103 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -390,6 +390,8 @@ class Crypt { */ public static function multiKeyEncrypt( $plainContent, array $publicKeys ) { + // Set empty vars to be set by openssl by reference + $sealed = ''; $envKeys = array(); if( openssl_seal( $plainContent, $sealed, $envKeys, $publicKeys ) ) { diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index cd46d23108a..56e4d572c24 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -96,9 +96,10 @@ class Util { private $view; // OC_FilesystemView object for filesystem operations private $pwd; // User Password private $client; // Client side encryption mode flag - private $publicKeyDir; // Directory containing all public user keys - private $encryptionDir; // Directory containing user's files_encryption - private $keyfilesPath; // Directory containing user's keyfiles + private $publicKeyDir; // Dir containing all public user keys + private $encryptionDir; // Dir containing user's files_encryption + private $keyfilesPath; // Dir containing user's keyfiles + 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 @@ -110,6 +111,7 @@ class Util { $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 @@ -159,6 +161,13 @@ class Util { $this->view->mkdir( $this->keyfilesPath ); } + + // Create mirrored share env keys directory + if( !$this->view->file_exists( $this->shareKeysPath ) ) { + + $this->view->mkdir( $this->shareKeysPath ); + + } // Create user keypair if ( From de0ed634f2fb1bb9fbb93f6c0a66882dea42e288 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Mon, 14 Jan 2013 17:05:47 +0000 Subject: [PATCH 002/131] Added two hooks: pre_unshare and pre_unshareAll, useful for files_encryption --- lib/public/share.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/public/share.php b/lib/public/share.php index 8c0cfc16b4e..0ff68fe265a 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -465,6 +465,13 @@ class Share { null, 1); if ($item) { + // Pass all the vars we have for now, they may be useful + \OC_Hook::emit('OCP\Share', 'pre_unshare', array( + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'shareType' => $shareType, + 'shareWith' => $shareWith, + )); self::delete($item['id']); return true; } @@ -480,6 +487,12 @@ class Share { public static function unshareAll($itemType, $itemSource) { $shares = self::getItemShared($itemType, $itemSource); if ($shares) { + // Pass all the vars we have for now, they may be useful + \OC_Hook::emit('OCP\Share', 'pre_unshareAll', array( + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'shares' => $shares + )); foreach ($shares as $share) { self::delete($share['id']); } From d95fc4e1e33f2e6fe4664d03bd39aa48f27e0ad8 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Mon, 14 Jan 2013 19:07:28 +0000 Subject: [PATCH 003/131] Adding sharing support: added new method in Keymanager setShareKey() Added notes in proxy{} and stream{} pointing to share support --- apps/files_encryption/appinfo/app.php | 16 ++++- apps/files_encryption/hooks/hooks.php | 44 ++++++++++++- apps/files_encryption/lib/keymanager.php | 77 ++++++++++++++--------- apps/files_encryption/lib/proxy.php | 9 ++- apps/files_encryption/lib/stream.php | 13 ++-- apps/files_encryption/test/keymanager.php | 16 +++-- 6 files changed, 125 insertions(+), 50 deletions(-) diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index 31b430d37a9..cc78402d1d0 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -10,10 +10,18 @@ OC::$CLASSPATH['OCA\Encryption\Session'] = 'apps/files_encryption/lib/session.ph 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_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfile' ); OCP\Util::connectHook( 'OC_User','post_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_unshare','OCA\Encryption\Hooks' ,'preUnshare' ); +OCP\Util::connectHook( 'OCP\Share','pre_unshareAll','OCA\Encryption\Hooks' ,'preUnshareAll' ); + +// Webdav-related hooks +OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfile' ); + stream_wrapper_register( 'crypt', 'OCA\Encryption\Stream' ); $session = new OCA\Encryption\Session(); @@ -24,7 +32,9 @@ if ( && OCA\Encryption\Crypt::mode() == 'server' ) { - // Force the user to re-log in if the encryption key isn't unlocked (happens when a user is logged in before the encryption app is enabled) + // Force the user to re-log in if the encryption key isn't unlocked + // (happens when a user is logged in before the encryption app is + // enabled) OCP\User::logout(); header( "Location: " . OC::$WEBROOT.'/' ); @@ -33,5 +43,5 @@ if ( } -OCP\App::registerAdmin( 'files_encryption', 'settings'); +OCP\App::registerAdmin( 'files_encryption', 'settings' ); OCP\App::registerPersonal( 'files_encryption', 'settings-personal' ); \ No newline at end of file diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index c2f97247835..ecceae352bc 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -121,8 +121,11 @@ class Hooks { if ( isset( $params['properties']['key'] ) ) { - Keymanager::setFileKey( $params['path'], $params['properties']['key'] ); - + $view = new \OC_FilesystemView( '/' ); + $userId = \OCP\User::getUser(); + + Keymanager::setFileKey( $view, $params['path'], $userId, $params['properties']['key'] ); + } else { \OC_Log::write( @@ -138,6 +141,43 @@ class Hooks { } + /** + * @brief + */ + public static function postShared( $params ) { + + // Delete existing catfile + Keymanager::deleteFileKey( ); + + // Generate new catfile and env keys + Crypt::multiKeyEncrypt( $plainContent, $publicKeys ); + + // Save env keys to user folders + + + } + + /** + * @brief + */ + public static function preUnshare( $params ) { + + // Delete existing catfile + + // Generate new catfile and env keys + + // Save env keys to user folders + } + + /** + * @brief + */ + public static function preUnshareAll( $params ) { + + trigger_error( "preUnshareAll" ); + + } + } ?> \ No newline at end of file diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 706e1c2661e..61bc50721ef 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -238,7 +238,7 @@ class Keymanager { */ public static function setUserKeys($privatekey, $publickey) { - return (self::setPrivateKey($privatekey) && self::setPublicKey($publickey)); + return ( self::setPrivateKey( $privatekey ) && self::setPublicKey( $publickey ) ); } @@ -262,6 +262,42 @@ class Keymanager { } + /** + * @note 'shareKey' is a more user-friendly name for env_key + */ + 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 + if ( + isset( $path_parts['dirname'] ) + && ! $view->file_exists( $basePath . $path_parts['dirname'] ) + ) { + + $view->mkdir( $basePath . $path_parts['dirname'] ); + + } + + return $targetPath; + + } + /** * @brief store file encryption key * @@ -271,15 +307,16 @@ 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( $path, $key, $view = Null, $dbClassName = '\OC_DB') { - - $targetPath = ltrim( $path, '/' ); - $user = \OCP\User::getUser(); + public static function setFileKey( \OC_FilesystemView $view, $path, $userId, $catfile ) { -// // update $keytarget and $user if key belongs to a file shared by someone else + $basePath = '/' . $userId . '/files_encryption/keyfiles'; + + $targetPath = self::keySetPreparation( $view, $path, $basePath, $userId ); + +// // update $keytarget and $userId if key belongs to a file shared by someone else // $query = $dbClassName::prepare( "SELECT uid_owner, source, target FROM `*PREFIX*sharing` WHERE target = ? AND uid_shared_with = ?" ); // -// $result = $query->execute( array ( '/'.$user.'/files/'.$targetPath, $user ) ); +// $result = $query->execute( array ( '/'.$userId.'/files/'.$targetPath, $userId ) ); // // if ( $row = $result->fetchRow( ) ) { // @@ -287,7 +324,7 @@ class Keymanager { // // $targetPath_parts = explode( '/', $targetPath ); // -// $user = $targetPath_parts[1]; +// $userId = $targetPath_parts[1]; // // $rootview = new \OC_FilesystemView( '/' ); // @@ -299,34 +336,14 @@ class Keymanager { // // } // -// $targetPath = str_replace( '/'.$user.'/files/', '', $targetPath ); +// $targetPath = str_replace( '/'.$userId.'/files/', '', $targetPath ); // // //TODO: check for write permission on shared file once the new sharing API is in place // // } - $path_parts = pathinfo( $targetPath ); - - if ( !$view ) { - - $view = new \OC_FilesystemView( '/' ); - - } - - $view->chroot( '/' . $user . '/files_encryption/keyfiles' ); - - // If the file resides within a subdirectory, create it - if ( - isset( $path_parts['dirname'] ) - && ! $view->file_exists( $path_parts['dirname'] ) - ) { - - $view->mkdir( $path_parts['dirname'] ); - - } - // Save the keyfile in parallel directory - return $view->file_put_contents( '/' . $targetPath . '.key', $key ); + return $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); } diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 52f47dba294..83c5e21c4bd 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -101,6 +101,8 @@ 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 + // Encrypt plain data and fetch key $encrypted = Crypt::keyEncryptKeyfile( $data, Keymanager::getPublicKey( $rootView, $userId ) ); @@ -114,10 +116,11 @@ class Proxy extends \OC_FileProxy { $filePath = '/' . implode( '/', $filePath ); # TODO: make keyfile dir dynamic from app config - $view = new \OC_FilesystemView( '/' . $userId . '/files_encryption/keyfiles' ); + + $view = new \OC_FilesystemView( '/' ); // Save keyfile for newly encrypted file in parallel directory tree - Keymanager::setFileKey( $filePath, $encrypted['key'], $view, '\OC_DB' ); + Keymanager::setFileKey( $view, $filePath, $userId, $encrypted['key'] ); // Update the file cache with file info \OC_FileCache::put( $path, array( 'encrypted'=>true, 'size' => $size ), '' ); @@ -159,6 +162,8 @@ class Proxy extends \OC_FileProxy { $userId = \OCP\USER::getUser(); + # TODO: Check if file is shared, if so, use multiKeyDecrypt + $encryptedKeyfile = Keymanager::getFileKey( $view, $userId, $filePath ); $session = new Session(); diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index f482e2d75ac..a17a4514faa 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -302,8 +302,12 @@ class Stream { // Make sure the userId is set $this->getuser(); + # 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 we're writing a new file (not overwriting an existing + // one), save the newly generated keyfile if ( ! $this->getKey() ) { $this->keyfile = Crypt::generateKey(); @@ -312,10 +316,11 @@ class Stream { $this->encKeyfile = Crypt::keyEncrypt( $this->keyfile, $this->publicKey ); - // Save the new encrypted file key - Keymanager::setFileKey( $this->rawPath, $this->encKeyfile, new \OC_FilesystemView( '/' ) ); + $view = new \OC_FilesystemView( '/' ); + $userId = \OCP\User::getUser(); - # TODO: move this new OCFSV out of here some how, use DI + // Save the new encrypted file key + Keymanager::setFileKey( $view, $this->rawPath, $userId, $this->encKeyfile ); } diff --git a/apps/files_encryption/test/keymanager.php b/apps/files_encryption/test/keymanager.php index f02d6eb5f7a..bf453fe3163 100644 --- a/apps/files_encryption/test/keymanager.php +++ b/apps/files_encryption/test/keymanager.php @@ -79,15 +79,13 @@ class Test_Keymanager extends \PHPUnit_Framework_TestCase { # NOTE: This cannot be tested until we are able to break out # of the FileSystemView data directory root -// $key = Crypt::symmetricEncryptFileContentKeyfile( $this->data, 'hat' ); -// -// $tmpPath = sys_get_temp_dir(). '/' . 'testSetFileKey'; -// -// $view = new \OC_FilesystemView( '/tmp/' ); -// -// //$view = new \OC_FilesystemView( '/' . $this->userId . '/files_encryption/keyfiles' ); -// -// Encryption\Keymanager::setFileKey( $tmpPath, $key['key'], $view ); + $key = Encryption\Crypt::symmetricEncryptFileContentKeyfile( $this->randomKey, 'hat' ); + + $path = 'unittest-'.time().'txt'; + + //$view = new \OC_FilesystemView( '/' . $this->userId . '/files_encryption/keyfiles' ); + + Encryption\Keymanager::setFileKey( $this->view, $path, $this->userId, $key['key'] ); } From 316eef3ded233c53ccb1f40aa339372ed9c644d9 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Sat, 19 Jan 2013 01:50:02 -0500 Subject: [PATCH 004/131] Fix sharing issue with collection and children mismatches --- lib/public/share.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/public/share.php b/lib/public/share.php index cda583aa073..920ce26700a 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -681,7 +681,8 @@ class Share { $collectionTypes[] = $type; } } - if (!self::getBackend($itemType) instanceof Share_Backend_Collection) { + // TODO Add option for collections to be collection of themselves, only 'folder' does it now... + if (!self::getBackend($itemType) instanceof Share_Backend_Collection || $itemType != 'folder') { unset($collectionTypes[0]); } // Return array if collections were found or the item type is a collection itself From 59ca312263d358c95b950266c678c71bf97716f3 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Wed, 23 Jan 2013 19:24:26 +0000 Subject: [PATCH 005/131] Work on util: findFiles() and encryptAll(); both close to working Ecnryption unit tests are failing, recursion in filecache{} --- apps/files_encryption/appinfo/app.php | 6 +- apps/files_encryption/lib/crypt.php | 4 +- apps/files_encryption/lib/keymanager.php | 112 +++++++------ apps/files_encryption/lib/proxy.php | 10 +- apps/files_encryption/lib/util.php | 157 +++++++++++++----- .../templates/settings-personal.php | 13 +- apps/files_encryption/templates/settings.php | 63 +------ apps/files_encryption/test/crypt.php | 6 +- apps/files_encryption/test/util.php | 23 ++- 9 files changed, 213 insertions(+), 181 deletions(-) diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index cc78402d1d0..fa293f45128 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -32,7 +32,7 @@ if ( && OCA\Encryption\Crypt::mode() == 'server' ) { - // Force the user to re-log in if the encryption key isn't unlocked + // Force the user to log-in again if the encryption key isn't unlocked // (happens when a user is logged in before the encryption app is // enabled) OCP\User::logout(); @@ -44,4 +44,6 @@ if ( } OCP\App::registerAdmin( 'files_encryption', 'settings' ); -OCP\App::registerPersonal( 'files_encryption', 'settings-personal' ); \ No newline at end of file + +// This is disabled until client-side encryption is supported: +// OCP\App::registerPersonal( 'files_encryption', 'settings-personal' ); \ No newline at end of file diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 642187b9103..2591e90227a 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -130,7 +130,7 @@ class Crypt { * @return true / false * @note see also OCA\Encryption\Util->isEncryptedPath() */ - public static function isEncryptedContent( $content ) { + public static function isCatfile( $content ) { if ( !$content ) { @@ -192,7 +192,7 @@ class Crypt { $content and isset( $metadata['encrypted'] ) and $metadata['encrypted'] === true - and !self::isEncryptedContent( $content ) + and !self::isCatfile( $content ) ) { return true; diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 61bc50721ef..c6669081a20 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -146,10 +146,59 @@ class Keymanager { } + /** + * @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 ); + +// // update $keytarget and $userId if key belongs to a file shared by someone else +// $query = $dbClassName::prepare( "SELECT uid_owner, source, target FROM `*PREFIX*sharing` WHERE target = ? AND uid_shared_with = ?" ); +// +// $result = $query->execute( array ( '/'.$userId.'/files/'.$targetPath, $userId ) ); +// +// if ( $row = $result->fetchRow( ) ) { +// +// $targetPath = $row['source']; +// +// $targetPath_parts = explode( '/', $targetPath ); +// +// $userId = $targetPath_parts[1]; +// +// $rootview = new \OC_FilesystemView( '/' ); +// +// if ( ! $rootview->is_writable( $targetPath ) ) { +// +// \OC_Log::write( 'Encryption library', "File Key not updated because you don't have write access for the corresponding file", \OC_Log::ERROR ); +// +// return false; +// +// } +// +// $targetPath = str_replace( '/'.$userId.'/files/', '', $targetPath ); +// +// //TODO: check for write permission on shared file once the new sharing API is in place +// +// } + + // Save the keyfile in parallel directory + return $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); + + } + /** * @brief retrieve keyfile for an encrypted file * @param string file name - * @return string file key or false + * @return string file key or false on failure * @note The keyfile returned is asymmetrically encrypted. Decryption * of the keyfile must be performed by client code */ @@ -171,7 +220,17 @@ class Keymanager { // // } - return $view->file_get_contents( '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key' ); + $catfilePath = '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key'; + + if ( $view->file_exists( $catfilePath ) ) { + + return $view->file_get_contents( $catfilePath ); + + } else { + + return false; + + } } @@ -298,55 +357,6 @@ class Keymanager { } - /** - * @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 ); - -// // update $keytarget and $userId if key belongs to a file shared by someone else -// $query = $dbClassName::prepare( "SELECT uid_owner, source, target FROM `*PREFIX*sharing` WHERE target = ? AND uid_shared_with = ?" ); -// -// $result = $query->execute( array ( '/'.$userId.'/files/'.$targetPath, $userId ) ); -// -// if ( $row = $result->fetchRow( ) ) { -// -// $targetPath = $row['source']; -// -// $targetPath_parts = explode( '/', $targetPath ); -// -// $userId = $targetPath_parts[1]; -// -// $rootview = new \OC_FilesystemView( '/' ); -// -// if ( ! $rootview->is_writable( $targetPath ) ) { -// -// \OC_Log::write( 'Encryption library', "File Key not updated because you don't have write access for the corresponding file", \OC_Log::ERROR ); -// -// return false; -// -// } -// -// $targetPath = str_replace( '/'.$userId.'/files/', '', $targetPath ); -// -// //TODO: check for write permission on shared file once the new sharing API is in place -// -// } - - // Save the keyfile in parallel directory - return $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); - - } - /** * @brief change password of private encryption key * diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 83c5e21c4bd..6f00bd13b46 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -68,7 +68,7 @@ class Proxy extends \OC_FileProxy { } - if ( Crypt::isEncryptedContent( $path ) ) { + if ( Crypt::isCatfile( $path ) ) { return true; @@ -147,7 +147,7 @@ class Proxy extends \OC_FileProxy { // If data is a catfile if ( Crypt::mode() == 'server' - && Crypt::isEncryptedContent( $data ) + && Crypt::isCatfile( $data ) ) { $split = explode( '/', $path ); @@ -269,14 +269,14 @@ class Proxy extends \OC_FileProxy { } public function postGetMimeType($path,$mime){ - if( Crypt::isEncryptedContent($path)){ + if( Crypt::isCatfile($path)){ $mime = \OCP\Files::getMimeType('crypt://'.$path,'w'); } return $mime; } public function postStat($path,$data){ - if( Crypt::isEncryptedContent($path)){ + if( Crypt::isCatfile($path)){ $cached= \OC_FileCache_Cached::get($path,''); $data['size']=$cached['size']; } @@ -284,7 +284,7 @@ class Proxy extends \OC_FileProxy { } public function postFileSize($path,$size){ - if( Crypt::isEncryptedContent($path)){ + if( Crypt::isCatfile($path)){ $cached = \OC_FileCache_Cached::get($path,''); return $cached['size']; }else{ diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 56e4d572c24..f70839e39fb 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -94,6 +94,7 @@ class Util { private $view; // OC_FilesystemView object for filesystem operations + private $userId; // ID of the currently logged-in user private $pwd; // User Password private $client; // Client side encryption mode flag private $publicKeyDir; // Dir containing all public user keys @@ -108,6 +109,8 @@ class Util { $this->view = $view; $this->userId = $userId; $this->client = $client; + $this->userDir = '/' . $this->userId; + $this->userFilesDir = '/' . $this->userId . '/' . 'files'; $this->publicKeyDir = '/' . 'public-keys'; $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption'; $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; @@ -120,7 +123,9 @@ class Util { public function ready() { if( - !$this->view->file_exists( $this->keyfilesPath ) + !$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 ) ) { @@ -141,6 +146,20 @@ class Util { */ public function setupServerSide( $passphrase = null ) { + // Create user dir + if( !$this->view->file_exists( $this->userDir ) ) { + + $this->view->mkdir( $this->userDir ); + + } + + // 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 ) ) { @@ -171,13 +190,13 @@ class Util { // Create user keypair if ( - !$this->view->file_exists( $this->publicKeyPath ) - or !$this->view->file_exists( $this->privateKeyPath ) + ! $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 @@ -193,52 +212,71 @@ class Util { } + $publicKey = Keymanager::getPublicKey( $this->view, $this->userId ); + + // Encrypt existing user files: + $this->encryptAll( $publicKey, $this->userFilesDir ); + return true; } - public function findFiles( $directory, $type = 'plain' ) { - - # TODO: test finding non plain content + /** + * @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 + */ + public function findFiles( $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 ) + ) { - if ( $handle = $this->view->opendir( $directory ) ) { - while ( false !== ( $file = readdir( $handle ) ) ) { - + if ( $file != "." && $file != ".." ) { - + $filePath = $directory . '/' . $this->view->getRelativePath( '/' . $file ); - var_dump($filePath); - + // If the path is a directory, search + // its contents if ( $this->view->is_dir( $filePath ) ) { $this->findFiles( $filePath ); - + + // If the path is a file, determine + // its encryption status } elseif ( $this->view->is_file( $filePath ) ) { - - if ( $type == 'plain' ) { - - $this->files[] = array( 'name' => $file, 'path' => $filePath ); - - } elseif ( $type == 'encrypted' ) { - if ( Crypt::isEncryptedContent( $this->view->file_get_contents( $filePath ) ) ) { - - $this->files[] = array( 'name' => $file, 'path' => $filePath ); - - } + // Disable proxies again, some- + // how they get re-enabled :/ + \OC_FileProxy::$enabled = false; - } elseif ( $type == 'legacy' ) { + // If the file is encrypted + if ( Keymanager::getFileKey( $this->view, $this->userId, $file ) ) { - if ( Crypt::isLegacyEncryptedContent( $this->view->file_get_contents( $filePath ) ) ) { + $found['encrypted'][] = array( 'name' => $file, 'path' => $filePath ); + + // If the file uses old + // encryption system + } elseif ( Crypt::isLegacyEncryptedContent( $this->view->file_get_contents( $filePath ) ) ) { - $this->files[] = 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' => $filePath ); } @@ -248,18 +286,22 @@ class Util { } - if ( !empty( $this->files ) ) { + \OC_FileProxy::$enabled = true; - return $this->files; + if ( empty( $found ) ) { + + return false; } else { - return false; + return $found; } } + \OC_FileProxy::$enabled = true; + return false; } @@ -278,22 +320,55 @@ class Util { \OC_FileProxy::$enabled = true; - return Crypt::isEncryptedContent( $data ); + return Crypt::isCatfile( $data ); } - public function encryptAll( $directory ) { + /** + * @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 ) { - $plainFiles = $this->findFiles( $this->view, 'plain' ); + if ( $found = $this->findFiles( $dirPath ) ) { - if ( $this->encryptFiles( $plainFiles ) ) { - - return true; + // Encrypt unencrypted files + foreach ( $found['plain'] as $plainFilePath ) { - } else { - - return false; + // Fetch data from file + $plainData = $this->view->file_get_contents( $plainFilePath ); + + // Encrypt data, generate catfile + $encrypted = Crypt::keyEncryptKeyfile( $plainData, $publicKey ); + + // Save catfile + Keymanager::setFileKey( $this->view, $plainFilePath, $this->userId, $encrypted['key'] ); + + // Overwrite the existing file with the encrypted one + $this->view->file_put_contents( $plainFilePath, $encrypted['data'] ); + } + + // FIXME: Legacy recrypting here isn't finished yet + // Encrypt legacy encrypted files + foreach ( $found['legacy'] as $legacyFilePath ) { + + // Fetch data from file + $legacyData = $this->view->file_get_contents( $legacyFilePath ); + + // Recrypt data, generate catfile + $recrypted = Crypt::legacyKeyRecryptKeyfile( $legacyData, $legacyPassphrase, $publicKey, $newPassphrase ); + + // Save catfile + Keymanager::setFileKey( $this->view, $plainFilePath, $this->userId, $recrypted['key'] ); + + // Overwrite the existing file with the encrypted one + $this->view->file_put_contents( $plainFilePath, $recrypted['data'] ); + + } + } } diff --git a/apps/files_encryption/templates/settings-personal.php b/apps/files_encryption/templates/settings-personal.php index 1274bd3bb5c..c8144da5633 100644 --- a/apps/files_encryption/templates/settings-personal.php +++ b/apps/files_encryption/templates/settings-personal.php @@ -9,17 +9,6 @@ value="" > - - /> - t('Client side encryption (most secure but makes it impossible to access your data from the web interface)'); ?> -
- /> - t('Server side encryption (allows you to access your files from the web interface and the desktop client)'); ?> + t('Server side encryption (allows you to access your files from the web interface)'); ?>
- - t('Choose encryption mode:'); ?> - - -

- - t('Important: Once you selected an encryption mode there is no way to change it back'); ?> - -

- -

- - /> - - t("Client side encryption (most secure but makes it impossible to access your data from the web interface)"); ?> -
- - - /> - - t('Server side encryption (allows you to access your files from the web interface and the desktop client)'); ?> -
- - - /> - - t('User specific (let the user decide)'); ?> -
- - - /> - - t('None (no encryption at all)'); ?> -
- -

t('Encryption'); ?> - t("Exclude the following file types from encryption"); ?> + t("Exclude the following file types from encryption:"); ?> +
+ style="width:20px;" /> - t('Server side encryption (allows you to access your files from the web interface)'); ?> + t( 'Server side encryption (allows you to access your files from the web interface)' ); ?>
+ /> - t('None (no encryption at all)'); ?> + t( 'None (no encryption at all)' ); ?>

diff --git a/apps/files_encryption/templates/settings.php b/apps/files_encryption/templates/settings.php index 17ac1fd224f..f7ef8a8efe6 100644 --- a/apps/files_encryption/templates/settings.php +++ b/apps/files_encryption/templates/settings.php @@ -2,17 +2,17 @@

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

From 825cdf8560e6b9f6dda9debdd271494fdfd3fcf7 Mon Sep 17 00:00:00 2001 From: Thomas Mueller Date: Tue, 29 Jan 2013 17:28:08 +0100 Subject: [PATCH 007/131] add support for apps to register alternative login methods below the standard login a list of icons/button will be displayed --- core/templates/login.php | 16 +++++++++++++++- lib/app.php | 9 +++++++++ lib/util.php | 2 ++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/core/templates/login.php b/core/templates/login.php index c82d2cafa2e..7616b93f9a5 100644 --- a/core/templates/login.php +++ b/core/templates/login.php @@ -41,5 +41,19 @@
- + +
+
+ t('Alternative Logins:') ?> +
    + +
  • + +
+
+
+ + + Date: Tue, 29 Jan 2013 19:54:40 +0000 Subject: [PATCH 008/131] Made encyrption keyfiles be deleted when their parents are Made encryption keyfiles be renamed when their parents are Fixed bugs with encryptAll() execution on login --- apps/files_encryption/appinfo/spec.txt | 12 +++++ apps/files_encryption/hooks/hooks.php | 15 ++++-- apps/files_encryption/lib/keymanager.php | 44 ++++++++-------- apps/files_encryption/lib/proxy.php | 67 ++++++++++++++++++++++++ apps/files_encryption/lib/util.php | 38 +++++++++++--- 5 files changed, 142 insertions(+), 34 deletions(-) diff --git a/apps/files_encryption/appinfo/spec.txt b/apps/files_encryption/appinfo/spec.txt index ab248be64d5..2d22dffe08d 100644 --- a/apps/files_encryption/appinfo/spec.txt +++ b/apps/files_encryption/appinfo/spec.txt @@ -1,3 +1,15 @@ +Encrypted files +--------------- + +- Each encrypted file has at least two components: the encrypted data file + ('catfile'), and it's corresponding key file ('keyfile'). Shared files have an + additional key file ('share key'). The catfile contains the encrypted data + concatenated with delimiter text, followed by the initialisation vector ('IV'), + and padding. e.g.: + + [encrypted data string][delimiter][IV][padding] + [anhAAjAmcGXqj1X9g==][00iv00][MSHU5N5gECP7aAg7][xx] (square braces added) + Notes ----- diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 73d7957541a..dafa14fc000 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -37,8 +37,6 @@ class Hooks { * @note This method should never be called for users using client side encryption */ public static function login( $params ) { - - // TODO: use lots of dependency injection here $view = new \OC_FilesystemView( '/' ); @@ -83,8 +81,17 @@ class Hooks { // Encrypt existing user files: // This serves to upgrade old versions of the encryption - // app (see appinfo/spec.txt - $this->encryptAll( $publicKey, $this->userFilesDir, $session->getLegacyKey(), $params['password'] ); + // app (see appinfo/spec.txt) + if ( + $util->encryptAll( $publicKey, '/' . $params['uid'] . '/' . 'files', $session->getLegacyKey(), $params['password'] ) + ) { + + \OC_Log::write( + 'Encryption library', 'Encryption of file belonging to "' . $params['uid'] . '" was started at login' + , \OC_Log::INFO + ); + + } return true; diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 301e5b33fd8..8656bb96758 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -234,33 +234,33 @@ class Keymanager { } /** - * @brief retrieve file encryption key + * @brief Delete a keyfile * - * @param string file name - * @return string file key or false + * @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( $path, $staticUserClass = 'OCP\User' ) { + public static function deleteFileKey( \OC_FilesystemView $view, $userId, $path ) { - $keypath = ltrim( $path, '/' ); - $user = $staticUserClass::getUser(); - - // update $keypath and $user if path point to a file shared by someone else -// $query = \OC_DB::prepare( "SELECT uid_owner, source, target FROM `*PREFIX*sharing` WHERE target = ? AND uid_shared_with = ?" ); -// -// $result = $query->execute( array ('/'.$user.'/files/'.$keypath, $user)); -// -// if ($row = $result->fetchRow()) { -// -// $keypath = $row['source']; -// $keypath_parts = explode( '/', $keypath ); -// $user = $keypath_parts[1]; -// $keypath = str_replace( '/' . $user . '/files/', '', $keypath ); -// -// } + $trimmed = ltrim( $path, '/' ); + $keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed . '.key'; - $view = new \OC_FilesystemView( '/' . $user. '/files_encryption/keyfiles/' ); + // 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 . '.key' ); + return $view->unlink( $keyPath ); + + } else { + + \OC_Log::write( 'Encryption library', 'Could not delete keyfile; does not exist: "' . $keyPath, \OC_Log::ERROR ); + + return false; + + } } diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 025af3c7f14..6d2a574abd2 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -192,6 +192,73 @@ class Proxy extends \OC_FileProxy { } + /** + * @brief When a file is deleted, remove its keyfile also + */ + public function postUnlink( $path ) { + + // Disable encryption proxy to prevent recursive calls + \OC_FileProxy::$enabled = false; + + $view = new \OC_FilesystemView( '/' ); + + $userId = \OCP\USER::getUser(); + + // Format path to be relative to user files dir + $trimmed = ltrim( $path, '/' ); + $split = explode( '/', $trimmed ); + $sliced = array_slice( $split, 2 ); + $relPath = implode( '/', $sliced ); + + // Delete keyfile so it isn't orphaned + $result = Keymanager::deleteFileKey( $view, $userId, $relPath ); + + \OC_FileProxy::$enabled = true; + + 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 preRename( $oldPath, $newPath ) { + +// trigger_error( "PATHS = ".var_export($oldPath, 1).' '.var_export($newPath, 1)); + + // 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'; + +// trigger_error("RENAMING = ".var_export($oldKeyfilePath, 1).' -> '.var_export($newKeyfilePath, 1)); + + // 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 ) { diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index fd4d7a9fcc6..2a69bba43c9 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -225,6 +225,9 @@ 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 */ public function findFiles( $directory ) { @@ -293,7 +296,7 @@ class Util { return false; } else { - + return $found; } @@ -334,20 +337,29 @@ class Util { if ( $found = $this->findFiles( $dirPath ) ) { + // Disable proxy to prevent file being encrypted twice + \OC_FileProxy::$enabled = false; + // Encrypt unencrypted files - foreach ( $found['plain'] as $plainFilePath ) { - + foreach ( $found['plain'] as $plainFile ) { + // Fetch data from file - $plainData = $this->view->file_get_contents( $plainFilePath ); + $plainData = $this->view->file_get_contents( $plainFile['path'] ); // Encrypt data, generate catfile $encrypted = Crypt::keyEncryptKeyfile( $plainData, $publicKey ); + // Format path to be relative to user files dir + $trimmed = ltrim( $plainFile['path'], '/' ); + $split = explode( '/', $trimmed ); + $sliced = array_slice( $split, 2 ); + $relPath = implode( '/', $sliced ); + // Save catfile - Keymanager::setFileKey( $this->view, $plainFilePath, $this->userId, $encrypted['key'] ); + Keymanager::setFileKey( $this->view, $relPath, $this->userId, $encrypted['key'] ); // Overwrite the existing file with the encrypted one - $this->view->file_put_contents( $plainFilePath, $encrypted['data'] ); + $this->view->file_put_contents( $plainFile['path'], $encrypted['data'] ); } @@ -367,15 +379,25 @@ class Util { $recrypted = Crypt::legacyKeyRecryptKeyfile( $legacyData, $legacyPassphrase, $publicKey, $newPassphrase ); // Save catfile - Keymanager::setFileKey( $this->view, $plainFilePath, $this->userId, $recrypted['key'] ); + Keymanager::setFileKey( $this->view, $plainFile['path'], $this->userId, $recrypted['key'] ); // Overwrite the existing file with the encrypted one - $this->view->file_put_contents( $plainFilePath, $recrypted['data'] ); + $this->view->file_put_contents( $plainFile['path'], $recrypted['data'] ); } } + + \OC_FileProxy::$enabled = true; + + // If files were found, return true + return true; + } else { + + // If no files were found, return false + return false; + } } From 0067ac6ca6389b61917cd7a19e7772e68ea78e8a Mon Sep 17 00:00:00 2001 From: Lukas Reschke Date: Wed, 30 Jan 2013 00:16:37 +0100 Subject: [PATCH 009/131] Remove the no longer existing function "isUserVerified" Thx @eMerzh --- settings/ajax/changepassword.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/settings/ajax/changepassword.php b/settings/ajax/changepassword.php index 8d45e62e4d8..f6fa38fd9ba 100644 --- a/settings/ajax/changepassword.php +++ b/settings/ajax/changepassword.php @@ -15,14 +15,8 @@ if(OC_User::isAdminUser(OC_User::getUser())) { if(OC_SubAdmin::isUserAccessible(OC_User::getUser(), $username)) { $userstatus = 'subadmin'; } -if(OC_User::getUser() === $username) { - if (OC_User::checkPassword($username, $oldPassword)) { +if(OC_User::getUser() === $username && OC_User::checkPassword($username, $oldPassword)) { $userstatus = 'user'; - } else { - if (!OC_Util::isUserVerified()) { - $userstatus = null; - } - } } if(is_null($userstatus)) { From a7aff48658d66f9bd0df891be6bbbf9e11b2d20a Mon Sep 17 00:00:00 2001 From: Lukas Reschke Date: Wed, 30 Jan 2013 00:17:41 +0100 Subject: [PATCH 010/131] Fix indentation --- settings/ajax/changepassword.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings/ajax/changepassword.php b/settings/ajax/changepassword.php index f6fa38fd9ba..c1ff0a63701 100644 --- a/settings/ajax/changepassword.php +++ b/settings/ajax/changepassword.php @@ -16,7 +16,7 @@ if(OC_SubAdmin::isUserAccessible(OC_User::getUser(), $username)) { $userstatus = 'subadmin'; } if(OC_User::getUser() === $username && OC_User::checkPassword($username, $oldPassword)) { - $userstatus = 'user'; + $userstatus = 'user'; } if(is_null($userstatus)) { From 61b23ce6cc4c9e21da1dd161f11fc15b878027fd Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Wed, 30 Jan 2013 17:25:17 +0000 Subject: [PATCH 011/131] Working on support for deleting directories (removing all keyfiles) --- apps/files_encryption/lib/proxy.php | 32 +++++++++++++++++------------ 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 6d2a574abd2..9e1dbfe0d37 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -195,27 +195,37 @@ class Proxy extends \OC_FileProxy { /** * @brief When a file is deleted, remove its keyfile also */ - public function postUnlink( $path ) { + public function preUnlink( $path ) { // Disable encryption proxy to prevent recursive calls \OC_FileProxy::$enabled = false; $view = new \OC_FilesystemView( '/' ); - $userId = \OCP\USER::getUser(); - // Format path to be relative to user files dir $trimmed = ltrim( $path, '/' ); $split = explode( '/', $trimmed ); $sliced = array_slice( $split, 2 ); $relPath = implode( '/', $sliced ); - - // Delete keyfile so it isn't orphaned - $result = Keymanager::deleteFileKey( $view, $userId, $relPath ); - - \OC_FileProxy::$enabled = true; - return $result; + if ( $view->is_dir( $path ) ) { + + // Dirs must be handled separately as deleteFileKey + // doesn't handle them + $view->unlink( 'files_encryption/keyfiles/'. $relPath ); + + } else { + + $userId = \OCP\USER::getUser(); + + // Delete keyfile so it isn't orphaned + $result = Keymanager::deleteFileKey( $view, $userId, $relPath ); + + \OC_FileProxy::$enabled = true; + + return $result; + + } } @@ -225,8 +235,6 @@ class Proxy extends \OC_FileProxy { * @note This is pre rather than post because using post didn't work */ public function preRename( $oldPath, $newPath ) { - -// trigger_error( "PATHS = ".var_export($oldPath, 1).' '.var_export($newPath, 1)); // Disable encryption proxy to prevent recursive calls \OC_FileProxy::$enabled = false; @@ -248,8 +256,6 @@ class Proxy extends \OC_FileProxy { $newRelPath = implode( '/', $newSliced ); $newKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $newRelPath . '.key'; -// trigger_error("RENAMING = ".var_export($oldKeyfilePath, 1).' -> '.var_export($newKeyfilePath, 1)); - // Rename keyfile so it isn't orphaned $result = $view->rename( $oldKeyfilePath, $newKeyfilePath ); From c7b1bdf00e65cca2a42d77fc5f27d0ea69e53be3 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Wed, 30 Jan 2013 18:52:02 +0000 Subject: [PATCH 012/131] Fixed handling of keyfile subdir creation Improved keyfile subdir deletion (1 bug remains here) --- apps/files_encryption/lib/keymanager.php | 94 ++++-------------------- apps/files_encryption/lib/proxy.php | 12 ++- 2 files changed, 23 insertions(+), 83 deletions(-) diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 8656bb96758..43af70dacc2 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -83,38 +83,7 @@ class Keymanager { // Check if sharing is enabled if ( OC_App::isEnabled( 'files_sharing' ) ) { -// // Check if file was shared with other users -// $query = \OC_DB::prepare( " -// SELECT -// uid_owner -// , source -// , target -// , uid_shared_with -// FROM -// `*PREFIX*sharing` -// WHERE -// ( target = ? AND uid_shared_with = ? ) -// OR source = ? -// " ); -// -// $result = $query->execute( array ( $filepath, $userId, $filepath ) ); -// -// $users = array(); -// -// if ( $row = $result->fetchRow() ) -// { -// $source = $row['source']; -// $owner = $row['uid_owner']; -// $users[] = $owner; -// // get the uids of all user with access to the file -// $query = \OC_DB::prepare( "SELECT source, uid_shared_with FROM `*PREFIX*sharing` WHERE source = ?" ); -// $result = $query->execute( array ($source)); -// while ( ($row = $result->fetchRow()) ) { -// $users[] = $row['uid_shared_with']; -// -// } -// -// } + } else { @@ -160,37 +129,16 @@ class Keymanager { $targetPath = self::keySetPreparation( $view, $path, $basePath, $userId ); -// // update $keytarget and $userId if key belongs to a file shared by someone else -// $query = $dbClassName::prepare( "SELECT uid_owner, source, target FROM `*PREFIX*sharing` WHERE target = ? AND uid_shared_with = ?" ); -// -// $result = $query->execute( array ( '/'.$userId.'/files/'.$targetPath, $userId ) ); -// -// if ( $row = $result->fetchRow( ) ) { -// -// $targetPath = $row['source']; -// -// $targetPath_parts = explode( '/', $targetPath ); -// -// $userId = $targetPath_parts[1]; -// -// $rootview = new \OC_FilesystemView( '/' ); -// -// if ( ! $rootview->is_writable( $targetPath ) ) { -// -// \OC_Log::write( 'Encryption library', "File Key not updated because you don't have write access for the corresponding file", \OC_Log::ERROR ); -// -// return false; -// -// } -// -// $targetPath = str_replace( '/'.$userId.'/files/', '', $targetPath ); -// -// //TODO: check for write permission on shared file once the new sharing API is in place -// -// } + if ( $view->is_dir( $basePath . '/' . $targetPath ) ) { - // Save the keyfile in parallel directory - return $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); + + + } else { + + // Save the keyfile in parallel directory + return $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); + + } } @@ -204,21 +152,7 @@ class Keymanager { public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) { $filePath_f = ltrim( $filePath, '/' ); - -// // update $keypath and $userId if path point to a file shared by someone else -// $query = \OC_DB::prepare( "SELECT uid_owner, source, target FROM `*PREFIX*sharing` WHERE target = ? AND uid_shared_with = ?" ); -// -// $result = $query->execute( array ('/'.$userId.'/files/'.$keypath, $userId)); -// -// if ($row = $result->fetchRow()) { -// -// $keypath = $row['source']; -// $keypath_parts = explode( '/', $keypath ); -// $userId = $keypath_parts[1]; -// $keypath = str_replace( '/' . $userId . '/files/', '', $keypath ); -// -// } - + $catfilePath = '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key'; if ( $view->file_exists( $catfilePath ) ) { @@ -337,7 +271,7 @@ 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 ); @@ -345,10 +279,10 @@ class Keymanager { // If the file resides within a subdirectory, create it if ( isset( $path_parts['dirname'] ) - && ! $view->file_exists( $basePath . $path_parts['dirname'] ) + && ! $view->file_exists( $basePath . '/' . $path_parts['dirname'] ) ) { - $view->mkdir( $basePath . $path_parts['dirname'] ); + $view->mkdir( $basePath . '/' . $path_parts['dirname'] ); } diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 9e1dbfe0d37..f7245d11cf5 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -22,6 +22,12 @@ * */ +/** +* @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 { @@ -202,6 +208,8 @@ class Proxy extends \OC_FileProxy { $view = new \OC_FilesystemView( '/' ); + $userId = \OCP\USER::getUser(); + // Format path to be relative to user files dir $trimmed = ltrim( $path, '/' ); $split = explode( '/', $trimmed ); @@ -212,11 +220,9 @@ class Proxy extends \OC_FileProxy { // Dirs must be handled separately as deleteFileKey // doesn't handle them - $view->unlink( 'files_encryption/keyfiles/'. $relPath ); + $view->unlink( $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/'. $relPath ); } else { - - $userId = \OCP\USER::getUser(); // Delete keyfile so it isn't orphaned $result = Keymanager::deleteFileKey( $view, $userId, $relPath ); From 2183f77527fa027a4bf86d8eb2229092605d6827 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Thu, 31 Jan 2013 16:49:07 +0000 Subject: [PATCH 013/131] Fixed incompatibilities with filecache rewrite merge --- apps/files_encryption/lib/crypt.php | 6 +++--- apps/files_encryption/lib/proxy.php | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 9d4f5a1fae0..106b757307d 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -170,10 +170,10 @@ class Crypt { */ public static function isEncryptedMeta( $path ) { - // TODO: Use DI to get OC_FileCache_Cached out of here + // TODO: Use DI to get \OC\Files\Filesystem out of here // Fetch all file metadata from DB - $metadata = \OC_FileCache_Cached::get( $path, '' ); + $metadata = \OC\Files\Filesystem::getFileInfo( $path, '' ); // Return encryption status return isset( $metadata['encrypted'] ) and ( bool )$metadata['encrypted']; @@ -187,7 +187,7 @@ class Crypt { public static function isLegacyEncryptedContent( $content ) { // Fetch all file metadata from DB - $metadata = \OC_FileCache_Cached::get( $content, '' ); + $metadata = \OC\Files\Filesystem::getFileInfo( $content, '' ); // If a file is flagged with encryption in DB, but isn't a // valid content + IV combination, it's probably using the diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index f7245d11cf5..55cddf2bec8 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -129,7 +129,7 @@ class Proxy extends \OC_FileProxy { Keymanager::setFileKey( $view, $filePath, $userId, $encrypted['key'] ); // Update the file cache with file info - \OC_FileCache::put( $path, array( 'encrypted'=>true, 'size' => $size ), '' ); + \OC\Files\Filesystem::putFileInfo( $path, array( 'encrypted'=>true, 'size' => $size ), '' ); // Re-enable proxy - our work is done \OC_FileProxy::$enabled = true; @@ -162,7 +162,7 @@ class Proxy extends \OC_FileProxy { $filePath = '/' . implode( '/', $filePath ); - //$cached = \OC_FileCache_Cached::get( $path, '' ); + //$cached = \OC\Files\Filesystem::getFileInfo( $path, '' ); $view = new \OC_FilesystemView( '' ); @@ -363,7 +363,7 @@ class Proxy extends \OC_FileProxy { if ( Crypt::isCatfile( $path ) ) { - $cached = \OC_FileCache_Cached::get( $path, '' ); + $cached = \OC\Files\Filesystem::getFileInfo( $path, '' ); $data['size'] = $cached['size']; @@ -376,7 +376,7 @@ class Proxy extends \OC_FileProxy { if ( Crypt::isCatfile( $path ) ) { - $cached = \OC_FileCache_Cached::get( $path, '' ); + $cached = \OC\Files\Filesystem::getFileInfo( $path, '' ); return $cached['size']; From c6b3bdd5a0f6651c557c6653b49acd005bbadba8 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Thu, 31 Jan 2013 17:47:30 +0000 Subject: [PATCH 014/131] Fixed compatibility with filecache rewrite merge --- apps/files_encryption/lib/stream.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index f634db7a385..4102a681d7f 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -484,7 +484,7 @@ class Stream { and $this->meta['mode']!='rb' ) { - \OC_FileCache::put( $this->path, array( 'encrypted' => true, 'size' => $this->size ), '' ); + \OC\Files\Filesystem::putFileInfo( $this->path, array( 'encrypted' => true, 'size' => $this->size ), '' ); } From 06847f609b09f118b552d70e6f837a92008db570 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Thu, 31 Jan 2013 19:40:51 +0000 Subject: [PATCH 015/131] Improved support for detecting and recrypting legacy files. Bugs remain. --- apps/files_encryption/hooks/hooks.php | 4 +-- apps/files_encryption/lib/crypt.php | 13 +++++----- apps/files_encryption/lib/session.php | 2 +- apps/files_encryption/lib/util.php | 35 +++++++++++++++++++++------ 4 files changed, 37 insertions(+), 17 deletions(-) diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index dafa14fc000..cb9993b2389 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -70,7 +70,7 @@ class Hooks { $view1->file_exists( 'encryption.key' ) && $encLegacyKey = $view1->file_get_contents( 'encryption.key' ) ) { - + $plainLegacyKey = Crypt::legacyDecrypt( $encLegacyKey, $params['password'] ); $session->setLegacyKey( $plainLegacyKey ); @@ -87,7 +87,7 @@ class Hooks { ) { \OC_Log::write( - 'Encryption library', 'Encryption of file belonging to "' . $params['uid'] . '" was started at login' + 'Encryption library', 'Encryption of existing files belonging to "' . $params['uid'] . '" started at login' , \OC_Log::INFO ); diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 106b757307d..6fbbd412b89 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -184,19 +184,18 @@ class Crypt { * @brief Check if a file is encrypted via legacy system * @return true / false */ - public static function isLegacyEncryptedContent( $content ) { + public static function isLegacyEncryptedContent( $data, $path ) { // Fetch all file metadata from DB - $metadata = \OC\Files\Filesystem::getFileInfo( $content, '' ); - + $metadata = \OC\Files\Filesystem::getFileInfo( $path, '' ); + // 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 ( - $content - and isset( $metadata['encrypted'] ) - and $metadata['encrypted'] === true - and ! self::isCatfile( $content ) + isset( $metadata['encrypted'] ) + and $metadata['encrypted'] === true + and ! self::isCatfile( $data ) ) { return true; diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index 4abc8be689f..bda22ee3a03 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -70,7 +70,7 @@ class Session { */ public function setLegacyKey( $legacyKey ) { - $_SESSION['legacyKey'] = $LegacyKey; + $_SESSION['legacyKey'] = $legacyKey; return true; diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 2a69bba43c9..b1c128cf8c4 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -37,8 +37,9 @@ namespace OCA\Encryption; /** * @brief Class for utilities relating to encrypted file storage system - * @param $view OC_FilesystemView object, expected to have OC '/' as root path - * @param $client flag indicating status of client side encryption. Currently + * @param OC_FilesystemView $view expected to have OC '/' as root path + * @param string $userId ID of the logged in user + * @param int $client indicating status of client side encryption. Currently * unused, likely to become obsolete shortly */ @@ -262,17 +263,25 @@ class Util { } elseif ( $this->view->is_file( $filePath ) ) { // Disable proxies again, some- - // how they get re-enabled :/ + // where they got re-enabled :/ \OC_FileProxy::$enabled = false; + $data = $this->view->file_get_contents( $filePath ); + // If the file is encrypted - if ( Keymanager::getFileKey( $this->view, $this->userId, $file ) ) { + // NOTE: If the userId is + // empty or not set, file will + // detected as plain + if ( + Keymanager::getFileKey( $this->view, $this->userId, $file ) + && Crypt::isCatfile( $filePath ) + ) { $found['encrypted'][] = array( 'name' => $file, 'path' => $filePath ); // If the file uses old // encryption system - } elseif ( Crypt::isLegacyEncryptedContent( $this->view->file_get_contents( $filePath ) ) ) { + } elseif ( Crypt::isLegacyEncryptedContent( $this->view->file_get_contents( $filePath ), $filePath ) ) { $found['legacy'][] = array( 'name' => $file, 'path' => $filePath ); @@ -355,11 +364,16 @@ class Util { $sliced = array_slice( $split, 2 ); $relPath = implode( '/', $sliced ); - // Save catfile + // Save keyfile Keymanager::setFileKey( $this->view, $relPath, $this->userId, $encrypted['key'] ); // Overwrite the existing file with the encrypted one $this->view->file_put_contents( $plainFile['path'], $encrypted['data'] ); + + $size = strlen( $encrypted['data'] ); + + // Add the file to the cache + \OC\Files\Filesystem::putFileInfo( $plainFile['path'], array( 'encrypted'=>true, 'size' => $size ), '' ); } @@ -370,6 +384,8 @@ class Util { && ! empty( $newPassphrase ) ) { + trigger_error("LEGACY FOUND"); + foreach ( $found['legacy'] as $legacyFilePath ) { // Fetch data from file @@ -378,11 +394,16 @@ class Util { // Recrypt data, generate catfile $recrypted = Crypt::legacyKeyRecryptKeyfile( $legacyData, $legacyPassphrase, $publicKey, $newPassphrase ); - // Save catfile + // Save keyfile Keymanager::setFileKey( $this->view, $plainFile['path'], $this->userId, $recrypted['key'] ); // Overwrite the existing file with the encrypted one $this->view->file_put_contents( $plainFile['path'], $recrypted['data'] ); + + $size = strlen( $recrypted['data'] ); + + // Add the file to the cache + \OC\Files\Filesystem::putFileInfo( $plainFile['path'], array( 'encrypted'=>true, 'size' => $size ), '' ); } From 0677d56ee226b0ba884f3e175c86540dbab643a5 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Fri, 1 Feb 2013 19:31:15 +0000 Subject: [PATCH 016/131] Added debugging output relating to recrypting legacy files --- apps/files_encryption/lib/crypt.php | 8 +++++++- apps/files_encryption/lib/util.php | 11 +++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 6fbbd412b89..231bfd9826b 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -186,8 +186,14 @@ class Crypt { */ public static function isLegacyEncryptedContent( $data, $path ) { + $trimmed = ltrim( $path, '/' ); + +// trigger_error( "DATA = ".var_export($data, 1). " CATFILE?: ".var_export( self::isCatfile( $data ), 1)); + // Fetch all file metadata from DB - $metadata = \OC\Files\Filesystem::getFileInfo( $path, '' ); + $metadata = \OC\Files\Filesystem::getFileInfo( $trimmed, '' ); + + trigger_error("PATH = ". var_export($trimmed, 1)." METADATA = ".var_export($metadata['encrypted'], 1)); // If a file is flagged with encryption in DB, but isn't a // valid content + IV combination, it's probably using the diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index b1c128cf8c4..7e396a9145b 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -268,10 +268,15 @@ class Util { $data = $this->view->file_get_contents( $filePath ); +// trigger_error("HAKE \n".var_export($this->view->file_get_contents( $filePath ), 1)." \nfilepath = ".var_export($filePath, 1 )); + // If the file is encrypted // NOTE: If the userId is // empty or not set, file will // detected as plain + // NOTE: This is inefficient; + // scanning every file like this + // will eat server resources :( if ( Keymanager::getFileKey( $this->view, $this->userId, $file ) && Crypt::isCatfile( $filePath ) @@ -346,6 +351,8 @@ class Util { if ( $found = $this->findFiles( $dirPath ) ) { +// trigger_error("FOUND = ".print_r($found, 1)); + // Disable proxy to prevent file being encrypted twice \OC_FileProxy::$enabled = false; @@ -384,13 +391,13 @@ class Util { && ! empty( $newPassphrase ) ) { - trigger_error("LEGACY FOUND"); - foreach ( $found['legacy'] as $legacyFilePath ) { // Fetch data from file $legacyData = $this->view->file_get_contents( $legacyFilePath ); + trigger_error("\n\nlegdata = ".var_export($legacyData).' \n\npassphrase = '.var_export($legacyPassphrase).' \n\npublickey = '.var_export($publicKey).' \n\nnewpass = '.var_export($newPassphrase)); + // Recrypt data, generate catfile $recrypted = Crypt::legacyKeyRecryptKeyfile( $legacyData, $legacyPassphrase, $publicKey, $newPassphrase ); From 1557b6d99dd55bfd6b55eadf78cc954273bdcf54 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sun, 3 Feb 2013 14:44:33 +0100 Subject: [PATCH 017/131] Fix leftcontent positioning. Ref #1255 --- apps/files/css/files.css | 2 +- core/css/styles.css | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/files/css/files.css b/apps/files/css/files.css index 661a2e827a4..e18836a7389 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -55,7 +55,7 @@ font-size:1.5em; font-weight:bold; color:#888; text-shadow:#fff 0 1px 0; } -table { position:relative; top:37px; width:100%; } +table { position:relative; width:100%; } tbody tr { background-color:#fff; height:2.5em; } tbody tr:hover, tbody tr:active, tbody tr.selected { background-color:#f8f8f8; } tbody tr.selected { background-color:#eee; } diff --git a/core/css/styles.css b/core/css/styles.css index 19cfad76268..685a20ba081 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -119,7 +119,7 @@ input[type="submit"].enabled { background:#66f866; border:1px solid #5e5; -moz-b #select_all{ margin-top:.4em !important;} /* CONTENT ------------------------------------------------------------------ */ -#controls { padding:0 0.5em; width:100%; top:3.5em; height:2.8em; margin:0; background:#f7f7f7; border-bottom:1px solid #eee; position:fixed; z-index:50; -moz-box-shadow:0 -3px 7px #000; -webkit-box-shadow:0 -3px 7px #000; box-shadow:0 -3px 7px #000; } +#controls { padding:0 0.5em; width:100%; top:0; height:2.8em; margin:0; background:#f7f7f7; border-bottom:1px solid #eee; position:relative; z-index:50; -moz-box-shadow:0 -3px 7px #000; -webkit-box-shadow:0 -3px 7px #000; box-shadow:0 -3px 7px #000; } #controls .button { display:inline-block; } #content { position:relative; height:100%; width:100%; } @@ -128,9 +128,9 @@ input[type="submit"].enabled { background:#66f866; border:1px solid #5e5; -moz-b -moz-box-sizing:border-box; box-sizing:border-box; } #leftcontent, .leftcontent { - position:fixed; overflow:auto; top:0; width:20em; height:100%; + position:relative; overflow:auto; width:20em; height:100%; background:#f8f8f8; border-right:1px solid #ddd; - -moz-box-sizing:border-box; box-sizing:border-box; padding-top:6.4em; + -moz-box-sizing:border-box; box-sizing:border-box; } #leftcontent li, .leftcontent li { background:#f8f8f8; padding:.5em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 200ms; -moz-transition:background-color 200ms; -o-transition:background-color 200ms; transition:background-color 200ms; } #leftcontent li:hover, #leftcontent li:active, #leftcontent li.active, .leftcontent li:hover, .leftcontent li:active, .leftcontent li.active { background:#eee; } From 88ad1e5fbd2178c6281d060e9caa47837c447edf Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sun, 3 Feb 2013 16:02:25 +0100 Subject: [PATCH 018/131] Make app icon linkable when enabling app. --- settings/js/apps.js | 1 + 1 file changed, 1 insertion(+) diff --git a/settings/js/apps.js b/settings/js/apps.js index 8bee958ec57..912ae99016d 100644 --- a/settings/js/apps.js +++ b/settings/js/apps.js @@ -138,6 +138,7 @@ OC.Settings.Apps = OC.Settings.Apps || { li.append(img); var a=$('').attr('href', entry.href); a.text(entry.name); + a.prepend(img); li.append(a); container.append(li); } From bce59c39458c859d14978f255cf520f111ea78dd Mon Sep 17 00:00:00 2001 From: Lukas Reschke Date: Sun, 3 Feb 2013 19:58:55 +0100 Subject: [PATCH 019/131] [user_webdavauth] add requesttoken --- apps/user_webdavauth/settings.php | 4 +++- apps/user_webdavauth/templates/settings.php | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/user_webdavauth/settings.php b/apps/user_webdavauth/settings.php index 41d7fa51cd2..7eabb0d48cc 100755 --- a/apps/user_webdavauth/settings.php +++ b/apps/user_webdavauth/settings.php @@ -24,7 +24,9 @@ OC_Util::checkAdminUser(); if($_POST) { - + // CSRF check + OCP\JSON::callCheck(); + if(isset($_POST['webdav_url'])) { OC_CONFIG::setValue('user_webdavauth_url', strip_tags($_POST['webdav_url'])); } diff --git a/apps/user_webdavauth/templates/settings.php b/apps/user_webdavauth/templates/settings.php index 880b77ac959..45f4d81aecf 100755 --- a/apps/user_webdavauth/templates/settings.php +++ b/apps/user_webdavauth/templates/settings.php @@ -2,6 +2,7 @@
t('WebDAV Authentication');?>

+
t('ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials.'); ?>

From bb9be6f6294934f13ced6a5bc26d226159fada1d Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 4 Feb 2013 00:24:34 +0100 Subject: [PATCH 020/131] Add box-sizing to controls. --- core/css/styles.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/css/styles.css b/core/css/styles.css index 685a20ba081..80485fd063d 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -119,7 +119,7 @@ input[type="submit"].enabled { background:#66f866; border:1px solid #5e5; -moz-b #select_all{ margin-top:.4em !important;} /* CONTENT ------------------------------------------------------------------ */ -#controls { padding:0 0.5em; width:100%; top:0; height:2.8em; margin:0; background:#f7f7f7; border-bottom:1px solid #eee; position:relative; z-index:50; -moz-box-shadow:0 -3px 7px #000; -webkit-box-shadow:0 -3px 7px #000; box-shadow:0 -3px 7px #000; } +#controls { padding:0 0.5em; width:100%; top:0; height:2.8em; margin:0; background:#f7f7f7; border-bottom:1px solid #eee; position:relative; -moz-box-sizing:border-box; box-sizing:border-box; z-index:50; -moz-box-shadow:0 -3px 7px #000; -webkit-box-shadow:0 -3px 7px #000; box-shadow:0 -3px 7px #000; } #controls .button { display:inline-block; } #content { position:relative; height:100%; width:100%; } From 9060c3bd83f7fa3eeee2f5e303055c84e19f8f5b Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sun, 3 Feb 2013 17:12:57 +0100 Subject: [PATCH 021/131] Files: fix positioning of Trash button and upload progress bar --- apps/files/css/files.css | 4 ++-- apps/files/templates/index.php | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/files/css/files.css b/apps/files/css/files.css index e18836a7389..0a12439c359 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -23,7 +23,7 @@ #new>ul>li>p { cursor:pointer; } #new>ul>li>form>input { padding:0.3em; margin:-0.3em; } -#trash { height:17px; margin:0 0 0 1em; z-index:1010; position:absolute; right:13.5em; } +#trash { height:17px; margin:0.3em 0.3em 0.3em 1em; z-index:1010; float: right; } #upload { height:27px; padding:0; margin-left:0.2em; overflow:hidden; @@ -44,7 +44,7 @@ z-index:20; position:relative; cursor:pointer; overflow:hidden; } -#uploadprogresswrapper { position:absolute; right:13.5em; top:0em; } +#uploadprogresswrapper { float: right; position: relative; } #uploadprogresswrapper #uploadprogressbar { position:relative; display:inline-block; width:10em; height:1.5em; top:.4em; } /* FILE TABLE */ diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index 2d4ed9ab2d9..9c12067ae95 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -35,18 +35,18 @@ - + + - -
-
- +
+
+ -
From 07a7478fdece219b04370ca0e218f3eb18ca8831 Mon Sep 17 00:00:00 2001 From: Thomas Mueller Date: Thu, 24 Jan 2013 13:47:04 +0100 Subject: [PATCH 022/131] PHPUnit support for Windows added --- autotest.cmd | 117 ++++++++++++++ tests/win32-phpunit.php | 347 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 464 insertions(+) create mode 100644 autotest.cmd create mode 100644 tests/win32-phpunit.php diff --git a/autotest.cmd b/autotest.cmd new file mode 100644 index 00000000000..053860db547 --- /dev/null +++ b/autotest.cmd @@ -0,0 +1,117 @@ +:: +:: ownCloud +:: +:: @author Thomas Müller +:: @author Tobias Ramforth (translated into Windows batch file) +:: +:: @copyright 2012 Thomas Müller thomas.mueller@tmit.eu +:: +@echo off + +set DATADIR=data-autotest +set BASEDIR=%~dp0 + +:: create autoconfig for sqlite, mysql and postgresql +echo ^ .\tests\autoconfig-sqlite.php +echo $AUTOCONFIG ^= array ^( >> .\tests\autoconfig-sqlite.php +echo 'installed' ^=^> false^, >> .\tests\autoconfig-sqlite.php +echo 'dbtype' ^=^> 'sqlite'^, >> .\tests\autoconfig-sqlite.php +echo 'dbtableprefix' ^=^> 'oc_'^, >> .\tests\autoconfig-sqlite.php +echo 'adminlogin' ^=^> 'admin'^, >> .\tests\autoconfig-sqlite.php +echo 'adminpass' ^=^> 'admin'^, >> .\tests\autoconfig-sqlite.php +echo 'directory' ^=^> '%BASEDIR%%DATADIR%'^, >> .\tests\autoconfig-sqlite.php +echo ^)^; >> .\tests\autoconfig-sqlite.php + +echo ^ .\tests\autoconfig-mysql.php +echo $AUTOCONFIG ^= array ^( >> .\tests\autoconfig-mysql.php +echo 'installed' ^=^> false^, >> .\tests\autoconfig-mysql.php +echo 'dbtype' ^=^> 'mysql'^, >> .\tests\autoconfig-mysql.php +echo 'dbtableprefix' ^=^> 'oc_'^, >> .\tests\autoconfig-mysql.php +echo 'adminlogin' ^=^> 'admin'^, >> .\tests\autoconfig-mysql.php +echo 'adminpass' ^=^> 'admin'^, >> .\tests\autoconfig-mysql.php +echo 'directory' ^=^> '%BASEDIR%%DATADIR%'^, >> .\tests\autoconfig-mysql.php +echo 'dbuser' ^=^> 'oc_autotest'^, >> .\tests\autoconfig-mysql.php +echo 'dbname' ^=^> 'oc_autotest'^, >> .\tests\autoconfig-mysql.php +echo 'dbhost' ^=^> 'localhost'^, >> .\tests\autoconfig-mysql.php +echo 'dbpass' ^=^> 'owncloud'^, >> .\tests\autoconfig-mysql.php +echo ^)^; >> .\tests\autoconfig-mysql.php + +echo ^ .\tests\autoconfig-pgsql.php +echo $AUTOCONFIG ^= array ^( >> .\tests\autoconfig-pgsql.php +echo 'installed' ^=^> false^, >> .\tests\autoconfig-pgsql.php +echo 'dbtype' ^=^> 'pgsql'^, >> .\tests\autoconfig-pgsql.php +echo 'dbtableprefix' ^=^> 'oc_'^, >> .\tests\autoconfig-pgsql.php +echo 'adminlogin' ^=^> 'admin'^, >> .\tests\autoconfig-pgsql.php +echo 'adminpass' ^=^> 'admin'^, >> .\tests\autoconfig-pgsql.php +echo 'directory' ^=^> '%BASEDIR%%DATADIR%'^, >> .\tests\autoconfig-pgsql.php +echo 'dbuser' ^=^> 'oc_autotest'^, >> .\tests\autoconfig-pgsql.php +echo 'dbname' ^=^> 'oc_autotest'^, >> .\tests\autoconfig-pgsql.php +echo 'dbhost' ^=^> 'localhost'^, >> .\tests\autoconfig-pgsql.php +echo 'dbpass' ^=^> 'owncloud'^, >> .\tests\autoconfig-pgsql.php +echo ^)^; >> .\tests\autoconfig-pgsql.php + +echo localhost:5432:*:oc_autotest:owncloud > %APPDATA%\postgresql\pgpass.conf + +:: +:: start test execution +:: +::call:execute_tests "sqlite" +call:execute_tests "mysql" +::call:execute_tests "mssql" +::call:execute_tests "ora" +::call:execute_tests "pgsql" + +goto:eof + +:execute_tests + echo "Setup environment for %~1 testing ..." + :: back to root folder + cd %BASEDIR% + + :: revert changes to tests\data + git checkout tests\data\* + + :: reset data directory + rmdir /s /q %DATADIR% + md %DATADIR% + + :: remove the old config file + :: del /q /f config\config.php + copy /y tests\preseed-config.php config\config.php + + :: drop database + if "%~1" == "mysql" mysql -u oc_autotest -powncloud -e "DROP DATABASE oc_autotest" + + if "%~1" == "pgsql" dropdb -h localhost -p 5432 -U oc_autotest -w oc_autotest + + :: copy autoconfig + copy /y %BASEDIR%\tests\autoconfig-%~1.php %BASEDIR%\config\autoconfig.php + + :: trigger installation + php -f index.php + + ::test execution + echo "Testing with %~1 ..." + cd tests + rmdir /s /q coverage-html-%~1 + md coverage-html-%~1 + php -f enable_all.php + ::phpunit --log-junit autotest-results-%~1.xml --coverage-clover autotest-clover-%~1.xml --coverage-html coverage-html-%~1 + ::phpunit --bootstrap bootstrap.php --configuration phpunit.xml + php win32-phpunit.php --bootstrap bootstrap.php --configuration phpunit.xml --log-junit autotest-results-%~1.xml --coverage-clover autotest-clover-%~1.xml --coverage-html coverage-html-%~1 + echo "Done with testing %~1 ..." + cd %BASEDIR% +goto:eof + +:: +:: NOTES on mysql: +:: - CREATE USER 'oc_autotest'@'localhost' IDENTIFIED BY 'owncloud'; +:: - grant access permissions: grant all on oc_autotest.* to 'oc_autotest'@'localhost'; +:: +:: NOTES on pgsql: +:: - su - postgres +:: - createuser -P (enter username and password and enable superuser) +:: - to enable dropdb I decided to add following line to pg_hba.conf (this is not the safest way but I don't care for the testing machine): +:: local all all trust +:: + diff --git a/tests/win32-phpunit.php b/tests/win32-phpunit.php new file mode 100644 index 00000000000..ac8f95efcbf --- /dev/null +++ b/tests/win32-phpunit.php @@ -0,0 +1,347 @@ +printHeader(); + $this->printFooter($result); + } + + protected function writeProgress($progress) + { + //ignore + } + } + break; + } +} + +//loading of OC_PHPUnit_TextUI_Command +switch (OC_PHPUnit_Loader::$PHPUnitVersionId) { + case "36": + case "37": { + class OC_PHPUnit_TextUI_Command extends PHPUnit_TextUI_Command + { + + public static function main($exit = TRUE) + { + $command = new OC_PHPUnit_TextUI_Command(); + $command->run($_SERVER['argv'], $exit); + } + + protected function handleArguments(array $argv) + { + parent::handleArguments($argv); + $this->arguments['listeners'][] = new OC_PHPUnit_Framework_TestListener(); + $this->arguments['printer'] = new OC_PHPUnit_TextUI_ResultPrinter(); + } + + protected function createRunner() + { + $coverage_Filter = new PHP_CodeCoverage_Filter(); + $coverage_Filter->addFileToBlacklist(__FILE__); + $runner = new PHPUnit_TextUI_TestRunner($this->arguments['loader'], $coverage_Filter); + return $runner; + } + } + break; + } +} + +class OC_PHPUnit_Loader +{ + + const SUCCESS_EXIT = 0; + const FAILURE_EXIT = 1; + const EXCEPTION_EXIT = 2; + + public static $PHPUnitVersionId; + + /** + * @return void + */ + public static function checkIncludePath() + { + //check include path + $PHPUnitParentDirectory = self::getPHPUnitParentDirectory(); + if (is_null($PHPUnitParentDirectory)) { + echo "Cannot find PHPUnit in include path (" . ini_get('include_path') . ")"; + exit(OC_PHPUnit_Loader::FAILURE_EXIT); + } + } + + /** + * @return null | string + */ + private static function getPHPUnitParentDirectory() + { + $pathArray = explode(PATH_SEPARATOR, ini_get('include_path')); + foreach ($pathArray as $path) + { + if (file_exists($path . DIRECTORY_SEPARATOR . 'PHPUnit/')) { + return $path; + } + } + return null; + } + + /** + * @return void + */ + public static function detectPHPUnitVersionId() + { + require_once 'PHPUnit/Runner/Version.php'; + + $PHPUnitVersion = PHPUnit_Runner_Version::id(); + + if ($PHPUnitVersion === "@package_version@") { + + self::$PHPUnitVersionId = "37"; + } + else if (version_compare($PHPUnitVersion, '3.7.0') >= 0) { + + self::$PHPUnitVersionId = "37"; + } + else if (version_compare($PHPUnitVersion, '3.6.0') >= 0) { + + self::$PHPUnitVersionId = "36"; + } + else if (version_compare($PHPUnitVersion, '3.6.0') >= 0) { + + echo "unsupported PHPUnit version: $PHPUnitVersion"; + exit(OC_PHPUnit_Loader::FAILURE_EXIT); + } + } + + /** + * @return void + */ + public static function load37() + { + + require 'PHPUnit/Autoload.php'; + + } + + + /** + * @return void + */ + public static function load36() + { + define('PHPUnit_MAIN_METHOD', 'OC_PHPUnit_TextUI_Command::main'); + + require 'PHPUnit/Autoload.php'; + + } +} + +class OC_PHPUnit_Framework_TestListener implements PHPUnit_Framework_TestListener +{ + + private $isSummaryTestCountPrinted = false; + + public static function printEvent($eventName, $params = array()) + { + self::printText("\n[$eventName"); + foreach ($params as $key => $value) { + self::printText(" $key='$value'"); + } + self::printText("]\n"); + } + + public static function printText($text) + { + file_put_contents('php://stderr', $text); + } + + private static function getMessage(Exception $e) + { + $message = ""; + if (strlen(get_class($e)) != 0) { + $message = $message . get_class($e); + } + if (strlen($message) != 0 && strlen($e->getMessage()) != 0) { + $message = $message . " : "; + } + $message = $message . $e->getMessage(); + return self::escapeValue($message); + } + + private static function getDetails(Exception $e) + { + return self::escapeValue($e->getTraceAsString()); + } + + public static function getValueAsString($value) + { + if (is_null($value)) { + return "null"; + } + else if (is_bool($value)) { + return $value == true ? "true" : "false"; + } + else if (is_array($value) || is_string($value)) { + $valueAsString = print_r($value, true); + if (strlen($valueAsString) > 10000) { + return null; + } + return $valueAsString; + } + else if (is_scalar($value)){ + return print_r($value, true); + } + return null; + } + + private static function escapeValue($text) { + $text = str_replace("|", "||", $text); + $text = str_replace("'", "|'", $text); + $text = str_replace("\n", "|n", $text); + $text = str_replace("\r", "|r", $text); + $text = str_replace("]", "|]", $text); + return $text; + } + + public static function getFileName($className) + { + $reflectionClass = new ReflectionClass($className); + $fileName = $reflectionClass->getFileName(); + return $fileName; + } + + public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) + { + self::printEvent("testFailed", array( + "name" => $test->getName(), + "message" => self::getMessage($e), + "details" => self::getDetails($e) + )); + } + + public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) + { + $params = array( + "name" => $test->getName(), + "message" => self::getMessage($e), + "details" => self::getDetails($e) + ); + if ($e instanceof PHPUnit_Framework_ExpectationFailedException) { + $comparisonFailure = $e->getComparisonFailure(); + if ($comparisonFailure instanceof PHPUnit_Framework_ComparisonFailure) { + $actualResult = $comparisonFailure->getActual(); + $expectedResult = $comparisonFailure->getExpected(); + $actualString = self::getValueAsString($actualResult); + $expectedString = self::getValueAsString($expectedResult); + if (!is_null($actualString) && !is_null($expectedString)) { + $params['actual'] = self::escapeValue($actualString); + $params['expected'] = self::escapeValue($expectedString); + } + } + } + self::printEvent("testFailed", $params); + } + + public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + self::printEvent("testIgnored", array( + "name" => $test->getName(), + "message" => self::getMessage($e), + "details" => self::getDetails($e) + )); + } + + public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + self::printEvent("testIgnored", array( + "name" => $test->getName(), + "message" => self::getMessage($e), + "details" => self::getDetails($e) + )); + } + + public function startTest(PHPUnit_Framework_Test $test) + { + $testName = $test->getName(); + $params = array( + "name" => $testName + ); + if ($test instanceof PHPUnit_Framework_TestCase) { + $className = get_class($test); + $fileName = self::getFileName($className); + $params['locationHint'] = "php_qn://$fileName::\\$className::$testName"; + } + self::printEvent("testStarted", $params); + } + + public function endTest(PHPUnit_Framework_Test $test, $time) + { + self::printEvent("testFinished", array( + "name" => $test->getName(), + "duration" => (int)(round($time, 2) * 1000) + )); + } + + public function startTestSuite(PHPUnit_Framework_TestSuite $suite) + { + if (!$this->isSummaryTestCountPrinted) { + $this->isSummaryTestCountPrinted = true; + //print tests count + self::printEvent("testCount", array( + "count" => count($suite) + )); + } + + $suiteName = $suite->getName(); + if (empty($suiteName)) { + return; + } + $params = array( + "name" => $suiteName, + ); + if (class_exists($suiteName, false)) { + $fileName = self::getFileName($suiteName); + $params['locationHint'] = "php_qn://$fileName::\\$suiteName"; + } + self::printEvent("testSuiteStarted", $params); + } + + public function endTestSuite(PHPUnit_Framework_TestSuite $suite) + { + $suiteName = $suite->getName(); + if (empty($suiteName)) { + return; + } + self::printEvent("testSuiteFinished", + array( + "name" => $suite->getName() + )); + } + +} + +OC_PHPUnit_TextUI_Command::main(); From 46e10407f7aef7850e56da51fc81311c6b77acaa Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 4 Feb 2013 14:09:32 +0100 Subject: [PATCH 023/131] Remove padding hack to position users list. --- settings/css/settings.css | 1 - 1 file changed, 1 deletion(-) diff --git a/settings/css/settings.css b/settings/css/settings.css index 5a3ab2c6e97..f27f9e8628c 100644 --- a/settings/css/settings.css +++ b/settings/css/settings.css @@ -31,7 +31,6 @@ tr:hover>td.password>span, tr:hover>td.displayName>span { margin:0; cursor:point tr:hover>td.remove>a, tr:hover>td.password>img,tr:hover>td.displayName>img, tr:hover>td.quota>img { visibility:visible; cursor:pointer; } tr:hover>td.remove>a { float:right; } li.selected { background-color:#ddd; } -#content>table:not(.nostyle) { margin-top:3em; } table:not(.nostyle) { width:100%; } #rightcontent { padding-left: 1em; } div.quota { float:right; display:block; position:absolute; right:25em; top:0; } From 997259df4b3000aef343fd19f29935d1fde8b23e Mon Sep 17 00:00:00 2001 From: Thomas Mueller Date: Mon, 4 Feb 2013 13:10:25 +0100 Subject: [PATCH 024/131] reuse \OC_Helper::tmpFolder() --- tests/lib/files/storage/commontest.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/lib/files/storage/commontest.php b/tests/lib/files/storage/commontest.php index 744d4608420..ce53c884f32 100644 --- a/tests/lib/files/storage/commontest.php +++ b/tests/lib/files/storage/commontest.php @@ -28,10 +28,7 @@ class CommonTest extends Storage { */ private $tmpDir; public function setUp() { - $this->tmpDir=get_temp_dir().'/filestoragecommon'; - if(!file_exists($this->tmpDir)) { - mkdir($this->tmpDir); - } + $this->tmpDir=\OC_Helper::tmpFolder(); $this->instance=new \OC\Files\Storage\CommonTest(array('datadir'=>$this->tmpDir)); } From 6058c2f734ca2259aebab9cc83eb63c2718b2e4d Mon Sep 17 00:00:00 2001 From: Thomas Mueller Date: Mon, 4 Feb 2013 15:04:26 +0100 Subject: [PATCH 025/131] we get best results regarding mime type detection if we use fileinfo - let's tell the admin about that --- lib/util.php | 8 ++++++++ settings/admin.php | 1 + settings/templates/admin.php | 15 ++++++++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/util.php b/lib/util.php index 91970ab2b96..4de34b9dfda 100755 --- a/lib/util.php +++ b/lib/util.php @@ -516,6 +516,14 @@ class OC_Util { } } + /** + * Check if the PHP module fileinfo is loaded. + * @return bool + */ + public static function fileInfoLoaded() { + return function_exists('finfo_open'); + } + /** * Check if the ownCloud server can connect to the internet */ diff --git a/settings/admin.php b/settings/admin.php index 4d9685ab920..7cca7165153 100755 --- a/settings/admin.php +++ b/settings/admin.php @@ -31,6 +31,7 @@ $tmpl->assign('entriesremain', $entriesremain); $tmpl->assign('htaccessworking', $htaccessworking); $tmpl->assign('internetconnectionworking', OC_Util::isinternetconnectionworking()); $tmpl->assign('islocaleworking', OC_Util::issetlocaleworking()); +$tmpl->assign('has_fileinfo', OC_Util::fileInfoLoaded()); $tmpl->assign('backgroundjobs_mode', OC_Appconfig::getValue('core', 'backgroundjobs_mode', 'ajax')); $tmpl->assign('shareAPIEnabled', OC_Appconfig::getValue('core', 'shareapi_enabled', 'yes')); diff --git a/settings/templates/admin.php b/settings/templates/admin.php index 0097489743f..9a9a691dcbf 100644 --- a/settings/templates/admin.php +++ b/settings/templates/admin.php @@ -22,7 +22,20 @@ if (!$_['htaccessworking']) { +
+ t('Module \'fileinfo\' missing');?> + + + t('The PHP module \'fileinfo\' is missing. We strongly recommend to enable this module to get best results with mime-type detection.'); ?> + + +
+
From 0a113600f7c3374c9c0840a8ec6bdae2d754a236 Mon Sep 17 00:00:00 2001 From: Thomas Mueller Date: Mon, 4 Feb 2013 15:32:01 +0100 Subject: [PATCH 026/131] in case file based session handling in enabled - we need to make sure the configured folder is writable --- lib/util.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/util.php b/lib/util.php index e8057abe9ae..45e594afd6b 100755 --- a/lib/util.php +++ b/lib/util.php @@ -268,6 +268,17 @@ class OC_Util { $web_server_restart= false; } + $handler = ini_get("session.save_handler"); + if($handler == "files") { + $tmpDir = session_save_path(); + if($tmpDir != ""){ + if(!@is_writable($tmpDir)){ + $errors[]=array('error' => 'The temporary folder used by PHP to save the session data is either incorrect or not writable! Please check : '.session_save_path().'
', + 'hint'=>'Please ask your server administrator to grant write access or define another temporary folder.'); + } + } + } + if($web_server_restart) { $errors[]=array('error'=>'PHP modules have been installed, but they are still listed as missing?
', 'hint'=>'Please ask your server administrator to restart the web server.'); } From 8de0f96a244a95e0b881e64d73f9aaa6011de188 Mon Sep 17 00:00:00 2001 From: Lukas Reschke Date: Mon, 4 Feb 2013 17:51:52 +0100 Subject: [PATCH 027/131] Allow loading of external fonts Required by several applications like our pdf viewer --- config/config.sample.php | 2 +- lib/template.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.sample.php b/config/config.sample.php index 5264e948200..1eec4c91c70 100644 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -130,7 +130,7 @@ $CONFIG = array( "remember_login_cookie_lifetime" => 60*60*24*15, /* Custom CSP policy, changing this will overwrite the standard policy */ -"custom_csp_policy" => "default-src \'self\'; script-src \'self\' \'unsafe-eval\'; style-src \'self\' \'unsafe-inline\'; frame-src *; img-src *", +"custom_csp_policy" => "default-src \'self\'; script-src \'self\' \'unsafe-eval\'; style-src \'self\' \'unsafe-inline\'; frame-src *; img-src *; font-src *", /* The directory where the user data is stored, default to data in the owncloud * directory. The sqlite database is also stored here, when sqlite is used. diff --git a/lib/template.php b/lib/template.php index 238d8a8ad0f..ebcc2b879c8 100644 --- a/lib/template.php +++ b/lib/template.php @@ -192,7 +192,7 @@ class OC_Template{ // Content Security Policy // If you change the standard policy, please also change it in config.sample.php - $policy = OC_Config::getValue('custom_csp_policy', 'default-src \'self\'; script-src \'self\' \'unsafe-eval\'; style-src \'self\' \'unsafe-inline\'; frame-src *; img-src *'); + $policy = OC_Config::getValue('custom_csp_policy', 'default-src \'self\'; script-src \'self\' \'unsafe-eval\'; style-src \'self\' \'unsafe-inline\'; frame-src *; img-src *; font-src *'); header('Content-Security-Policy:'.$policy); // Standard header('X-WebKit-CSP:'.$policy); // Older webkit browsers From b06ac67e07512fbf1b12e586bc73d7569aec9e24 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 4 Feb 2013 18:30:49 +0100 Subject: [PATCH 028/131] Add 'hascontrols' class for content with fixed topbar. --- apps/files/css/files.css | 4 ++-- apps/files/templates/index.php | 18 +++++++++--------- core/css/styles.css | 10 +++++++++- settings/templates/apps.php | 2 +- settings/templates/users.php | 2 +- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/apps/files/css/files.css b/apps/files/css/files.css index 0a12439c359..f37ac4c262a 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -3,7 +3,7 @@ See the COPYING-README file. */ /* FILE MENU */ -.actions { padding:.3em; float:left; height:2em; } +.actions { padding:.3em; float:left; height:2em; width: 100%; } .actions input, .actions button, .actions .button { margin:0; float:left; } #new { @@ -23,7 +23,7 @@ #new>ul>li>p { cursor:pointer; } #new>ul>li>form>input { padding:0.3em; margin:-0.3em; } -#trash { height:17px; margin:0.3em 0.3em 0.3em 1em; z-index:1010; float: right; } +#trash { height:17px; margin: 0 1em; z-index:1010; float: right; } #upload { height:27px; padding:0; margin-left:0.2em; overflow:hidden; diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index 9c12067ae95..0b4aa21eac3 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -35,18 +35,18 @@ - - + - -
-
- +
+
+ +
@@ -59,7 +59,7 @@
t('Nothing in here. Upload something!')?>
- +
diff --git a/core/css/styles.css b/core/css/styles.css index 80485fd063d..02300ff4cd3 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -119,10 +119,18 @@ input[type="submit"].enabled { background:#66f866; border:1px solid #5e5; -moz-b #select_all{ margin-top:.4em !important;} /* CONTENT ------------------------------------------------------------------ */ -#controls { padding:0 0.5em; width:100%; top:0; height:2.8em; margin:0; background:#f7f7f7; border-bottom:1px solid #eee; position:relative; -moz-box-sizing:border-box; box-sizing:border-box; z-index:50; -moz-box-shadow:0 -3px 7px #000; -webkit-box-shadow:0 -3px 7px #000; box-shadow:0 -3px 7px #000; } +#controls { + position:fixed; + height:2.8em; width:100%; + padding:0 70px 0 0.5em; margin:0; + -moz-box-sizing:border-box; box-sizing:border-box; + -moz-box-shadow:0 -3px 7px #000; -webkit-box-shadow:0 -3px 7px #000; box-shadow:0 -3px 7px #000; + background:#f7f7f7; border-bottom:1px solid #eee; z-index:50; +} #controls .button { display:inline-block; } #content { position:relative; height:100%; width:100%; } +#content .hascontrols { position: relative; top: 3em; } #content-wrapper { position:absolute; height:100%; width:100%; padding-top:3.5em; padding-left:64px; -moz-box-sizing:border-box; box-sizing:border-box; diff --git a/settings/templates/apps.php b/settings/templates/apps.php index 3f0d2a9d1c6..ed1232ac322 100644 --- a/settings/templates/apps.php +++ b/settings/templates/apps.php @@ -10,7 +10,7 @@ t('Add your App');?> t('More Apps');?> -