From 14451bdaf07f88c6ac46092c74b987a360b04547 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Fri, 29 Mar 2013 21:11:29 +0100 Subject: Development snapshot; Fixed errors from Hooks::login(); Work on enable/disable recoveryAdmin for lost passwords in settings page (template, ajax, js); Work on fixing sharing files to users (still broken); --- apps/files_encryption/js/settings.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'apps/files_encryption/js') diff --git a/apps/files_encryption/js/settings.js b/apps/files_encryption/js/settings.js index 0be857bb73e..4f367f880db 100644 --- a/apps/files_encryption/js/settings.js +++ b/apps/files_encryption/js/settings.js @@ -6,12 +6,26 @@ $(document).ready(function(){ + // Trigger ajax on filetype blacklist change $('#encryption_blacklist').multiSelect({ oncheck:blackListChange, onuncheck:blackListChange, createText:'...' }); + // Trigger ajax on recoveryAdmin status change + $( 'input:radio[name="adminEnableRecovery"]' ).change( + function() { + $.post( + '../ajax/adminrecovery.php' + , $( this ).val() + , function( data ) { + // TODO: provide user with feedback of outcome + } + ); + } + ); + function blackListChange(){ var blackList=$('#encryption_blacklist').val().join(','); OC.AppConfig.setValue('files_encryption','type_blacklist',blackList); -- cgit v1.2.3 From f378a7f572e1da4b24280c1fcbf830e026186c83 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Wed, 10 Apr 2013 17:37:03 +0200 Subject: Fixed proxy class handing of read / write files Various work on other classes --- apps/files_encryption/ajax/adminrecovery.php | 12 +++-- apps/files_encryption/appinfo/app.php | 6 ++- apps/files_encryption/hooks/hooks.php | 10 ++-- apps/files_encryption/js/settings.js | 9 ++-- apps/files_encryption/lib/proxy.php | 49 +++++++++---------- apps/files_encryption/lib/stream.php | 2 +- apps/files_encryption/lib/util.php | 70 ++++++++++++++++++++++------ apps/files_encryption/test/proxy.php | 2 +- apps/files_encryption/test/util.php | 12 +++++ 9 files changed, 114 insertions(+), 58 deletions(-) (limited to 'apps/files_encryption/js') diff --git a/apps/files_encryption/ajax/adminrecovery.php b/apps/files_encryption/ajax/adminrecovery.php index f22114f8514..cec0cd4ddda 100644 --- a/apps/files_encryption/ajax/adminrecovery.php +++ b/apps/files_encryption/ajax/adminrecovery.php @@ -15,6 +15,8 @@ use OCA\Encryption; \OCP\JSON::checkAppEnabled( 'files_encryption' ); \OCP\JSON::callCheck(); +$return = $doSetup = false; + if ( isset( $_POST['adminEnableRecovery'] ) && $_POST['adminEnableRecovery'] == 1 @@ -47,7 +49,7 @@ if ( // If the recoveryAdmin UID exists but doesn't have admin rights } else { - \OCP\JSON::error(); + $return = false; } @@ -63,10 +65,12 @@ if ( $util->setupServerSide( $_POST['recoveryPassword'] ); // Store the UID in the DB - OC_Appconfig::setValue( 'encryption', 'recoveryAdminUid', $recoveryAdminUid ); + OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminUid', $recoveryAdminUid ); - \OCP\JSON::success(); + $return = true; } -} \ No newline at end of file +} + +($return) ? OC_JSON::success() : OC_JSON::error(); \ No newline at end of file diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index 9747fb20ad6..c2de9d0b441 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -24,8 +24,10 @@ OCP\Util::connectHook( 'OCP\Share', 'post_unshareAll', 'OCA\Encryption\Hooks', ' OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfileFromClient' ); stream_wrapper_register( 'crypt', 'OCA\Encryption\Stream' ); -$view = new OC_FilesystemView('/'); -$session = new OCA\Encryption\Session($view); + +$view = new OC_FilesystemView( '/' ); + +$session = new OCA\Encryption\Session( $view ); if ( ! $session->getPrivateKey( \OCP\USER::getUser() ) diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 82de80a1cf4..e65f0945f41 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -63,7 +63,7 @@ class Hooks { $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $params['password'] ); - $session = new Session($view); + $session = new Session( $view ); $session->setPrivateKey( $privateKey, $params['uid'] ); @@ -116,8 +116,8 @@ class Hooks { // is in use (client-side encryption does not have access to // the necessary keys) if ( Crypt::mode() == 'server' ) { - $view = new \OC_FilesystemView( '/' ); - $session = new Session($view); + + $session = new Session(); // Get existing decrypted private key $privateKey = $session->getPrivateKey(); @@ -189,7 +189,7 @@ class Hooks { if ( $params['itemType'] === 'file' ) { $view = new \OC_FilesystemView( '/' ); - $session = new Session($view); + $session = new Session(); $userId = \OCP\User::getUser(); $util = new Util( $view, $userId ); $path = $util->fileIdToPath( $params['itemSource'] ); @@ -244,7 +244,7 @@ class Hooks { if ( $params['itemType'] === 'file' ) { $view = new \OC_FilesystemView( '/' ); - $session = new Session($view); + $session = new Session(); $userId = \OCP\User::getUser(); $util = new Util( $view, $userId ); $path = $util->fileIdToPath( $params['itemSource'] ); diff --git a/apps/files_encryption/js/settings.js b/apps/files_encryption/js/settings.js index 4f367f880db..9a0bebf2478 100644 --- a/apps/files_encryption/js/settings.js +++ b/apps/files_encryption/js/settings.js @@ -16,11 +16,14 @@ $(document).ready(function(){ // Trigger ajax on recoveryAdmin status change $( 'input:radio[name="adminEnableRecovery"]' ).change( function() { + + var foo = $( this ).val(); + $.post( - '../ajax/adminrecovery.php' - , $( this ).val() + OC.filePath('files_encryption', 'ajax', 'adminrecovery.php') + , { adminEnableRecovery: foo, recoveryPassword: 'password' } , function( data ) { - // TODO: provide user with feedback of outcome + alert( data ); } ); } diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 7e18ec9b104..44a2e1aae55 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -101,7 +101,7 @@ class Proxy extends \OC_FileProxy { $userId = \OCP\USER::getUser(); $rootView = new \OC_FilesystemView( '/' ); $util = new Util( $rootView, $userId ); - $session = new Session($rootView); + $session = new Session( $rootView ); $fileOwner = \OC\Files\Filesystem::getOwner( $path ); $privateKey = $session->getPrivateKey(); $filePath = $util->stripUserFilesPath( $path ); @@ -115,9 +115,16 @@ class Proxy extends \OC_FileProxy { if ( $encKeyfile = Keymanager::getFileKey( $rootView, $fileOwner, $filePath ) ) { $keyPreExists = true; - + + // Fetch shareKey + $shareKey = Keymanager::getShareKey( $rootView, $userId, $filePath ); + // Decrypt the keyfile - $plainKey = $util->decryptUnknownKeyfile( $filePath, $fileOwner, $privateKey ); + $plainKey = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); + + trigger_error("\$shareKey = $shareKey"); + + trigger_error("\$plainKey = $plainKey"); } else { @@ -170,6 +177,7 @@ class Proxy extends \OC_FileProxy { // Save sharekeys to user folders // TODO: openssl_seal generates new shareKeys (envelope keys) each time data is encrypted, but will data still be decryptable using old shareKeys? If so we don't need to replace the old shareKeys here, we only need to set the new ones + Keymanager::setShareKeys( $rootView, $filePath, $multiEncrypted['keys'] ); // Set encrypted keyfile as common varname @@ -219,15 +227,18 @@ class Proxy extends \OC_FileProxy { // If data is a catfile if ( Crypt::mode() == 'server' - && Crypt::isCatfileContent( $data ) + && Crypt::isCatfileContent( $data ) // TODO: Do we really need this check? Can't we assume it is properly encrypted? ) { - // TODO use get owner to find correct location of key files for shared files - $session = new Session($view); + // TODO: use get owner to find correct location of key files for shared files + $session = new Session( $view ); $privateKey = $session->getPrivateKey( $userId ); // Get the file owner so we can retrieve its keyfile - list($fileOwner, $ownerPath) = $util->getUidAndFilename($relPath); +// list( $fileOwner, $ownerPath ) = $util->getUidAndFilename( $relPath ); + + $fileOwner = \OC\Files\Filesystem::getOwner( $path ); + $ownerPath = $util->stripUserFilesPath( $path ); // TODO: Don't trust $path, fetch owner path // Get the encrypted keyfile $encKeyfile = Keymanager::getFileKey( $view, $fileOwner, $ownerPath ); @@ -235,27 +246,9 @@ class Proxy extends \OC_FileProxy { // Attempt to fetch the user's shareKey $shareKey = Keymanager::getShareKey( $view, $userId, $relPath ); - // Check if key is shared or not - if ( $shareKey ) { - - \OC_FileProxy::$enabled = false; - -// trigger_error("\$encKeyfile = $encKeyfile, \$shareKey = $shareKey, \$privateKey = $privateKey"); - - // Decrypt keyfile with shareKey - $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); - -// $plainKeyfile = $encKeyfile; - -// trigger_error("PROXY plainkeyfile = ". var_export($plainKeyfile, 1)); - - } else { - - // If key is unshared, decrypt with user private key - $plainKeyfile = Crypt::keyDecrypt( $encKeyfile, $privateKey ); - - } - + // Decrypt keyfile with shareKey + $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); + $plainData = Crypt::symmetricDecryptFileContent( $data, $plainKeyfile ); // trigger_error("PLAINDATA = ". var_export($plainData, 1)); diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index d269a562404..7315245fcce 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -236,7 +236,7 @@ class Stream { $this->getUser(); - $session = new Session($this->rootView); + $session = new Session( $this->rootView ); $privateKey = $session->getPrivateKey( $this->userId ); diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 420e3398a8d..dc4e37150c5 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -24,13 +24,17 @@ # Bugs # ---- # Sharing a file to a user without encryption set up will not provide them with access but won't notify the sharer -# Timeouts on first login due to encryption of very large files +# Sharing files to other users currently broken (due to merge + ongoing implementation of support for lost password recovery) +# Timeouts on first login due to encryption of very large files (fix in progress, as a result streaming is currently broken) +# Sharing all files to admin for recovery purposes still in progress +# Possibly public links are broken (not tested since last merge of master) +# getOwner() currently returns false in all circumstances, unsure what code is returning this... # Missing features # ---------------- -# Re-use existing keyfiles so they don't need version control (part implemented, stream{} and util{} remain) # Make sure user knows if large files weren't encrypted +# Support for resharing encrypted files # Test @@ -122,7 +126,8 @@ class Util { $this->userId = $userId; $this->client = $client; $this->userDir = '/' . $this->userId; - $this->userFilesDir = '/' . $this->userId . '/' . 'files'; + $this->fileFolderName = 'files'; + $this->userFilesDir = '/' . $this->userId . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable? $this->publicKeyDir = '/' . 'public-keys'; $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption'; $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; @@ -690,7 +695,6 @@ class Util { /** * @brief Expand given path to all sub files & folders - * @param Session $session * @param string $path path which needs to be updated * @return array $pathsArray all found file paths * @note Paths of directories excluded, only *file* paths are returned @@ -747,6 +751,8 @@ class Util { * @param string $privateKey * @note Checks whether file was encrypted with openssl_seal or * openssl_encrypt, and decrypts accrdingly + * @note This was used when 2 types of encryption for keyfiles was used, + * but now we've switched to exclusively using openssl_seal() */ public function decryptUnknownKeyfile( $filePath, $fileOwner, $privateKey ) { @@ -861,19 +867,55 @@ class Util { /** * @brief get uid of the owners of the file and the path to the file - * @param $filename + * @param $shareFilePath Path of the file to check + * @note $shareFilePath must be relative to data/UID/files. Files + * relative to /Shared are also acceptable * @return array */ - public function getUidAndFilename($filename) { - $uid = \OC\Files\Filesystem::getOwner($filename); - - \OC\Files\Filesystem::initMountPoints($uid); - if ( $uid != \OCP\User::getUser() ) { - $info = \OC\Files\Filesystem::getFileInfo($filename); - $ownerView = new \OC\Files\View('/'.$uid.'/files'); - $filename = $ownerView->getPath($info['fileid']); + public function getUidAndFilename( $shareFilePath ) { + + $fileOwnerUid = \OC\Files\Filesystem::getOwner( $shareFilePath ); + + // Check that UID is valid + if ( ! \OCP\User::userExists( $fileOwnerUid ) ) { + + throw new \Exception( 'Could not find owner (UID = "' . var_export( $fileOwnerUid, 1 ) . '") of file "' . $shareFilePath . '"' ); + + } + + // NOTE: Bah, this dependency should be elsewhere + \OC\Files\Filesystem::initMountPoints( $fileOwnerUid ); + + // If the file owner is the currently logged in user + if ( $fileOwnerUid == $this->userId ) { + + // Assume the path supplied is correct + $filename = $shareFilePath; + + } else { + + $info = \OC\Files\Filesystem::getFileInfo( $shareFilePath ); + $ownerView = new \OC\Files\View( '/' . $fileOwnerUid . '/files' ); + + // Fetch real file path from DB + $filename = $ownerView->getPath( $info['fileid'] ); // TODO: Check that this returns a path without including the user data dir + } - return array($uid, $filename); + + // Make path relative for use by $view + $relpath = $fileOwnerUid . '/' . $this->fileFolderName . '/' . $filename; + + // Check that the filename we're using is working + if ( $this->view->file_exists( $relpath ) ) { + + return array ( $fileOwnerUid, $relpath ); + + } else { + + throw new \Exception( 'Supplied path could not be resolved "' . $shareFilePath . '"' ); + + } + } } diff --git a/apps/files_encryption/test/proxy.php b/apps/files_encryption/test/proxy.php index 709730f7609..5a2d851ff7c 100644 --- a/apps/files_encryption/test/proxy.php +++ b/apps/files_encryption/test/proxy.php @@ -52,7 +52,7 @@ // $this->userId = 'admin'; // $this->pass = 'admin'; // -// $this->session = new Encryption\Session(); +// $this->session = new Encryption\Session( $view ); // FIXME: Provide a $view object for use here // // $this->session->setPrivateKey( // '-----BEGIN PRIVATE KEY----- diff --git a/apps/files_encryption/test/util.php b/apps/files_encryption/test/util.php index e2767a2ec39..3ebc484809b 100755 --- a/apps/files_encryption/test/util.php +++ b/apps/files_encryption/test/util.php @@ -24,6 +24,8 @@ $loader->register(); use \Mockery as m; use OCA\Encryption; +\OC_User::login( 'admin', 'admin' ); + class Test_Enc_Util extends \PHPUnit_Framework_TestCase { function setUp() { @@ -184,6 +186,16 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase { $this->assertTrue( $util->setRecovery( $enabled ) ); } + + function testGetUidAndFilename() { + + \OC_User::setUserId( 'admin' ); + + $this->util->getUidAndFilename( 'test1.txt' ); + + + + } // /** // * @brief test decryption using legacy blowfish method -- cgit v1.2.3 From ba29147e34a22142c4bfd2afa3f5b9f1e6efcd63 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Wed, 1 May 2013 19:18:31 +0200 Subject: Fixed recoveryadmin settings in user and admin settings pages (js, templates, ajax) Renamed recovery methods in Util{} for clarity Added note about bug causing slow page load and redundant keypair generation recoveryAdmin functionality not yet complete --- apps/files_encryption/ajax/adminrecovery.php | 27 ++++++-- apps/files_encryption/ajax/userrecovery.php | 9 +-- apps/files_encryption/appinfo/app.php | 4 +- apps/files_encryption/js/settings-admin.js | 37 ++++++++++ apps/files_encryption/js/settings-personal.js | 23 +++++++ apps/files_encryption/js/settings.js | 36 ---------- apps/files_encryption/lib/keymanager.php | 2 +- apps/files_encryption/lib/session.php | 18 +++-- apps/files_encryption/lib/util.php | 79 ++++++++++++++-------- apps/files_encryption/settings-admin.php | 28 ++++++++ apps/files_encryption/settings-personal.php | 20 ++++++ apps/files_encryption/settings.php | 27 -------- apps/files_encryption/templates/settings-admin.php | 39 +++++++++++ .../templates/settings-personal.php | 22 ++++++ apps/files_encryption/templates/settings.php | 39 ----------- apps/files_encryption/tests/util.php | 14 ++-- 16 files changed, 267 insertions(+), 157 deletions(-) create mode 100644 apps/files_encryption/js/settings-admin.js create mode 100644 apps/files_encryption/js/settings-personal.js delete mode 100644 apps/files_encryption/js/settings.js create mode 100644 apps/files_encryption/settings-admin.php delete mode 100644 apps/files_encryption/settings.php create mode 100644 apps/files_encryption/templates/settings-admin.php delete mode 100644 apps/files_encryption/templates/settings.php (limited to 'apps/files_encryption/js') diff --git a/apps/files_encryption/ajax/adminrecovery.php b/apps/files_encryption/ajax/adminrecovery.php index cec0cd4ddda..157fc8f313c 100644 --- a/apps/files_encryption/ajax/adminrecovery.php +++ b/apps/files_encryption/ajax/adminrecovery.php @@ -17,11 +17,12 @@ use OCA\Encryption; $return = $doSetup = false; +// Enable recoveryAdmin if ( isset( $_POST['adminEnableRecovery'] ) - && $_POST['adminEnableRecovery'] == 1 - && isset( $_POST['recoveryPassword'] ) - && ! empty ( $_POST['recoveryPassword'] ) + && 1 == $_POST['adminEnableRecovery'] +// && isset( $_POST['recoveryPassword'] ) +// && ! empty ( $_POST['recoveryPassword'] ) ) { // TODO: Let the admin set this themselves @@ -29,7 +30,7 @@ if ( // If desired recoveryAdmin UID is already in use if ( ! \OC_User::userExists( $recoveryAdminUid ) ) { - + // Create new recoveryAdmin user \OC_User::createUser( $recoveryAdminUid, $_POST['recoveryPassword'] ); @@ -55,11 +56,11 @@ if ( } - // If recoveryAdmin has passed other checks + // Setup recoveryAdmin user for encryption if ( $doSetup ) { $view = new \OC_FilesystemView( '/' ); - $util = new Util( $view, $recoveryAdminUid ); + $util = new \OCA\Encryption\Util( $view, $recoveryAdminUid ); // Ensure recoveryAdmin is ready for encryption (has usable keypair etc.) $util->setupServerSide( $_POST['recoveryPassword'] ); @@ -71,6 +72,20 @@ if ( } + // Set recoveryAdmin as enabled + OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminEnabled', 1 ); + +// Disable recoveryAdmin +} elseif ( + isset( $_POST['adminEnableRecovery'] ) + && 0 == $_POST['adminEnableRecovery'] +) { + + // Set recoveryAdmin as enabled + OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminEnabled', 0 ); + + $return = true; + } ($return) ? OC_JSON::success() : OC_JSON::error(); \ No newline at end of file diff --git a/apps/files_encryption/ajax/userrecovery.php b/apps/files_encryption/ajax/userrecovery.php index 56c18f7ad5b..f72be3181ef 100644 --- a/apps/files_encryption/ajax/userrecovery.php +++ b/apps/files_encryption/ajax/userrecovery.php @@ -13,21 +13,18 @@ use OCA\Encryption; \OCP\JSON::checkLoggedIn(); \OCP\JSON::checkAppEnabled( 'files_encryption' ); -\OCP\JSON::callCheck(); if ( isset( $_POST['userEnableRecovery'] ) + && ( 0 == $_POST['userEnableRecovery'] || 1 == $_POST['userEnableRecovery'] ) ) { - // Ensure preference is an integer - $recoveryEnabled = intval( $_POST['userEnableRecovery'] ); - $userId = \OCP\USER::getUser(); $view = new \OC_FilesystemView( '/' ); - $util = new Util( $view, $userId ); + $util = new \OCA\Encryption\Util( $view, $userId ); // Save recovery preference to DB - $result = $util->setRecovery( $recoveryEnabled ); + $result = $util->setRecoveryForUser( $_POST['userEnableRecovery'] ); if ( $result ) { diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index 9ae6c8331f8..a7253c43332 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -28,7 +28,7 @@ OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'p stream_wrapper_register( 'crypt', 'OCA\Encryption\Stream' ); -$view = new OC_FilesystemView( '/' ); +$view = new \OC\Files\View( '/' ); $session = new OCA\Encryption\Session( $view ); @@ -50,5 +50,5 @@ if ( } // Register settings scripts -OCP\App::registerAdmin( 'files_encryption', 'settings' ); +OCP\App::registerAdmin( 'files_encryption', 'settings-admin' ); OCP\App::registerPersonal( 'files_encryption', 'settings-personal' ); diff --git a/apps/files_encryption/js/settings-admin.js b/apps/files_encryption/js/settings-admin.js new file mode 100644 index 00000000000..48b5598d524 --- /dev/null +++ b/apps/files_encryption/js/settings-admin.js @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2013, Sam Tuke , Robin Appelman + * + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + + +$(document).ready(function(){ + // Trigger ajax on filetype blacklist change + $('#encryption_blacklist').multiSelect({ + oncheck:blackListChange, + onuncheck:blackListChange, + createText:'...' + }); + + // Trigger ajax on recoveryAdmin status change + $( 'input:radio[name="adminEnableRecovery"]' ).change( + function() { + + var recoveryStatus = $( this ).val(); + + $.post( + OC.filePath( 'files_encryption', 'ajax', 'adminrecovery.php' ) + , { adminEnableRecovery: recoveryStatus, recoveryPassword: 'password' } + , function( data ) { + alert( data ); + } + ); + } + ); + + function blackListChange(){ + var blackList=$( '#encryption_blacklist' ).val().join( ',' ); + OC.AppConfig.setValue( 'files_encryption', 'type_blacklist', blackList ); + } +}) \ No newline at end of file diff --git a/apps/files_encryption/js/settings-personal.js b/apps/files_encryption/js/settings-personal.js new file mode 100644 index 00000000000..e4a1b7448f4 --- /dev/null +++ b/apps/files_encryption/js/settings-personal.js @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2013, Sam Tuke + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +$(document).ready(function(){ + // Trigger ajax on recoveryAdmin status change + $( 'input:radio[name="userEnableRecovery"]' ).change( + function() { + + var recoveryStatus = $( this ).val(); + + $.post( + OC.filePath( 'files_encryption', 'ajax', 'userrecovery.php' ) + , { userEnableRecovery: recoveryStatus } + , function( data ) { + alert( data ); + } + ); + } + ); +}) \ No newline at end of file diff --git a/apps/files_encryption/js/settings.js b/apps/files_encryption/js/settings.js deleted file mode 100644 index 9a0bebf2478..00000000000 --- a/apps/files_encryption/js/settings.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2011, Robin Appelman - * This file is licensed under the Affero General Public License version 3 or later. - * See the COPYING-README file. - */ - - -$(document).ready(function(){ - // Trigger ajax on filetype blacklist change - $('#encryption_blacklist').multiSelect({ - oncheck:blackListChange, - onuncheck:blackListChange, - createText:'...' - }); - - // Trigger ajax on recoveryAdmin status change - $( 'input:radio[name="adminEnableRecovery"]' ).change( - function() { - - var foo = $( this ).val(); - - $.post( - OC.filePath('files_encryption', 'ajax', 'adminrecovery.php') - , { adminEnableRecovery: foo, recoveryPassword: 'password' } - , function( data ) { - alert( data ); - } - ); - } - ); - - function blackListChange(){ - var blackList=$('#encryption_blacklist').val().join(','); - OC.AppConfig.setValue('files_encryption','type_blacklist',blackList); - } -}) \ No newline at end of file diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 9f3cb8120ca..51d4f8ffc04 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -32,7 +32,7 @@ class Keymanager { /** * @brief retrieve the ENCRYPTED private key from a user * - * @return string private key or false + * @return string private key or false (hopefully) * @note the key returned by this method must be decrypted before use */ public static function getPrivateKey( \OC_FilesystemView $view, $user ) { diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index 0c6a7131fd9..0e6bb96605f 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -35,22 +35,28 @@ class Session { * * The ownCloud key pair is used to allow public link sharing even if encryption is enabled */ - public function __construct( \OC_FilesystemView $view ) { + public function __construct( $view ) { $this->view = $view; if ( ! $this->view->is_dir( 'owncloud_private_key' ) ) { - $this->view->mkdir('owncloud_private_key'); + $this->view->mkdir( 'owncloud_private_key' ); + } - if ( - ! $this->view->file_exists("/public-keys/owncloud.public.key") - || ! $this->view->file_exists("/owncloud_private_key/owncloud.private.key" ) + ! $this->view->file_exists( "/public-keys/owncloud.public.key" ) + || ! $this->view->file_exists( "/owncloud_private_key/owncloud.private.key" ) ) { - + + //FIXME: Bug: for some reason file_exists is returning + // false in above if statement, and causing new keys + // to be generated on each page load. At last check + // our app.php is being executed 18 times per page load + // , causing 18 new keypairs and huge performance hit. + $keypair = Crypt::createKeypair(); \OC_FileProxy::$enabled = false; diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index eabb34f7ab0..015125370bc 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -24,11 +24,8 @@ # Bugs # ---- # Sharing a file to a user without encryption set up will not provide them with access but won't notify the sharer -# Timeouts on first login due to encryption of very large files (fix in progress, as a result streaming is currently broken) # Sharing all files to admin for recovery purposes still in progress # Possibly public links are broken (not tested since last merge of master) -# encryptAll during login mangles paths: /files/files/ -# encryptAll is accessing files via encryption proxy - perhaps proxies should be disabled? # Missing features @@ -204,12 +201,18 @@ class Util { $this->view->file_put_contents( $this->privateKeyPath, $encryptedPrivateKey ); \OC_FileProxy::$enabled = true; - - // create database configuration - $sql = 'INSERT INTO `*PREFIX*encryption` (`uid`,`mode`,`recovery`) VALUES (?,?,?)'; - $args = array( $this->userId, 'server-side', 0); - $query = \OCP\DB::prepare( $sql ); - $query->execute( $args ); + + } + + // If there's no record for this user's encryption preferences + if ( false === $this->recoveryEnabledForUser() ) { + + // create database configuration + $sql = 'INSERT INTO `*PREFIX*encryption` (`uid`,`mode`,`recovery`) VALUES (?,?,?)'; + $args = array( $this->userId, 'server-side', 0); + $query = \OCP\DB::prepare( $sql ); + $query->execute( $args ); + } return true; @@ -218,11 +221,11 @@ class Util { /** * @brief Check whether pwd recovery is enabled for a given user - * @return bool + * @return 1 = yes, 0 = no, false = no record * @note If records are not being returned, check for a hidden space * at the start of the uid in db */ - public function recoveryEnabled() { + public function recoveryEnabledForUser() { $sql = 'SELECT recovery @@ -237,16 +240,25 @@ class Util { $result = $query->execute( $args ); - // Set default in case no records found - $recoveryEnabled = 0; + $recoveryEnabled = array(); while( $row = $result->fetchRow() ) { - $recoveryEnabled = $row['recovery']; + $recoveryEnabled[] = $row['recovery']; } - return $recoveryEnabled; + // If no record is found + if ( empty( $recoveryEnabled ) ) { + + return false; + + // If a record is found + } else { + + return $recoveryEnabled[0]; + + } } @@ -255,20 +267,33 @@ class Util { * @param bool $enabled Whether to enable or disable recovery * @return bool */ - public function setRecovery( $enabled ) { + public function setRecoveryForUser( $enabled ) { - $sql = 'UPDATE - *PREFIX*encryption - SET - recovery = ? - WHERE - uid = ?'; + $recoveryStatus = $this->recoveryEnabledForUser(); + + // If a record for this user already exists, update it + if ( false === $recoveryStatus ) { - // Ensure value is an integer - $enabled = intval( $enabled ); + $sql = 'INSERT INTO `*PREFIX*encryption` + (`uid`,`mode`,`recovery`) + VALUES (?,?,?)'; + + $args = array( $this->userId, 'server-side', $enabled ); - $args = array( $enabled, $this->userId ); - + // Create a new record instead + } else { + + $sql = 'UPDATE + *PREFIX*encryption + SET + recovery = ? + WHERE + uid = ?'; + + $args = array( $enabled, $this->userId ); + + } + $query = \OCP\DB::prepare( $sql ); if ( $query->execute( $args ) ) { @@ -888,7 +913,7 @@ class Util { public function getSharingUsersArray( $sharingEnabled, $filePath, $currentUserId = false ) { // Check if key recovery is enabled - $recoveryEnabled = $this->recoveryEnabled(); + $recoveryEnabled = $this->recoveryEnabledForUser(); // Make sure that a share key is generated for the owner too list($owner, $ownerPath) = $this->getUidAndFilename($filePath); diff --git a/apps/files_encryption/settings-admin.php b/apps/files_encryption/settings-admin.php new file mode 100644 index 00000000000..b09515f0c33 --- /dev/null +++ b/apps/files_encryption/settings-admin.php @@ -0,0 +1,28 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +\OC_Util::checkAdminUser(); + +$tmpl = new OCP\Template( 'files_encryption', 'settings-admin' ); + +$blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) ); + +// Check if an adminRecovery account is enabled for recovering files after lost pwd +$view = new OC_FilesystemView( '' ); + +$recoveryAdminEnabled = OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' ); +$recoveryAdminUid = OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminUid' ); + +$tmpl->assign( 'blacklist', $blackList ); +$tmpl->assign( 'encryption_mode', \OC_Appconfig::getValue( 'files_encryption', 'mode', 'none' ) ); +$tmpl->assign( 'recoveryEnabled', $recoveryAdminEnabled ); + +\OCP\Util::addscript( 'files_encryption', 'settings-admin' ); +\OCP\Util::addscript( 'core', 'multiselect' ); + +return $tmpl->fetchPage(); diff --git a/apps/files_encryption/settings-personal.php b/apps/files_encryption/settings-personal.php index c001bb0d725..f7ebc425120 100644 --- a/apps/files_encryption/settings-personal.php +++ b/apps/files_encryption/settings-personal.php @@ -10,6 +10,26 @@ $tmpl = new OCP\Template( 'files_encryption', 'settings-personal'); $blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) ); +// Add human readable message in case nothing is blacklisted +if ( + 1 == count( $blackList ) + && $blackList[0] == '' +) { + + // FIXME: Make this string translatable + $blackList[0] = "(None - all filetypes will be encrypted)"; + +} + +$user = \OCP\USER::getUser(); +$view = new \OC_FilesystemView( '/' ); +$util = new \OCA\Encryption\Util( $view, $user ); + +$recoveryEnabledForUser = $util->recoveryEnabledForUser(); + +\OCP\Util::addscript( 'files_encryption', 'settings-personal' ); + +$tmpl->assign( 'recoveryEnabled', $recoveryEnabledForUser ); $tmpl->assign( 'blacklist', $blackList ); return $tmpl->fetchPage(); diff --git a/apps/files_encryption/settings.php b/apps/files_encryption/settings.php deleted file mode 100644 index 71d47f061af..00000000000 --- a/apps/files_encryption/settings.php +++ /dev/null @@ -1,27 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -\OC_Util::checkAdminUser(); - -$tmpl = new OCP\Template( 'files_encryption', 'settings' ); - -$blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) ); - -// Check if an adminRecovery account is enabled for recovering files after lost pwd -$view = new OC_FilesystemView( '' ); -$util = new \OCA\Encryption\Util( $view, \OCP\USER::getUser() ); -$recoveryEnabled = $util->recoveryEnabled(); - -$tmpl->assign( 'blacklist', $blackList ); -$tmpl->assign( 'encryption_mode', \OC_Appconfig::getValue( 'files_encryption', 'mode', 'none' ) ); -$tmpl->assign( 'recoveryEnabled', $recoveryEnabled ); - -\OCP\Util::addscript( 'files_encryption', 'settings' ); -\OCP\Util::addscript( 'core', 'multiselect' ); - -return $tmpl->fetchPage(); diff --git a/apps/files_encryption/templates/settings-admin.php b/apps/files_encryption/templates/settings-admin.php new file mode 100644 index 00000000000..6499d0c8e80 --- /dev/null +++ b/apps/files_encryption/templates/settings-admin.php @@ -0,0 +1,39 @@ +
+
+ +

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

+

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

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

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

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

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

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

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

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

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

-

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

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

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

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

+ +

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

+ -- cgit v1.2.3 From 4b53f72d0d749cceec7a9fa7be5d8bc6bab722c6 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Tue, 7 May 2013 16:17:38 +0200 Subject: Added facility to manually encrypt all files from personal settings Added success/fail feedback to personal settings functions Improved look/layout of personal settings page Fixed misplaced plain text in ajax scripts --- apps/files_encryption/ajax/adminrecovery.php | 5 ++- apps/files_encryption/ajax/encryptall.php | 40 ++++++++++++++++++++++ apps/files_encryption/ajax/userrecovery.php | 22 +++++------- apps/files_encryption/css/settings-personal.css | 10 ++++++ apps/files_encryption/js/settings-personal.js | 39 ++++++++++++++++++++- apps/files_encryption/settings-personal.php | 3 ++ .../templates/settings-personal.php | 32 +++++++++++++---- 7 files changed, 127 insertions(+), 24 deletions(-) create mode 100644 apps/files_encryption/ajax/encryptall.php create mode 100644 apps/files_encryption/css/settings-personal.css (limited to 'apps/files_encryption/js') diff --git a/apps/files_encryption/ajax/adminrecovery.php b/apps/files_encryption/ajax/adminrecovery.php index eeeaf4c6ed7..c3c19943c0d 100644 --- a/apps/files_encryption/ajax/adminrecovery.php +++ b/apps/files_encryption/ajax/adminrecovery.php @@ -1,5 +1,3 @@ -setValue( $app, $key, $value ) - @@ -91,4 +89,5 @@ if ( } -($return) ? OC_JSON::success() : OC_JSON::error(); \ No newline at end of file +// Return success or failure +( $return ) ? \OCP\JSON::success() : \OCP\JSON::error(); \ No newline at end of file diff --git a/apps/files_encryption/ajax/encryptall.php b/apps/files_encryption/ajax/encryptall.php new file mode 100644 index 00000000000..ce613ca4435 --- /dev/null +++ b/apps/files_encryption/ajax/encryptall.php @@ -0,0 +1,40 @@ + + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + * + * @brief Script to handle manual trigger of \OCA\Encryption\Util{}->encryptAll() + */ + +use OCA\Encryption; + +\OCP\JSON::checkAppEnabled( 'files_encryption' ); +\OCP\JSON::callCheck(); + +$return = false; + +if ( + isset( $_POST['encryptAll'] ) + && ! empty( $_POST['userPassword'] ) +) { + + $view = new \OC_FilesystemView( '' ); + $userId = \OCP\User::getUser(); + $util = new \OCA\Encryption\Util( $view, $userId ); + $session = new \OCA\Encryption\Session( $view ); + $publicKey = \OCA\Encryption\Keymanager::getPublicKey( $view, $userId ); + $path = '/' . $userId . '/' . 'files'; + + $util->encryptAll( $publicKey, $path, $session->getLegacyKey(), $_POST['userPassword'] ); + + $return = true; + +} else { + + $return = false; + +} + +// Return success or failure +( $return ) ? \OCP\JSON::success() : \OCP\JSON::error(); \ No newline at end of file diff --git a/apps/files_encryption/ajax/userrecovery.php b/apps/files_encryption/ajax/userrecovery.php index f72be3181ef..85a799011d7 100644 --- a/apps/files_encryption/ajax/userrecovery.php +++ b/apps/files_encryption/ajax/userrecovery.php @@ -1,5 +1,3 @@ -setValue( $app, $key, $value ) - @@ -13,6 +11,7 @@ use OCA\Encryption; \OCP\JSON::checkLoggedIn(); \OCP\JSON::checkAppEnabled( 'files_encryption' ); +\OCP\JSON::callCheck(); if ( isset( $_POST['userEnableRecovery'] ) @@ -24,16 +23,13 @@ if ( $util = new \OCA\Encryption\Util( $view, $userId ); // Save recovery preference to DB - $result = $util->setRecoveryForUser( $_POST['userEnableRecovery'] ); - - if ( $result ) { - - \OCP\JSON::success(); - - } else { + $return = $util->setRecoveryForUser( $_POST['userEnableRecovery'] ); - \OCP\JSON::error(); - - } +} else { + + $return = false; -} \ No newline at end of file +} + +// Return success or failure +( $return ) ? \OCP\JSON::success() : \OCP\JSON::error(); \ No newline at end of file diff --git a/apps/files_encryption/css/settings-personal.css b/apps/files_encryption/css/settings-personal.css new file mode 100644 index 00000000000..4ee0acc9768 --- /dev/null +++ b/apps/files_encryption/css/settings-personal.css @@ -0,0 +1,10 @@ +/* Copyright (c) 2013, Sam Tuke, + This file is licensed under the Affero General Public License version 3 or later. + See the COPYING-README file. */ + +#encryptAllError +, #encryptAllSuccess +, #recoveryEnabledError +, #recoveryEnabledSuccess { + display: none; +} \ No newline at end of file diff --git a/apps/files_encryption/js/settings-personal.js b/apps/files_encryption/js/settings-personal.js index e4a1b7448f4..3b9b00dc797 100644 --- a/apps/files_encryption/js/settings-personal.js +++ b/apps/files_encryption/js/settings-personal.js @@ -9,15 +9,52 @@ $(document).ready(function(){ $( 'input:radio[name="userEnableRecovery"]' ).change( function() { + // Hide feedback messages in case they're already visible + $('#recoveryEnabledSuccess').hide(); + $('#recoveryEnabledError').hide(); + var recoveryStatus = $( this ).val(); $.post( OC.filePath( 'files_encryption', 'ajax', 'userrecovery.php' ) , { userEnableRecovery: recoveryStatus } , function( data ) { - alert( data ); + if ( data.status == "success" ) { + $('#recoveryEnabledSuccess').show(); + } else { + $('#recoveryEnabledError').show(); + } + } + ); + // Ensure page is not reloaded on form submit + return false; + } + ); + + $("#encryptAll").click( + function(){ + + // Hide feedback messages in case they're already visible + $('#encryptAllSuccess').hide(); + $('#encryptAllError').hide(); + + var userPassword = $( '#userPassword' ).val(); + var encryptAll = $( '#encryptAll' ).val(); + + $.post( + OC.filePath( 'files_encryption', 'ajax', 'encryptall.php' ) + , { encryptAll: encryptAll, userPassword: userPassword } + , function( data ) { + if ( data.status == "success" ) { + $('#encryptAllSuccess').show(); + } else { + $('#encryptAllError').show(); + } } ); + // Ensure page is not reloaded on form submit + return false; } + ); }) \ No newline at end of file diff --git a/apps/files_encryption/settings-personal.php b/apps/files_encryption/settings-personal.php index c6d9d80f0b9..46efb61b029 100644 --- a/apps/files_encryption/settings-personal.php +++ b/apps/files_encryption/settings-personal.php @@ -6,6 +6,9 @@ * See the COPYING-README file. */ +// Add CSS stylesheet +\OC_Util::addStyle( 'files_encryption', 'settings-personal' ); + $tmpl = new OCP\Template( 'files_encryption', 'settings-personal'); $blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) ); diff --git a/apps/files_encryption/templates/settings-personal.php b/apps/files_encryption/templates/settings-personal.php index c81f361ced9..00f567ecb26 100644 --- a/apps/files_encryption/templates/settings-personal.php +++ b/apps/files_encryption/templates/settings-personal.php @@ -1,15 +1,17 @@
- t( 'Encryption' )); ?> + t( 'Encryption' ) ); ?>

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

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

    @@ -20,17 +22,19 @@
- +

- t( "Enable password recovery by sharing all files with administrator:" )); ?> + +
+ t( "Enabling this option will allow you to reobtain access to your encrypted files if your password is lost" ) ); ?>
/> - t( "Enabled" )); ?> + t( "Enabled" ) ); ?>
/> - t( "Disabled" )); ?> + t( "Disabled" ) ); ?> +

t( 'File recovery settings updated' ) ); ?>
+
t( 'Could not update file recovery' ) ); ?>

+
+

+ +
+ t( "Use this if you suspect that you still have files which are unencrypted, or encrypted using ownCloud 4 or older." ) ); ?> +
+ + + +

t( 'Scan complete' ) );?>
+
t( 'Unable to scan and encrypt files' ) );?>
+

-- cgit v1.2.3 From 517efdf952526ce0f0a03107874baca18742c49b Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Mon, 13 May 2013 17:26:21 +0200 Subject: don't create a recovery user, only generate recovery key similar to the public link share key --- apps/files_encryption/ajax/adminrecovery.php | 122 ++++++++++----------- apps/files_encryption/js/settings-admin.js | 9 +- apps/files_encryption/lib/session.php | 10 +- apps/files_encryption/lib/util.php | 4 +- apps/files_encryption/templates/settings-admin.php | 17 +-- 5 files changed, 63 insertions(+), 99 deletions(-) (limited to 'apps/files_encryption/js') diff --git a/apps/files_encryption/ajax/adminrecovery.php b/apps/files_encryption/ajax/adminrecovery.php index c3c19943c0d..6a056dc7b3d 100644 --- a/apps/files_encryption/ajax/adminrecovery.php +++ b/apps/files_encryption/ajax/adminrecovery.php @@ -1,4 +1,5 @@ * This file is licensed under the Affero General Public License version 3 or later. @@ -6,87 +7,78 @@ * * @brief Script to handle admin settings for encrypted key recovery */ - use OCA\Encryption; \OCP\JSON::checkAdminUser(); -\OCP\JSON::checkAppEnabled( 'files_encryption' ); +\OCP\JSON::checkAppEnabled('files_encryption'); \OCP\JSON::callCheck(); -$return = $doSetup = false; +$return = false; // Enable recoveryAdmin -if ( - isset( $_POST['adminEnableRecovery'] ) - && 1 == $_POST['adminEnableRecovery'] -// && isset( $_POST['recoveryPassword'] ) -// && ! empty ( $_POST['recoveryPassword'] ) + +if ( + isset($_POST['adminEnableRecovery']) + && 1 == $_POST['adminEnableRecovery'] ) { - // TODO: Let the admin set this themselves - $recoveryAdminUid = 'recoveryAdmin'; - - // If desired recoveryAdmin UID is already in use - if ( ! \OC_User::userExists( $recoveryAdminUid ) ) { - - // Create new recoveryAdmin user - \OC_User::createUser( $recoveryAdminUid, $_POST['recoveryPassword'] ); - - // Make recovery user an administrator - \OC_Group::addToGroup ( $recoveryAdminUid, 'admin' ); - - $doSetup = true; - - } else { - - // Get list of admin users - $admins = OC_Group::usersInGroup( 'admin' ); - - // If the existing recoveryAdmin UID is an admin - if ( in_array( $recoveryAdminUid, $admins ) ) { - - // The desired recoveryAdmi UID pre-exists and can be used - $doSetup = true; - - // If the recoveryAdmin UID exists but doesn't have admin rights - } else { - - $return = false; - - } - + $view = new \OC\Files\View('/'); + + $recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); + + if ($recoveryKeyId === null) { + $recoveryKeyId = 'recovery_' . substr(md5(time()), 0, 8); + \OC_Appconfig::setValue('files_encryption', 'recoveryKeyId', $recoveryKeyId); } - - // Setup recoveryAdmin user for encryption - if ( $doSetup ) { - - $view = new \OC_FilesystemView( '/' ); - $util = new \OCA\Encryption\Util( $view, $recoveryAdminUid ); - - // Ensure recoveryAdmin is ready for encryption (has usable keypair etc.) - $util->setupServerSide( $_POST['recoveryPassword'] ); - - // Store the UID in the DB - OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminUid', $recoveryAdminUid ); - - $return = true; - + + if (!$view->is_dir('/owncloud_private_key')) { + $view->mkdir('/owncloud_private_key'); } - + + if ( + (!$view->file_exists("/public-keys/" . $recoveryKeyId . ".public.key") + || !$view->file_exists("/owncloud_private_key/" . $recoveryKeyId . ".private.key")) + && isset($_POST['recoveryPassword']) + && !empty($_POST['recoveryPassword']) + ) { + + $keypair = \OCA\Encryption\Crypt::createKeypair(); + + \OC_FileProxy::$enabled = false; + + // Save public key + + if (!$view->is_dir('/public-keys')) { + $view->mkdir('/public-keys'); + } + + $view->file_put_contents('/public-keys/' . $recoveryKeyId . '.public.key', $keypair['publicKey']); + + // Encrypt private key empthy passphrase + $encryptedPrivateKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($keypair['privateKey'], $_POST['recoveryPassword']); + + // Save private key + $view->file_put_contents('/owncloud_private_key/' . $recoveryKeyId . '.private.key', $encryptedPrivateKey); + + \OC_FileProxy::$enabled = true; + + } + // Set recoveryAdmin as enabled - OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminEnabled', 1 ); + OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); + + $return = true; // Disable recoveryAdmin -} elseif ( - isset( $_POST['adminEnableRecovery'] ) - && 0 == $_POST['adminEnableRecovery'] +} elseif ( + isset($_POST['adminEnableRecovery']) + && 0 == $_POST['adminEnableRecovery'] ) { - - // Set recoveryAdmin as enabled - OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminEnabled', 0 ); - - $return = true; + // Set recoveryAdmin as enabled + OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 0); + + $return = true; } // Return success or failure diff --git a/apps/files_encryption/js/settings-admin.js b/apps/files_encryption/js/settings-admin.js index 8e9c8c22306..9cdb7aca68a 100644 --- a/apps/files_encryption/js/settings-admin.js +++ b/apps/files_encryption/js/settings-admin.js @@ -7,13 +7,6 @@ $(document).ready(function(){ - // Trigger ajax on filetype blacklist change - $('#encryption_blacklist').multiSelect({ - oncheck:blackListChange, - onuncheck:blackListChange, - createText:'...' - }); - // Trigger ajax on recoveryAdmin status change $( 'input:radio[name="adminEnableRecovery"]' ).change( function() { @@ -24,7 +17,7 @@ $(document).ready(function(){ if ( '' == recoveryPassword ) { // FIXME: add proper OC notification - alert( 'You must set a recovery account password first' ); + alert( 'You must set a recovery account password first' ); } else { diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index 920f0b6a9a3..5444d0215ca 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -49,7 +49,7 @@ class Session { $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); if ($publicShareKeyId === null) { - $publicShareKeyId = substr(md5(time()),0,8); + $publicShareKeyId = 'pubShare_'.substr(md5(time()),0,8); \OC_Appconfig::setValue('files_encryption', 'publicShareKeyId', $publicShareKeyId); } @@ -57,13 +57,7 @@ class Session { ! $this->view->file_exists( "/public-keys/".$publicShareKeyId.".public.key" ) || ! $this->view->file_exists( "/owncloud_private_key/".$publicShareKeyId.".private.key" ) ) { - - //FIXME: Bug: for some reason file_exists is returning - // false in above if statement, and causing new keys - // to be generated on each page load. At last check - // our app.php is being executed 18 times per page load - // , causing 18 new keypairs and huge performance hit. - + $keypair = Crypt::createKeypair(); \OC_FileProxy::$enabled = false; diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 8162ae0a367..732f5fece85 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -958,10 +958,10 @@ class Util { if ( $recoveryEnabled ) { // Find recoveryAdmin user ID - $recoveryAdminUid = \OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminUid' ); + $recoveryKeyId = \OC_Appconfig::getValue( 'files_encryption', 'recoveryKeyId' ); // Add recoveryAdmin to list of users sharing - $userIds[] = $recoveryAdminUid; + $userIds[] = $recoveryKeyId; } diff --git a/apps/files_encryption/templates/settings-admin.php b/apps/files_encryption/templates/settings-admin.php index 863f1dfa9a5..be7beecf696 100644 --- a/apps/files_encryption/templates/settings-admin.php +++ b/apps/files_encryption/templates/settings-admin.php @@ -4,25 +4,10 @@

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

- - t( "Enable encryption passwords recovery account (allow sharing to recovery account):" )); ?> + t( "Enable encryption passwords recovery key (allow sharing to recovery key):" )); ?>
-
- t( "To perform a recovery log in using the 'recoveryAdmin' account and the specified password" )); ?>
-- cgit v1.2.3 From d8ae2fa80d004a7c9de7e1c6d012a6c0b6a423aa Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Wed, 15 May 2013 11:42:22 +0200 Subject: only let the user change the recovery admin settings if a key passwords was entered. --- apps/files_encryption/js/settings-admin.js | 41 +++++++++++----------- apps/files_encryption/settings-admin.php | 5 --- apps/files_encryption/templates/settings-admin.php | 12 +++---- 3 files changed, 25 insertions(+), 33 deletions(-) (limited to 'apps/files_encryption/js') diff --git a/apps/files_encryption/js/settings-admin.js b/apps/files_encryption/js/settings-admin.js index 9cdb7aca68a..2fffcf77b32 100644 --- a/apps/files_encryption/js/settings-admin.js +++ b/apps/files_encryption/js/settings-admin.js @@ -8,33 +8,32 @@ $(document).ready(function(){ // Trigger ajax on recoveryAdmin status change + var enabledStatus = $('#adminEnableRecovery').val(); + + $('input:password[name="recoveryPassword"]').keyup(function(event) { + var recoveryPassword = $( '#recoveryPassword' ).val(); + var checkedButton = $('input:radio[name="adminEnableRecovery"]:checked').val(); + var uncheckedValue = (1+parseInt(checkedButton)) % 2; + if (recoveryPassword != '' ) { + $('input:radio[name="adminEnableRecovery"][value="'+uncheckedValue.toString()+'"]').removeAttr("disabled"); + } else { + $('input:radio[name="adminEnableRecovery"][value="'+uncheckedValue.toString()+'"]').attr("disabled", "true"); + } + }); + $( 'input:radio[name="adminEnableRecovery"]' ).change( function() { var recoveryStatus = $( this ).val(); var recoveryPassword = $( '#recoveryPassword' ).val(); - - if ( '' == recoveryPassword ) { - - // FIXME: add proper OC notification - alert( 'You must set a recovery account password first' ); - - } else { - - $.post( - OC.filePath( 'files_encryption', 'ajax', 'adminrecovery.php' ) - , { adminEnableRecovery: recoveryStatus, recoveryPassword: recoveryPassword } - , function( data ) { - alert( data ); - } - ); - - } + $.post( + OC.filePath( 'files_encryption', 'ajax', 'adminrecovery.php' ) + , { adminEnableRecovery: recoveryStatus, recoveryPassword: recoveryPassword } + , function( data ) { + alert( data ); + } + ); } ); - function blackListChange(){ - var blackList=$( '#encryption_blacklist' ).val().join( ',' ); - OC.AppConfig.setValue( 'files_encryption', 'type_blacklist', blackList ); - } }) \ No newline at end of file diff --git a/apps/files_encryption/settings-admin.php b/apps/files_encryption/settings-admin.php index ae9a85643ef..66efc584367 100644 --- a/apps/files_encryption/settings-admin.php +++ b/apps/files_encryption/settings-admin.php @@ -10,18 +10,13 @@ $tmpl = new OCP\Template( 'files_encryption', 'settings-admin' ); -$blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) ); - // Check if an adminRecovery account is enabled for recovering files after lost pwd $view = new OC_FilesystemView( '' ); $recoveryAdminEnabled = OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' ); -$recoveryAdminUid = OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminUid' ); -$tmpl->assign( 'blacklist', $blackList ); $tmpl->assign( 'encryption_mode', \OC_Appconfig::getValue( 'files_encryption', 'mode', 'none' ) ); $tmpl->assign( 'recoveryEnabled', $recoveryAdminEnabled ); -$tmpl->assign( 'recoveryAdminUid', $recoveryAdminUid ); \OCP\Util::addscript( 'files_encryption', 'settings-admin' ); \OCP\Util::addscript( 'core', 'multiselect' ); diff --git a/apps/files_encryption/templates/settings-admin.php b/apps/files_encryption/templates/settings-admin.php index be7beecf696..95c1b66681c 100644 --- a/apps/files_encryption/templates/settings-admin.php +++ b/apps/files_encryption/templates/settings-admin.php @@ -9,16 +9,14 @@ t( "Enable encryption passwords recovery key (allow sharing to recovery key):" )); ?>

- - - -
- + + +
/> + /> t( "Enabled" )); ?>
@@ -26,7 +24,7 @@ type='radio' name='adminEnableRecovery' value='0' - /> + /> t( "Disabled" )); ?>

-- cgit v1.2.3 From 5b160edebba2a10de83b09a8010a811321dd6370 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Wed, 15 May 2013 14:02:13 +0200 Subject: check if the user knows the correct recovery password before changing the recovery key settings --- .gitignore | 1 + apps/files_encryption/ajax/adminrecovery.php | 63 +++++++++++++++++++++------- apps/files_encryption/hooks/hooks.php | 3 +- apps/files_encryption/js/settings-admin.js | 6 ++- apps/files_encryption/lib/crypt.php | 10 +++-- 5 files changed, 63 insertions(+), 20 deletions(-) (limited to 'apps/files_encryption/js') diff --git a/.gitignore b/.gitignore index b57dd3d2058..bc0c1d53a55 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,4 @@ data-autotest /tests/coverage* /tests/autoconfig* /tests/autotest* +/l10n/.tx/ \ No newline at end of file diff --git a/apps/files_encryption/ajax/adminrecovery.php b/apps/files_encryption/ajax/adminrecovery.php index 6a056dc7b3d..520c7156c89 100644 --- a/apps/files_encryption/ajax/adminrecovery.php +++ b/apps/files_encryption/ajax/adminrecovery.php @@ -15,16 +15,37 @@ use OCA\Encryption; $return = false; +function checkPassword($view, $password, $recoveryKeyId) { + $pathKey = '/owncloud_private_key/'. $recoveryKeyId . ".private.key"; + $pathControlData = '/control-file/controlfile.enc'; + + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $recoveryKey = $view->file_get_contents( $pathKey ); + + $decryptedRecoveryKey = \OCA\Encryption\Crypt::symmetricDecryptFileContent($recoveryKey, $password); + + $controlData = $view->file_get_contents($pathControlData); + $decryptedControlData = \OCA\Encryption\Crypt::keyDecrypt($controlData, $decryptedRecoveryKey); + + \OC_FileProxy::$enabled = $proxyStatus; + + if ($decryptedControlData === 'ownCloud') { + return true; + } else { + return false; + } +} + + // Enable recoveryAdmin -if ( - isset($_POST['adminEnableRecovery']) - && 1 == $_POST['adminEnableRecovery'] -) { +$recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); - $view = new \OC\Files\View('/'); +if (isset($_POST['adminEnableRecovery']) && $_POST['adminEnableRecovery'] == 1){ - $recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); + $view = new \OC\Files\View('/'); if ($recoveryKeyId === null) { $recoveryKeyId = 'recovery_' . substr(md5(time()), 0, 8); @@ -38,8 +59,6 @@ if ( if ( (!$view->file_exists("/public-keys/" . $recoveryKeyId . ".public.key") || !$view->file_exists("/owncloud_private_key/" . $recoveryKeyId . ".private.key")) - && isset($_POST['recoveryPassword']) - && !empty($_POST['recoveryPassword']) ) { $keypair = \OCA\Encryption\Crypt::createKeypair(); @@ -60,25 +79,39 @@ if ( // Save private key $view->file_put_contents('/owncloud_private_key/' . $recoveryKeyId . '.private.key', $encryptedPrivateKey); + // create control file which let us check later on if the entered password was correct. + $encryptedControlData = \OCA\Encryption\Crypt::keyEncrypt("ownCloud", $keypair['publicKey']); + if (!$view->is_dir('/control-file')) { + $view->mkdir('/control-file'); + } + $view->file_put_contents('/control-file/controlfile.enc', $encryptedControlData); + \OC_FileProxy::$enabled = true; - } + // Set recoveryAdmin as enabled + OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); - // Set recoveryAdmin as enabled - OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); + $return = true; - $return = true; + } else { // get recovery key and check the password + $return = checkPassword($view, $_POST['recoveryPassword'] ,$recoveryKeyId); + if ($return) { + OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); + } + } // Disable recoveryAdmin } elseif ( isset($_POST['adminEnableRecovery']) && 0 == $_POST['adminEnableRecovery'] ) { + $view = new \OC\Files\View('/'); + $return = checkPassword($view, $_POST['recoveryPassword'], $recoveryKeyId); - // Set recoveryAdmin as enabled + if ($return) { + // Set recoveryAdmin as disabled OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 0); - - $return = true; + } } // Return success or failure diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 31175d1c346..ed254fd8d8b 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -59,7 +59,8 @@ class Hooks { \OC_FileProxy::$enabled = true; - $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $params['password'] ); + //$privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $params['password'] ); + $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, "helloworld" ); $session = new Session( $view ); diff --git a/apps/files_encryption/js/settings-admin.js b/apps/files_encryption/js/settings-admin.js index 2fffcf77b32..fa353901c3f 100644 --- a/apps/files_encryption/js/settings-admin.js +++ b/apps/files_encryption/js/settings-admin.js @@ -25,12 +25,16 @@ $(document).ready(function(){ function() { var recoveryStatus = $( this ).val(); + var oldStatus = (1+parseInt(recoveryStatus)) % 2; var recoveryPassword = $( '#recoveryPassword' ).val(); $.post( OC.filePath( 'files_encryption', 'ajax', 'adminrecovery.php' ) , { adminEnableRecovery: recoveryStatus, recoveryPassword: recoveryPassword } , function( data ) { - alert( data ); + if (data.status == "error") { + alert("Couldn't switch recovery key mode, please check your recovery key password!"); + $('input:radio[name="adminEnableRecovery"][value="'+oldStatus.toString()+'"]').attr("checked", "true"); + } } ); } diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index f92930c2cbd..5267ba81f57 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -217,7 +217,7 @@ class Crypt { * @returns decrypted file */ public static function decrypt( $encryptedContent, $iv, $passphrase ) { - + if ( $plainContent = openssl_decrypt( $encryptedContent, 'AES-128-CFB', $passphrase, false, $iv ) ) { return $plainContent; @@ -463,9 +463,13 @@ class Crypt { */ public static function keyDecrypt( $encryptedContent, $privatekey ) { - openssl_private_decrypt( $encryptedContent, $plainContent, $privatekey ); + $result = @openssl_private_decrypt( $encryptedContent, $plainContent, $privatekey ); - return $plainContent; + if ( $result ) { + return $plainContent; + } + + return $result; } -- cgit v1.2.3 From 64d94c540aeaba67e2f779b2551c72a80334aa3e Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Wed, 15 May 2013 16:12:20 +0200 Subject: enable admin to change the recovery password --- apps/files_encryption/ajax/adminrecovery.php | 31 ++---------- apps/files_encryption/js/settings-admin.js | 59 ++++++++++++++++++++++ apps/files_encryption/lib/util.php | 28 ++++++++++ apps/files_encryption/settings-personal.php | 1 + apps/files_encryption/templates/settings-admin.php | 27 +++++++++- 5 files changed, 118 insertions(+), 28 deletions(-) (limited to 'apps/files_encryption/js') diff --git a/apps/files_encryption/ajax/adminrecovery.php b/apps/files_encryption/ajax/adminrecovery.php index 520c7156c89..0ab449709c3 100644 --- a/apps/files_encryption/ajax/adminrecovery.php +++ b/apps/files_encryption/ajax/adminrecovery.php @@ -15,30 +15,6 @@ use OCA\Encryption; $return = false; -function checkPassword($view, $password, $recoveryKeyId) { - $pathKey = '/owncloud_private_key/'. $recoveryKeyId . ".private.key"; - $pathControlData = '/control-file/controlfile.enc'; - - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - - $recoveryKey = $view->file_get_contents( $pathKey ); - - $decryptedRecoveryKey = \OCA\Encryption\Crypt::symmetricDecryptFileContent($recoveryKey, $password); - - $controlData = $view->file_get_contents($pathControlData); - $decryptedControlData = \OCA\Encryption\Crypt::keyDecrypt($controlData, $decryptedRecoveryKey); - - \OC_FileProxy::$enabled = $proxyStatus; - - if ($decryptedControlData === 'ownCloud') { - return true; - } else { - return false; - } -} - - // Enable recoveryAdmin $recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); @@ -94,7 +70,8 @@ if (isset($_POST['adminEnableRecovery']) && $_POST['adminEnableRecovery'] == 1){ $return = true; } else { // get recovery key and check the password - $return = checkPassword($view, $_POST['recoveryPassword'] ,$recoveryKeyId); + $util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \OCP\User::getUser()); + $return = $util->checkRecoveryPassword($_POST['recoveryPassword']); if ($return) { OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); } @@ -105,8 +82,8 @@ if (isset($_POST['adminEnableRecovery']) && $_POST['adminEnableRecovery'] == 1){ isset($_POST['adminEnableRecovery']) && 0 == $_POST['adminEnableRecovery'] ) { - $view = new \OC\Files\View('/'); - $return = checkPassword($view, $_POST['recoveryPassword'], $recoveryKeyId); + $util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \OCP\User::getUser()); + $return = $util->checkRecoveryPassword($_POST['recoveryPassword']); if ($return) { // Set recoveryAdmin as disabled diff --git a/apps/files_encryption/js/settings-admin.js b/apps/files_encryption/js/settings-admin.js index fa353901c3f..9bc6ab6433c 100644 --- a/apps/files_encryption/js/settings-admin.js +++ b/apps/files_encryption/js/settings-admin.js @@ -5,6 +5,27 @@ * See the COPYING-README file. */ +OC.msg={ + startSaving:function(selector){ + $(selector) + .html( t('settings', 'Saving...') ) + .removeClass('success') + .removeClass('error') + .stop(true, true) + .show(); + }, + finishedSaving:function(selector, data){ + if( data.status === "success" ){ + $(selector).html( data.data.message ) + .addClass('success') + .stop(true, true) + .delay(3000) + .fadeOut(900); + }else{ + $(selector).html( data.data.message ).addClass('error'); + } + } +}; $(document).ready(function(){ // Trigger ajax on recoveryAdmin status change @@ -34,10 +55,48 @@ $(document).ready(function(){ if (data.status == "error") { alert("Couldn't switch recovery key mode, please check your recovery key password!"); $('input:radio[name="adminEnableRecovery"][value="'+oldStatus.toString()+'"]').attr("checked", "true"); + } else { + if (recoveryStatus == "0") { + $('button:button[name="submitChangeRecoveryKey"]').attr("disabled", "true"); + $('input:password[name="changeRecoveryPassword"]').attr("disabled", "true"); + $('input:password[name="changeRecoveryPassword"]').val(""); + } else { + $('input:password[name="changeRecoveryPassword"]').removeAttr("disabled"); + } } } ); } ); + + // change password + + $('input:password[name="changeRecoveryPassword"]').keyup(function(event) { + var oldRecoveryPassword = $('input:password[id="oldRecoveryPassword"]').val(); + var newRecoveryPassword = $('input:password[id="newRecoveryPassword"]').val(); + if (newRecoveryPassword != '' && oldRecoveryPassword != '' ) { + $('button:button[name="submitChangeRecoveryKey"]').removeAttr("disabled"); + } else { + $('button:button[name="submitChangeRecoveryKey"]').attr("disabled", "true"); + } + }); + + + $('button:button[name="submitChangeRecoveryKey"]').click(function() { + var oldRecoveryPassword = $('input:password[id="oldRecoveryPassword"]').val(); + var newRecoveryPassword = $('input:password[id="newRecoveryPassword"]').val(); + OC.msg.startSaving('#encryption .msg'); + $.post( + OC.filePath( 'files_encryption', 'ajax', 'changeRecoveryPassword.php' ) + , { oldPassword: oldRecoveryPassword, newPassword: newRecoveryPassword } + , function( data ) { + if (data.status == "error") { + OC.msg.finishedSaving('#encryption .msg', data); + } else { + OC.msg.finishedSaving('#encryption .msg', data); + } + } + ); + }); }) \ No newline at end of file diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 19c9cd72a19..6cb4ccb8085 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -1282,4 +1282,32 @@ class Util { return $this->userFilesDir; } + public function checkRecoveryPassword($password) { + + $pathKey = '/owncloud_private_key/' . $this->recoveryKeyId . ".private.key"; + $pathControlData = '/control-file/controlfile.enc'; + + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $recoveryKey = $this->view->file_get_contents($pathKey); + + $decryptedRecoveryKey = Crypt::symmetricDecryptFileContent($recoveryKey, $password); + + $controlData = $this->view->file_get_contents($pathControlData); + $decryptedControlData = Crypt::keyDecrypt($controlData, $decryptedRecoveryKey); + + \OC_FileProxy::$enabled = $proxyStatus; + + if ($decryptedControlData === 'ownCloud') { + return true; + } + + return false; + } + + public function getRecoveryKeyId() { + return $this->recoveryKeyId; + } + } diff --git a/apps/files_encryption/settings-personal.php b/apps/files_encryption/settings-personal.php index 46efb61b029..90edc0eae24 100644 --- a/apps/files_encryption/settings-personal.php +++ b/apps/files_encryption/settings-personal.php @@ -32,6 +32,7 @@ $recoveryAdminEnabled = OC_Appconfig::getValue( 'files_encryption', 'recoveryAdm $recoveryEnabledForUser = $util->recoveryEnabledForUser(); \OCP\Util::addscript( 'files_encryption', 'settings-personal' ); +\OCP\Util::addScript( 'settings', 'personal' ); $tmpl->assign( 'recoveryEnabled', $recoveryAdminEnabled ); $tmpl->assign( 'recoveryEnabledForUser', $recoveryEnabledForUser ); diff --git a/apps/files_encryption/templates/settings-admin.php b/apps/files_encryption/templates/settings-admin.php index 95c1b66681c..18fea1845f4 100644 --- a/apps/files_encryption/templates/settings-admin.php +++ b/apps/files_encryption/templates/settings-admin.php @@ -10,7 +10,7 @@

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

+

+

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

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

-- cgit v1.2.3 From 9d1e60325c6f478484ff8f70ff3cd13d9d7d4913 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Thu, 16 May 2013 14:53:04 +0200 Subject: allow admin to recover users files in case of password lost --- apps/files_encryption/hooks/hooks.php | 73 +++++++++++++++++++------- apps/files_encryption/js/settings-admin.js | 2 +- apps/files_encryption/lib/helper.php | 2 +- apps/files_encryption/lib/util.php | 84 +++++++++++++++++++++++++++++- lib/user.php | 7 +-- settings/ajax/changepassword.php | 5 +- settings/css/settings.css | 2 + settings/js/users.js | 4 +- settings/templates/personal.php | 2 +- settings/templates/users.php | 5 ++ settings/users.php | 3 ++ 11 files changed, 159 insertions(+), 30 deletions(-) (limited to 'apps/files_encryption/js') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index f843c7027d5..0af0845d7c1 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -142,32 +142,67 @@ class Hooks { * @brief Change a user's encryption passphrase * @param array $params keys: uid, password */ - public static function setPassphrase( $params ) { - + public static function setPassphrase($params) { + // Only attempt to change passphrase if server-side encryption // is in use (client-side encryption does not have access to // the necessary keys) - if ( Crypt::mode() == 'server' ) { + if (Crypt::mode() == 'server') { - $view = new \OC_FilesystemView( '/' ); + if ($params['uid'] == \OCP\User::getUser()) { - $session = new Session($view); - - // Get existing decrypted private key - $privateKey = $session->getPrivateKey(); - - // Encrypt private key with new user pwd as passphrase - $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $privateKey, $params['password'] ); - - // Save private key - Keymanager::setPrivateKey( $encryptedPrivateKey ); - - // NOTE: Session does not need to be updated as the - // private key has not changed, only the passphrase - // used to decrypt it has changed + $view = new \OC_FilesystemView('/'); + + $session = new Session($view); + + // Get existing decrypted private key + $privateKey = $session->getPrivateKey(); + + // Encrypt private key with new user pwd as passphrase + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($privateKey, $params['password']); + + // Save private key + Keymanager::setPrivateKey($encryptedPrivateKey); + + // NOTE: Session does not need to be updated as the + // private key has not changed, only the passphrase + // used to decrypt it has changed + + } else { // admin changed the password for a different user, create new keys and reencrypt file keys + + $user = $params['uid']; + $recoveryPassword = $params['recoveryPassword']; + $newUserPassword = $params['password']; + + $view = new \OC_FilesystemView('/'); + + // make sure that the users home is mounted + \OC\Files\Filesystem::initMountPoints($user); + + $keypair = Crypt::createKeypair(); + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + // Save public key + $view->file_put_contents( '/public-keys/'.$user.'.public.key', $keypair['publicKey'] ); + + // Encrypt private key empthy passphrase + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], $newUserPassword ); + + // Save private key + $view->file_put_contents( '/'.$user.'/files_encryption/'.$user.'.private.key', $encryptedPrivateKey ); + + if ( $recoveryPassword ) { // if recovery key is set we can re-encrypt the key files + $util = new Util($view, $user); + $util->recoverUsersFiles($recoveryPassword); + } + + \OC_FileProxy::$enabled = $proxyStatus; + } } - } /* diff --git a/apps/files_encryption/js/settings-admin.js b/apps/files_encryption/js/settings-admin.js index 9bc6ab6433c..dbae42b011c 100644 --- a/apps/files_encryption/js/settings-admin.js +++ b/apps/files_encryption/js/settings-admin.js @@ -69,7 +69,7 @@ $(document).ready(function(){ } ); - // change password + // change recovery password $('input:password[name="changeRecoveryPassword"]').keyup(function(event) { var oldRecoveryPassword = $('input:password[id="oldRecoveryPassword"]').val(); diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php index 6d5aae4e8b5..86d860465e6 100755 --- a/apps/files_encryption/lib/helper.php +++ b/apps/files_encryption/lib/helper.php @@ -46,7 +46,7 @@ class Helper { public static function registerUserHooks() { \OCP\Util::connectHook( 'OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login' ); - \OCP\Util::connectHook( 'OC_User', 'pre_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase' ); + \OCP\Util::connectHook( 'OC_User', 'post_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase' ); \OCP\Util::connectHook( 'OC_User', 'post_createUser', 'OCA\Encryption\Hooks', 'postCreateUser' ); \OCP\Util::connectHook( 'OC_User', 'post_deleteUser', 'OCA\Encryption\Hooks', 'postDeleteUser' ); } diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 91d86cc8558..fab807b0141 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -929,7 +929,7 @@ class Util { // Get the current users's private key for decrypting existing keyfile $privateKey = $session->getPrivateKey(); - + $fileOwner = \OC\Files\Filesystem::getOwner( $filePath ); // Decrypt keyfile @@ -1336,7 +1336,7 @@ class Util { } } - /** + /** * @brief remove recovery key to all encrypted files */ public function removeRecoveryKeys($path = '/') { @@ -1351,4 +1351,84 @@ class Util { } } } + + /** + * @brief decrypt given file with recovery key and encrypt it again to the owner and his new key + * @param type $file + * @param type $privateKey recovery key to decrypt the file + */ + private function recoverFile($file, $privateKey) { + + $sharingEnabled = \OCP\Share::isEnabled(); + + // Find out who, if anyone, is sharing the file + if ($sharingEnabled) { + $result = \OCP\Share::getUsersSharingFile($file, $this->userId, true, true, true); + $userIds = $result['users']; + $userIds[] = $this->recoveryKeyId; + if ($result['public']) { + $userIds[] = $this->publicShareKeyId; + } + } else { + $userIds = array($this->userId, $this->recoveryKeyId); + } + $filteredUids = $this->filterShareReadyUsers($userIds); + + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + //decrypt file key + $encKeyfile = $this->view->file_get_contents($this->keyfilesPath.$file.".key"); + $shareKey = $this->view->file_get_contents($this->shareKeysPath.$file.".".$this->recoveryKeyId.".shareKey"); + $plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + // encrypt file key again to all users, this time with the new public key for the recovered use + $userPubKeys = Keymanager::getPublicKeys($this->view, $filteredUids['ready']); + $multiEncKey = Crypt::multiKeyEncrypt($plainKeyfile, $userPubKeys); + + // write new keys to filesystem TDOO! + $this->view->file_put_contents($this->keyfilesPath.$file.'.key', $multiEncKey['data']); + foreach ($multiEncKey['keys'] as $userId => $shareKey) { + $shareKeyPath = $this->shareKeysPath.$file.'.'.$userId.'.shareKey'; + $this->view->file_put_contents($shareKeyPath, $shareKey); + } + + // Return proxy to original status + \OC_FileProxy::$enabled = $proxyStatus; + } + + /** + * @brief collect all files and recover them one by one + * @param type $path to look for files keys + * @param type $privateKey private recovery key which is used to decrypt the files + */ + private function recoverAllFiles($path, $privateKey) { + $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path); + foreach ($dirContent as $item) { + $filePath = substr($item['path'], 25); + if ($item['type'] == 'dir') { + $this->addRecoveryKey($filePath . '/', $privateKey); + } else { + $file = substr($filePath, 0, -4); + $this->recoverFile($file, $privateKey); + } + } + } + + /** + * @brief recover users files in case of password lost + * @param type $recoveryPassword + */ + public function recoverUsersFiles($recoveryPassword) { + + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $encryptedKey = $this->view->file_get_contents( '/owncloud_private_key/'.$this->recoveryKeyId.'.private.key' ); + $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $recoveryPassword ); + + \OC_FileProxy::$enabled = $proxyStatus; + + $this->recoverAllFiles('/', $privateKey); + } } diff --git a/lib/user.php b/lib/user.php index 226b716188d..833e8866592 100644 --- a/lib/user.php +++ b/lib/user.php @@ -393,13 +393,14 @@ class OC_User { * @brief Set password * @param $uid The username * @param $password The new password + * @param $recoveryPassword for the encryption app to reset encryption keys * @returns true/false * * Change the password of a user */ - public static function setPassword( $uid, $password ) { + public static function setPassword( $uid, $password, $recoveryPassword = null ) { $run = true; - OC_Hook::emit( "OC_User", "pre_setPassword", array( "run" => &$run, "uid" => $uid, "password" => $password )); + OC_Hook::emit( "OC_User", "pre_setPassword", array( "run" => &$run, "uid" => $uid, "password" => $password, "recoveryPassword" => $recoveryPassword )); if( $run ) { $success = false; @@ -412,7 +413,7 @@ class OC_User { } // invalidate all login cookies OC_Preferences::deleteApp($uid, 'login_token'); - OC_Hook::emit( "OC_User", "post_setPassword", array( "uid" => $uid, "password" => $password )); + OC_Hook::emit( "OC_User", "post_setPassword", array( "uid" => $uid, "password" => $password, "recoveryPassword" => $recoveryPassword )); return $success; } else{ diff --git a/settings/ajax/changepassword.php b/settings/ajax/changepassword.php index 4f16bff63d5..fe63f27a6e2 100644 --- a/settings/ajax/changepassword.php +++ b/settings/ajax/changepassword.php @@ -8,8 +8,9 @@ OC_JSON::checkLoggedIn(); OC_APP::loadApps(); $username = isset($_POST["username"]) ? $_POST["username"] : OC_User::getUser(); -$password = isset($_POST["newpassword"]) ? $_POST["newpassword"] : null; +$password = isset($_POST["password"]) ? $_POST["password"] : null; $oldPassword=isset($_POST["oldpassword"])?$_POST["oldpassword"]:''; +$recoveryPassword=isset($_POST["recoveryPassword"])?$_POST["recoveryPassword"]:null; $userstatus = null; if(OC_User::isAdminUser(OC_User::getUser())) { @@ -28,7 +29,7 @@ if(is_null($userstatus)) { } // Return Success story -if(!is_null($password) && OC_User::setPassword( $username, $password )) { +if(!is_null($password) && OC_User::setPassword( $username, $password, $recoveryPassword )) { OC_JSON::success(array("data" => array( "username" => $username ))); } else{ diff --git a/settings/css/settings.css b/settings/css/settings.css index 46a0bbe7c32..950e8929012 100644 --- a/settings/css/settings.css +++ b/settings/css/settings.css @@ -45,6 +45,8 @@ table:not(.nostyle) { width:100%; } #rightcontent { padding-left: 1em; } div.quota { float:right; display:block; position:absolute; right:25em; top:-1px; } div.quota-select-wrapper { position: relative; } +div.recoveryPassword { left:50em; display:block; position:absolute; top:-1px; } +input#recoveryPassword {width:15em;} select.quota { position:absolute; left:0; top:0; width:10em; } select.quota-user { position:relative; left:0; top:0; width:10em; } div.quota>span { position:absolute; right:0; white-space:nowrap; top:.7em; color:#888; text-shadow:0 1px 0 #fff; } diff --git a/settings/js/users.js b/settings/js/users.js index 690c9ad0464..9bd7f31f0b2 100644 --- a/settings/js/users.js +++ b/settings/js/users.js @@ -351,9 +351,11 @@ $(document).ready(function () { input.keypress(function (event) { if (event.keyCode == 13) { if ($(this).val().length > 0) { + var recoveryPasswordVal = $('input:password[id="recoveryPassword"]').val(); + console.log("RECOVERY PASSWD: " + recoveryPasswordVal); $.post( OC.filePath('settings', 'ajax', 'changepassword.php'), - {username: uid, password: $(this).val()}, + {username: uid, password: $(this).val(), recoveryPassword: recoveryPasswordVal}, function (result) { } ); diff --git a/settings/templates/personal.php b/settings/templates/personal.php index cfb45e99c4d..da812e8ed9a 100644 --- a/settings/templates/personal.php +++ b/settings/templates/personal.php @@ -38,7 +38,7 @@ if($_['passwordChangeSupported']) {
t('Your password was changed');?>
t('Unable to change your password');?>
- diff --git a/settings/templates/users.php b/settings/templates/users.php index e86dd46efbe..a6df85983dd 100644 --- a/settings/templates/users.php +++ b/settings/templates/users.php @@ -29,6 +29,11 @@ $_['subadmingroups'] = array_flip($items); + +
+ +
+
t('Default Storage'));?> diff --git a/settings/users.php b/settings/users.php index 94e6d0a9a10..e5c8a7aaa8d 100644 --- a/settings/users.php +++ b/settings/users.php @@ -20,6 +20,8 @@ $users = array(); $groups = array(); $isadmin = OC_User::isAdminUser(OC_User::getUser()); +$recoveryAdminEnabled = OC_App::isEnabled('files_encryption') && + OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' ); if($isadmin) { $accessiblegroups = OC_Group::getGroups(); @@ -77,4 +79,5 @@ $tmpl->assign( 'numofgroups', count($accessiblegroups)); $tmpl->assign( 'quota_preset', $quotaPreset); $tmpl->assign( 'default_quota', $defaultQuota); $tmpl->assign( 'defaultQuotaIsUserDefined', $defaultQuotaIsUserDefined); +$tmpl->assign( 'recoveryAdminEnabled', $recoveryAdminEnabled); $tmpl->printPage(); -- cgit v1.2.3 From 15a3ae6db14fd021d3c9ca672a8afc98b86cf174 Mon Sep 17 00:00:00 2001 From: Björn Schießle Date: Wed, 22 May 2013 18:01:18 +0200 Subject: improved error messages --- apps/files_encryption/ajax/adminrecovery.php | 8 +++++++- apps/files_encryption/js/settings-admin.js | 10 +++++----- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'apps/files_encryption/js') diff --git a/apps/files_encryption/ajax/adminrecovery.php b/apps/files_encryption/ajax/adminrecovery.php index a32225d0366..306f0088be3 100644 --- a/apps/files_encryption/ajax/adminrecovery.php +++ b/apps/files_encryption/ajax/adminrecovery.php @@ -22,6 +22,7 @@ $recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); if (isset($_POST['adminEnableRecovery']) && $_POST['adminEnableRecovery'] == 1){ $return = \OCA\Encryption\Helper::adminEnableRecovery($recoveryKeyId, $_POST['recoveryPassword']); + $action = "enable"; // Disable recoveryAdmin } elseif ( @@ -29,7 +30,12 @@ if (isset($_POST['adminEnableRecovery']) && $_POST['adminEnableRecovery'] == 1){ && 0 == $_POST['adminEnableRecovery'] ) { $return = \OCA\Encryption\Helper::adminDisableRecovery($_POST['recoveryPassword']); + $action = "disable"; } // Return success or failure -( $return ) ? \OCP\JSON::success() : \OCP\JSON::error(); \ No newline at end of file +if ($return) { + \OCP\JSON::success(array("data" => array( "message" => 'Recovery key successfully ' . $action.'d'))); +} else { + \OCP\JSON::error(array("data" => array( "message" => 'Could not '.$action.' recovery key. Please check your recovery key password!'))); +} diff --git a/apps/files_encryption/js/settings-admin.js b/apps/files_encryption/js/settings-admin.js index dbae42b011c..c58d75341df 100644 --- a/apps/files_encryption/js/settings-admin.js +++ b/apps/files_encryption/js/settings-admin.js @@ -44,19 +44,19 @@ $(document).ready(function(){ $( 'input:radio[name="adminEnableRecovery"]' ).change( function() { - var recoveryStatus = $( this ).val(); var oldStatus = (1+parseInt(recoveryStatus)) % 2; var recoveryPassword = $( '#recoveryPassword' ).val(); $.post( OC.filePath( 'files_encryption', 'ajax', 'adminrecovery.php' ) , { adminEnableRecovery: recoveryStatus, recoveryPassword: recoveryPassword } - , function( data ) { - if (data.status == "error") { - alert("Couldn't switch recovery key mode, please check your recovery key password!"); + , function( result ) { + if (result.status === "error") { + OC.Notification.show(t('admin', result.data.message)); $('input:radio[name="adminEnableRecovery"][value="'+oldStatus.toString()+'"]').attr("checked", "true"); } else { - if (recoveryStatus == "0") { + OC.Notification.hide(); + if (recoveryStatus === "0") { $('button:button[name="submitChangeRecoveryKey"]').attr("disabled", "true"); $('input:password[name="changeRecoveryPassword"]').attr("disabled", "true"); $('input:password[name="changeRecoveryPassword"]').val(""); -- cgit v1.2.3 From 6c8de5ae6d11886d498e810808484a2bdfeaef12 Mon Sep 17 00:00:00 2001 From: Florin Peter Date: Thu, 23 May 2013 23:56:31 +0200 Subject: fixes after review from @DeepDiver1975 --- apps/files_encryption/hooks/hooks.php | 2 +- apps/files_encryption/js/settings-admin.js | 2 +- apps/files_encryption/js/settings-personal.js | 2 +- apps/files_encryption/lib/crypt.php | 246 ++++----- apps/files_encryption/lib/helper.php | 92 ++-- apps/files_encryption/lib/keymanager.php | 230 ++++---- apps/files_encryption/lib/proxy.php | 204 ++++--- apps/files_encryption/lib/session.php | 64 +-- apps/files_encryption/lib/stream.php | 170 +++--- apps/files_encryption/lib/util.php | 601 ++++++++++----------- apps/files_encryption/settings-admin.php | 1 - apps/files_encryption/settings-personal.php | 1 - .../templates/settings-personal.php | 13 - 13 files changed, 752 insertions(+), 876 deletions(-) (limited to 'apps/files_encryption/js') diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 53afefc721b..2066300a163 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -189,7 +189,7 @@ class Hooks { // Save public key $view->file_put_contents( '/public-keys/'.$user.'.public.key', $keypair['publicKey'] ); - // Encrypt private key empthy passphrase + // Encrypt private key empty passphrase $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], $newUserPassword ); // Save private key diff --git a/apps/files_encryption/js/settings-admin.js b/apps/files_encryption/js/settings-admin.js index c58d75341df..7c1866445ee 100644 --- a/apps/files_encryption/js/settings-admin.js +++ b/apps/files_encryption/js/settings-admin.js @@ -99,4 +99,4 @@ $(document).ready(function(){ ); }); -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/apps/files_encryption/js/settings-personal.js b/apps/files_encryption/js/settings-personal.js index 3b9b00dc797..312b672ad46 100644 --- a/apps/files_encryption/js/settings-personal.js +++ b/apps/files_encryption/js/settings-personal.js @@ -57,4 +57,4 @@ $(document).ready(function(){ } ); -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 1a5c9300a27..f5b7a8a0a40 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -26,7 +26,7 @@ namespace OCA\Encryption; //require_once '../3rdparty/Crypt_Blowfish/Blowfish.php'; -require_once realpath(dirname(__FILE__) . '/../3rdparty/Crypt_Blowfish/Blowfish.php'); +require_once realpath( dirname( __FILE__ ) . '/../3rdparty/Crypt_Blowfish/Blowfish.php' ); /** * Class for common cryptography functionality @@ -40,8 +40,7 @@ class Crypt * @param string $user name (use system wide setting if name=null) * @return string 'client' or 'server' */ - public static function mode($user = null) - { + public static function mode( $user = null ) { return 'server'; @@ -51,20 +50,19 @@ class Crypt * @brief Create a new encryption keypair * @return array publicKey, privatekey */ - public static function createKeypair() - { + public static function createKeypair() { - $res = openssl_pkey_new(array('private_key_bits' => 4096)); + $res = openssl_pkey_new( array( 'private_key_bits' => 4096 ) ); // Get private key - openssl_pkey_export($res, $privateKey); + openssl_pkey_export( $res, $privateKey ); // Get public key - $publicKey = openssl_pkey_get_details($res); + $publicKey = openssl_pkey_get_details( $res ); $publicKey = $publicKey['key']; - return (array('publicKey' => $publicKey, 'privateKey' => $privateKey)); + return ( array( 'publicKey' => $publicKey, 'privateKey' => $privateKey ) ); } @@ -77,8 +75,7 @@ class Crypt * blocks with encryption alone, hence padding is added to achieve the * required length. */ - public static function addPadding($data) - { + public static function addPadding( $data ) { $padded = $data . 'xx'; @@ -91,12 +88,11 @@ class Crypt * @param string $padded padded data to remove padding from * @return string unpadded data on success, false on error */ - public static function removePadding($padded) - { + public static function removePadding( $padded ) { - if (substr($padded, -2) == 'xx') { + if ( substr( $padded, -2 ) == 'xx' ) { - $data = substr($padded, 0, -2); + $data = substr( $padded, 0, -2 ); return $data; @@ -115,27 +111,26 @@ class Crypt * @return boolean * @note see also OCA\Encryption\Util->isEncryptedPath() */ - public static function isCatfileContent($content) - { + public static function isCatfileContent( $content ) { - if (!$content) { + if ( !$content ) { return false; } - $noPadding = self::removePadding($content); + $noPadding = self::removePadding( $content ); // Fetch encryption metadata from end of file - $meta = substr($noPadding, -22); + $meta = substr( $noPadding, -22 ); // Fetch IV from end of file - $iv = substr($meta, -16); + $iv = substr( $meta, -16 ); // Fetch identifier from start of metadata - $identifier = substr($meta, 0, 6); + $identifier = substr( $meta, 0, 6 ); - if ($identifier == '00iv00') { + if ( $identifier == '00iv00' ) { return true; @@ -152,16 +147,15 @@ class Crypt * @param string $path * @return bool */ - public static function isEncryptedMeta($path) - { + public static function isEncryptedMeta( $path ) { // TODO: Use DI to get \OC\Files\Filesystem out of here // Fetch all file metadata from DB - $metadata = \OC\Files\Filesystem::getFileInfo($path); + $metadata = \OC\Files\Filesystem::getFileInfo( $path ); // Return encryption status - return isset($metadata['encrypted']) and ( bool )$metadata['encrypted']; + return isset( $metadata['encrypted'] ) and ( bool )$metadata['encrypted']; } @@ -172,19 +166,18 @@ class Crypt * e.g. filename or /Docs/filename, NOT admin/files/filename * @return boolean */ - public static function isLegacyEncryptedContent($data, $relPath) - { + public static function isLegacyEncryptedContent( $data, $relPath ) { // Fetch all file metadata from DB - $metadata = \OC\Files\Filesystem::getFileInfo($relPath, ''); + $metadata = \OC\Files\Filesystem::getFileInfo( $relPath, '' ); // If a file is flagged with encryption in DB, but isn't a // valid content + IV combination, it's probably using the // legacy encryption system if ( - isset($metadata['encrypted']) + isset( $metadata['encrypted'] ) and $metadata['encrypted'] === true - and !self::isCatfileContent($data) + and !self::isCatfileContent( $data ) ) { return true; @@ -199,18 +192,20 @@ class Crypt /** * @brief Symmetrically encrypt a string + * @param $plainContent + * @param $iv + * @param string $passphrase * @return string encrypted file content */ - public static function encrypt($plainContent, $iv, $passphrase = '') - { + public static function encrypt( $plainContent, $iv, $passphrase = '' ) { - if ($encryptedContent = openssl_encrypt($plainContent, 'AES-128-CFB', $passphrase, false, $iv)) { + if ( $encryptedContent = openssl_encrypt( $plainContent, 'AES-128-CFB', $passphrase, false, $iv ) ) { return $encryptedContent; } else { - \OC_Log::write('Encryption library', 'Encryption (symmetric) of content failed', \OC_Log::ERROR); + \OC_Log::write( 'Encryption library', 'Encryption (symmetric) of content failed', \OC_Log::ERROR ); return false; @@ -220,21 +215,21 @@ class Crypt /** * @brief Symmetrically decrypt a string + * @param $encryptedContent + * @param $iv + * @param $passphrase + * @throws \Exception * @return string decrypted file content */ - public static function decrypt($encryptedContent, $iv, $passphrase) - { + public static function decrypt( $encryptedContent, $iv, $passphrase ) { - if ($plainContent = openssl_decrypt($encryptedContent, 'AES-128-CFB', $passphrase, false, $iv)) { + if ( $plainContent = openssl_decrypt( $encryptedContent, 'AES-128-CFB', $passphrase, false, $iv ) ) { return $plainContent; - } else { - throw new \Exception('Encryption library: Decryption (symmetric) of content failed'); - - return false; + throw new \Exception( 'Encryption library: Decryption (symmetric) of content failed' ); } @@ -246,8 +241,7 @@ class Crypt * @param string $iv IV to be concatenated * @returns string concatenated content */ - public static function concatIv($content, $iv) - { + public static function concatIv( $content, $iv ) { $combined = $content . '00iv00' . $iv; @@ -260,17 +254,16 @@ class Crypt * @param string $catFile concatenated data to be split * @returns array keys: encrypted, iv */ - public static function splitIv($catFile) - { + public static function splitIv( $catFile ) { // Fetch encryption metadata from end of file - $meta = substr($catFile, -22); + $meta = substr( $catFile, -22 ); // Fetch IV from end of file - $iv = substr($meta, -16); + $iv = substr( $meta, -16 ); // Remove IV and IV identifier text to expose encrypted content - $encrypted = substr($catFile, 0, -22); + $encrypted = substr( $catFile, 0, -22 ); $split = array( 'encrypted' => $encrypted @@ -290,10 +283,9 @@ class Crypt * @note IV need not be specified, as it will be stored in the returned keyfile * and remain accessible therein. */ - public static function symmetricEncryptFileContent($plainContent, $passphrase = '') - { + public static function symmetricEncryptFileContent( $plainContent, $passphrase = '' ) { - if (!$plainContent) { + if ( !$plainContent ) { return false; @@ -301,18 +293,18 @@ class Crypt $iv = self::generateIv(); - if ($encryptedContent = self::encrypt($plainContent, $iv, $passphrase)) { + if ( $encryptedContent = self::encrypt( $plainContent, $iv, $passphrase ) ) { // Combine content to encrypt with IV identifier and actual IV - $catfile = self::concatIv($encryptedContent, $iv); + $catfile = self::concatIv( $encryptedContent, $iv ); - $padded = self::addPadding($catfile); + $padded = self::addPadding( $catfile ); return $padded; } else { - \OC_Log::write('Encryption library', 'Encryption (symmetric) of keyfile content failed', \OC_Log::ERROR); + \OC_Log::write( 'Encryption library', 'Encryption (symmetric) of keyfile content failed', \OC_Log::ERROR ); return false; @@ -334,25 +326,26 @@ class Crypt * * This function decrypts a file */ - public static function symmetricDecryptFileContent($keyfileContent, $passphrase = '') - { + public static function symmetricDecryptFileContent( $keyfileContent, $passphrase = '' ) { - if (!$keyfileContent) { + if ( !$keyfileContent ) { - throw new \Exception('Encryption library: no data provided for decryption'); + throw new \Exception( 'Encryption library: no data provided for decryption' ); } // Remove padding - $noPadding = self::removePadding($keyfileContent); + $noPadding = self::removePadding( $keyfileContent ); // Split into enc data and catfile - $catfile = self::splitIv($noPadding); + $catfile = self::splitIv( $noPadding ); - if ($plainContent = self::decrypt($catfile['encrypted'], $catfile['iv'], $passphrase)) { + if ( $plainContent = self::decrypt( $catfile['encrypted'], $catfile['iv'], $passphrase ) ) { return $plainContent; + } else { + return false; } } @@ -365,16 +358,15 @@ class Crypt * * This function decrypts a file */ - public static function symmetricEncryptFileContentKeyfile($plainContent) - { + public static function symmetricEncryptFileContentKeyfile( $plainContent ) { $key = self::generateKey(); - if ($encryptedContent = self::symmetricEncryptFileContent($plainContent, $key)) { + if ( $encryptedContent = self::symmetricEncryptFileContent( $plainContent, $key ) ) { return array( - 'key' => $key - , 'encrypted' => $encryptedContent + 'key' => $key, + 'encrypted' => $encryptedContent ); } else { @@ -392,29 +384,28 @@ class Crypt * @returns array keys: keys (array, key = userId), data * @note symmetricDecryptFileContent() can decrypt files created using this method */ - public static function multiKeyEncrypt($plainContent, array $publicKeys) - { + public static function multiKeyEncrypt( $plainContent, array $publicKeys ) { // openssl_seal returns false without errors if $plainContent // is empty, so trigger our own error - if (empty($plainContent)) { + if ( empty( $plainContent ) ) { - trigger_error("Cannot mutliKeyEncrypt empty plain content"); - throw new \Exception('Cannot mutliKeyEncrypt empty plain content'); + throw new \Exception( 'Cannot mutliKeyEncrypt empty plain content' ); } // Set empty vars to be set by openssl by reference $sealed = ''; $shareKeys = array(); + $mappedShareKeys = array(); - if (openssl_seal($plainContent, $sealed, $shareKeys, $publicKeys)) { + if ( openssl_seal( $plainContent, $sealed, $shareKeys, $publicKeys ) ) { $i = 0; // Ensure each shareKey is labelled with its // corresponding userId - foreach ($publicKeys as $userId => $publicKey) { + foreach ( $publicKeys as $userId => $publicKey ) { $mappedShareKeys[$userId] = $shareKeys[$i]; $i++; @@ -422,8 +413,8 @@ class Crypt } return array( - 'keys' => $mappedShareKeys - , 'data' => $sealed + 'keys' => $mappedShareKeys, + 'data' => $sealed ); } else { @@ -446,22 +437,21 @@ class Crypt * * This function decrypts a file */ - public static function multiKeyDecrypt($encryptedContent, $shareKey, $privateKey) - { + public static function multiKeyDecrypt( $encryptedContent, $shareKey, $privateKey ) { - if (!$encryptedContent) { + if ( !$encryptedContent ) { return false; } - if (openssl_open($encryptedContent, $plainContent, $shareKey, $privateKey)) { + if ( openssl_open( $encryptedContent, $plainContent, $shareKey, $privateKey ) ) { return $plainContent; } else { - \OC_Log::write('Encryption library', 'Decryption (asymmetric) of sealed content failed', \OC_Log::ERROR); + \OC_Log::write( 'Encryption library', 'Decryption (asymmetric) of sealed content failed', \OC_Log::ERROR ); return false; @@ -473,10 +463,9 @@ class Crypt * @brief Asymetrically encrypt a string using a public key * @return string encrypted file */ - public static function keyEncrypt($plainContent, $publicKey) - { + public static function keyEncrypt( $plainContent, $publicKey ) { - openssl_public_encrypt($plainContent, $encryptedContent, $publicKey); + openssl_public_encrypt( $plainContent, $encryptedContent, $publicKey ); return $encryptedContent; @@ -486,12 +475,11 @@ class Crypt * @brief Asymetrically decrypt a file using a private key * @return string decrypted file */ - public static function keyDecrypt($encryptedContent, $privatekey) - { + public static function keyDecrypt( $encryptedContent, $privatekey ) { - $result = @openssl_private_decrypt($encryptedContent, $plainContent, $privatekey); + $result = @openssl_private_decrypt( $encryptedContent, $plainContent, $privatekey ); - if ($result) { + if ( $result ) { return $plainContent; } @@ -503,27 +491,26 @@ class Crypt * @brief Generates a pseudo random initialisation vector * @return String $iv generated IV */ - public static function generateIv() - { + public static function generateIv() { - if ($random = openssl_random_pseudo_bytes(12, $strong)) { + if ( $random = openssl_random_pseudo_bytes( 12, $strong ) ) { - if (!$strong) { + if ( !$strong ) { // If OpenSSL indicates randomness is insecure, log error - \OC_Log::write('Encryption library', 'Insecure symmetric key was generated using openssl_random_pseudo_bytes()', \OC_Log::WARN); + \OC_Log::write( 'Encryption library', 'Insecure symmetric key was generated using openssl_random_pseudo_bytes()', \OC_Log::WARN ); } // We encode the iv purely for string manipulation // purposes - it gets decoded before use - $iv = base64_encode($random); + $iv = base64_encode( $random ); return $iv; } else { - throw new \Exception('Generating IV failed'); + throw new \Exception( 'Generating IV failed' ); } @@ -533,16 +520,15 @@ class Crypt * @brief Generate a pseudo random 1024kb ASCII key * @returns $key Generated key */ - public static function generateKey() - { + public static function generateKey() { // Generate key - if ($key = base64_encode(openssl_random_pseudo_bytes(183, $strong))) { + if ( $key = base64_encode( openssl_random_pseudo_bytes( 183, $strong ) ) ) { - if (!$strong) { + if ( !$strong ) { // If OpenSSL indicates randomness is insecure, log error - throw new \Exception('Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()'); + throw new \Exception( 'Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()' ); } @@ -563,12 +549,11 @@ class Crypt * * if the key is left out, the default handeler will be used */ - public static function getBlowfish($key = '') - { + public static function getBlowfish( $key = '' ) { - if ($key) { + if ( $key ) { - return new \Crypt_Blowfish($key); + return new \Crypt_Blowfish( $key ); } else { @@ -582,14 +567,13 @@ class Crypt * @param $passphrase * @return mixed */ - public static function legacyCreateKey($passphrase) - { + public static function legacyCreateKey( $passphrase ) { // Generate a random integer - $key = mt_rand(10000, 99999) . mt_rand(10000, 99999) . mt_rand(10000, 99999) . mt_rand(10000, 99999); + $key = mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ); // Encrypt the key with the passphrase - $legacyEncKey = self::legacyEncrypt($key, $passphrase); + $legacyEncKey = self::legacyEncrypt( $key, $passphrase ); return $legacyEncKey; @@ -605,12 +589,11 @@ class Crypt * * This function encrypts an content */ - public static function legacyEncrypt($content, $passphrase = '') - { + public static function legacyEncrypt( $content, $passphrase = '' ) { - $bf = self::getBlowfish($passphrase); + $bf = self::getBlowfish( $passphrase ); - return $bf->encrypt($content); + return $bf->encrypt( $content ); } @@ -624,14 +607,13 @@ class Crypt * * This function decrypts an content */ - public static function legacyDecrypt($content, $passphrase = '') - { + public static function legacyDecrypt( $content, $passphrase = '' ) { - $bf = self::getBlowfish($passphrase); + $bf = self::getBlowfish( $passphrase ); - $decrypted = $bf->decrypt($content); + $decrypted = $bf->decrypt( $content ); - return rtrim($decrypted, "\0");; + return rtrim( $decrypted, "\0" );; } @@ -641,17 +623,16 @@ class Crypt * @param int $maxLength * @return string */ - private static function legacyBlockDecrypt($data, $key = '', $maxLength = 0) - { + private static function legacyBlockDecrypt( $data, $key = '', $maxLength = 0 ) { $result = ''; - while (strlen($data)) { - $result .= self::legacyDecrypt(substr($data, 0, 8192), $key); - $data = substr($data, 8192); + while ( strlen( $data ) ) { + $result .= self::legacyDecrypt( substr( $data, 0, 8192 ), $key ); + $data = substr( $data, 8192 ); } - if ($maxLength > 0) { - return substr($result, 0, $maxLength); + if ( $maxLength > 0 ) { + return substr( $result, 0, $maxLength ); } else { - return rtrim($result, "\0"); + return rtrim( $result, "\0" ); } } @@ -663,18 +644,17 @@ class Crypt * @param $path * @return array */ - public static function legacyKeyRecryptKeyfile($legacyEncryptedContent, $legacyPassphrase, $publicKeys, $newPassphrase, $path) - { + public static function legacyKeyRecryptKeyfile( $legacyEncryptedContent, $legacyPassphrase, $publicKeys, $newPassphrase, $path ) { - $decrypted = self::legacyBlockDecrypt($legacyEncryptedContent, $legacyPassphrase); + $decrypted = self::legacyBlockDecrypt( $legacyEncryptedContent, $legacyPassphrase ); // Encrypt plain data, generate keyfile & encrypted file - $cryptedData = self::symmetricEncryptFileContentKeyfile($decrypted); + $cryptedData = self::symmetricEncryptFileContentKeyfile( $decrypted ); // Encrypt plain keyfile to multiple sharefiles - $multiEncrypted = Crypt::multiKeyEncrypt($cryptedData['key'], $publicKeys); + $multiEncrypted = Crypt::multiKeyEncrypt( $cryptedData['key'], $publicKeys ); - return array('data' => $cryptedData['encrypted'], 'filekey' => $multiEncrypted['data'], 'sharekeys' => $multiEncrypted['keys']); + return array( 'data' => $cryptedData['encrypted'], 'filekey' => $multiEncrypted['data'], 'sharekeys' => $multiEncrypted['keys'] ); } diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php index e4bf2c1226a..43f573c16b9 100755 --- a/apps/files_encryption/lib/helper.php +++ b/apps/files_encryption/lib/helper.php @@ -37,35 +37,32 @@ class Helper * @brief register share related hooks * */ - public static function registerShareHooks() - { + public static function registerShareHooks() { - \OCP\Util::connectHook('OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared'); - \OCP\Util::connectHook('OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared'); - \OCP\Util::connectHook('OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare'); + \OCP\Util::connectHook( 'OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared' ); + \OCP\Util::connectHook( 'OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared' ); + \OCP\Util::connectHook( 'OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare' ); } /** * @brief register user related hooks * */ - public static function registerUserHooks() - { + public static function registerUserHooks() { - \OCP\Util::connectHook('OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login'); - \OCP\Util::connectHook('OC_User', 'post_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase'); - \OCP\Util::connectHook('OC_User', 'post_createUser', 'OCA\Encryption\Hooks', 'postCreateUser'); - \OCP\Util::connectHook('OC_User', 'post_deleteUser', 'OCA\Encryption\Hooks', 'postDeleteUser'); + \OCP\Util::connectHook( 'OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login' ); + \OCP\Util::connectHook( 'OC_User', 'post_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase' ); + \OCP\Util::connectHook( 'OC_User', 'post_createUser', 'OCA\Encryption\Hooks', 'postCreateUser' ); + \OCP\Util::connectHook( 'OC_User', 'post_deleteUser', 'OCA\Encryption\Hooks', 'postDeleteUser' ); } /** * @brief register filesystem related hooks * */ - public static function registerFilesystemHooks() - { + public static function registerFilesystemHooks() { - \OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename'); + \OCP\Util::connectHook( 'OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename' ); } /** @@ -75,14 +72,13 @@ class Helper * @param string $password * @return bool */ - public static function setupUser($util, $password) - { + public static function setupUser( $util, $password ) { // Check files_encryption infrastructure is ready for action - if (!$util->ready()) { + if ( !$util->ready() ) { - \OC_Log::write('Encryption library', 'User account "' . $util->getUserId() . '" is not ready for encryption; configuration started', \OC_Log::DEBUG); + \OC_Log::write( 'Encryption library', 'User account "' . $util->getUserId() . '" is not ready for encryption; configuration started', \OC_Log::DEBUG ); - if (!$util->setupServerSide($password)) { + if ( !$util->setupServerSide( $password ) ) { return false; } } @@ -99,22 +95,21 @@ class Helper * @internal param string $password * @return bool */ - public static function adminEnableRecovery($recoveryKeyId, $recoveryPassword) - { - $view = new \OC\Files\View('/'); + public static function adminEnableRecovery( $recoveryKeyId, $recoveryPassword ) { + $view = new \OC\Files\View( '/' ); - if ($recoveryKeyId === null) { - $recoveryKeyId = 'recovery_' . substr(md5(time()), 0, 8); - \OC_Appconfig::setValue('files_encryption', 'recoveryKeyId', $recoveryKeyId); + if ( $recoveryKeyId === null ) { + $recoveryKeyId = 'recovery_' . substr( md5( time() ), 0, 8 ); + \OC_Appconfig::setValue( 'files_encryption', 'recoveryKeyId', $recoveryKeyId ); } - if (!$view->is_dir('/owncloud_private_key')) { - $view->mkdir('/owncloud_private_key'); + if ( !$view->is_dir( '/owncloud_private_key' ) ) { + $view->mkdir( '/owncloud_private_key' ); } if ( - (!$view->file_exists("/public-keys/" . $recoveryKeyId . ".public.key") - || !$view->file_exists("/owncloud_private_key/" . $recoveryKeyId . ".private.key")) + ( !$view->file_exists( "/public-keys/" . $recoveryKeyId . ".public.key" ) + || !$view->file_exists( "/owncloud_private_key/" . $recoveryKeyId . ".private.key" ) ) ) { $keypair = \OCA\Encryption\Crypt::createKeypair(); @@ -123,37 +118,37 @@ class Helper // Save public key - if (!$view->is_dir('/public-keys')) { - $view->mkdir('/public-keys'); + if ( !$view->is_dir( '/public-keys' ) ) { + $view->mkdir( '/public-keys' ); } - $view->file_put_contents('/public-keys/' . $recoveryKeyId . '.public.key', $keypair['publicKey']); + $view->file_put_contents( '/public-keys/' . $recoveryKeyId . '.public.key', $keypair['publicKey'] ); // Encrypt private key empthy passphrase - $encryptedPrivateKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($keypair['privateKey'], $recoveryPassword); + $encryptedPrivateKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent( $keypair['privateKey'], $recoveryPassword ); // Save private key - $view->file_put_contents('/owncloud_private_key/' . $recoveryKeyId . '.private.key', $encryptedPrivateKey); + $view->file_put_contents( '/owncloud_private_key/' . $recoveryKeyId . '.private.key', $encryptedPrivateKey ); // create control file which let us check later on if the entered password was correct. - $encryptedControlData = \OCA\Encryption\Crypt::keyEncrypt("ownCloud", $keypair['publicKey']); - if (!$view->is_dir('/control-file')) { - $view->mkdir('/control-file'); + $encryptedControlData = \OCA\Encryption\Crypt::keyEncrypt( "ownCloud", $keypair['publicKey'] ); + if ( !$view->is_dir( '/control-file' ) ) { + $view->mkdir( '/control-file' ); } - $view->file_put_contents('/control-file/controlfile.enc', $encryptedControlData); + $view->file_put_contents( '/control-file/controlfile.enc', $encryptedControlData ); \OC_FileProxy::$enabled = true; // Set recoveryAdmin as enabled - \OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); + \OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminEnabled', 1 ); $return = true; } else { // get recovery key and check the password - $util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \OCP\User::getUser()); - $return = $util->checkRecoveryPassword($_POST['recoveryPassword']); - if ($return) { - \OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1); + $util = new \OCA\Encryption\Util( new \OC_FilesystemView( '/' ), \OCP\User::getUser() ); + $return = $util->checkRecoveryPassword( $_POST['recoveryPassword'] ); + if ( $return ) { + \OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminEnabled', 1 ); } } @@ -167,14 +162,13 @@ class Helper * @param $recoveryPassword * @return bool */ - public static function adminDisableRecovery($recoveryPassword) - { - $util = new Util(new \OC_FilesystemView('/'), \OCP\User::getUser()); - $return = $util->checkRecoveryPassword($recoveryPassword); + public static function adminDisableRecovery( $recoveryPassword ) { + $util = new Util( new \OC_FilesystemView( '/' ), \OCP\User::getUser() ); + $return = $util->checkRecoveryPassword( $recoveryPassword ); - if ($return) { + if ( $return ) { // Set recoveryAdmin as disabled - \OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 0); + \OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminEnabled', 0 ); } return $return; diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index a8cbc19d401..aaa2e4ba1b5 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -38,15 +38,14 @@ class Keymanager * @return string private key or false (hopefully) * @note the key returned by this method must be decrypted before use */ - public static function getPrivateKey(\OC_FilesystemView $view, $user) - { + public static function getPrivateKey( \OC_FilesystemView $view, $user ) { $path = '/' . $user . '/' . 'files_encryption' . '/' . $user . '.private.key'; $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $key = $view->file_get_contents($path); + $key = $view->file_get_contents( $path ); \OC_FileProxy::$enabled = $proxyStatus; @@ -59,13 +58,12 @@ class Keymanager * @param $userId * @return string public key or false */ - public static function getPublicKey(\OC_FilesystemView $view, $userId) - { + public static function getPublicKey( \OC_FilesystemView $view, $userId ) { $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $result = $view->file_get_contents('/public-keys/' . $userId . '.public.key'); + $result = $view->file_get_contents( '/public-keys/' . $userId . '.public.key' ); \OC_FileProxy::$enabled = $proxyStatus; @@ -79,12 +77,11 @@ class Keymanager * @param $userId * @return array keys: privateKey, publicKey */ - public static function getUserKeys(\OC_FilesystemView $view, $userId) - { + public static function getUserKeys( \OC_FilesystemView $view, $userId ) { return array( - 'publicKey' => self::getPublicKey($view, $userId) - , 'privateKey' => self::getPrivateKey($view, $userId) + 'publicKey' => self::getPublicKey( $view, $userId ) + , 'privateKey' => self::getPrivateKey( $view, $userId ) ); } @@ -95,14 +92,13 @@ class Keymanager * @param array $userIds * @return array of public keys for the specified users */ - public static function getPublicKeys(\OC_FilesystemView $view, array $userIds) - { + public static function getPublicKeys( \OC_FilesystemView $view, array $userIds ) { $keys = array(); - foreach ($userIds as $userId) { + foreach ( $userIds as $userId ) { - $keys[$userId] = self::getPublicKey($view, $userId); + $keys[$userId] = self::getPublicKey( $view, $userId ); } @@ -122,41 +118,40 @@ class Keymanager * @note The keyfile is not encrypted here. Client code must * asymmetrically encrypt the keyfile before passing it to this method */ - public static function setFileKey(\OC_FilesystemView $view, $path, $userId, $catfile) - { + public static function setFileKey( \OC_FilesystemView $view, $path, $userId, $catfile ) { $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; //here we need the currently logged in user, while userId can be a different user - $util = new Util($view, \OCP\User::getUser()); - list($owner, $filename) = $util->getUidAndFilename($path); + $util = new Util( $view, \OCP\User::getUser() ); + list( $owner, $filename ) = $util->getUidAndFilename( $path ); $basePath = '/' . $owner . '/files_encryption/keyfiles'; - $targetPath = self::keySetPreparation($view, $filename, $basePath, $owner); + $targetPath = self::keySetPreparation( $view, $filename, $basePath, $owner ); - if (!$view->is_dir($basePath . '/' . $targetPath)) { + if ( !$view->is_dir( $basePath . '/' . $targetPath ) ) { // create all parent folders - $info = pathinfo($basePath . '/' . $targetPath); - $keyfileFolderName = $view->getLocalFolder($info['dirname']); + $info = pathinfo( $basePath . '/' . $targetPath ); + $keyfileFolderName = $view->getLocalFolder( $info['dirname'] ); - if (!file_exists($keyfileFolderName)) { + if ( !file_exists( $keyfileFolderName ) ) { - mkdir($keyfileFolderName, 0750, true); + mkdir( $keyfileFolderName, 0750, true ); } } // try reusing key file if part file - if (self::isPartialFilePath($targetPath)) { + if ( self::isPartialFilePath( $targetPath ) ) { - $result = $view->file_put_contents($basePath . '/' . self::fixPartialFilePath($targetPath) . '.key', $catfile); + $result = $view->file_put_contents( $basePath . '/' . self::fixPartialFilePath( $targetPath ) . '.key', $catfile ); } else { - $result = $view->file_put_contents($basePath . '/' . $targetPath . '.key', $catfile); + $result = $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); } @@ -172,13 +167,12 @@ class Keymanager * @return string File path without .part extension * @note this is needed for reusing keys */ - public static function fixPartialFilePath($path) - { + public static function fixPartialFilePath( $path ) { - if (preg_match('/\.part$/', $path)) { + if ( preg_match( '/\.part$/', $path ) ) { - $newLength = strlen($path) - 5; - $fPath = substr($path, 0, $newLength); + $newLength = strlen( $path ) - 5; + $fPath = substr( $path, 0, $newLength ); return $fPath; @@ -195,10 +189,9 @@ class Keymanager * @param string $path Path that may identify a .part file * @return bool */ - public static function isPartialFilePath($path) - { + public static function isPartialFilePath( $path ) { - if (preg_match('/\.part$/', $path)) { + if ( preg_match( '/\.part$/', $path ) ) { return true; @@ -220,15 +213,14 @@ class Keymanager * @note The keyfile returned is asymmetrically encrypted. Decryption * of the keyfile must be performed by client code */ - public static function getFileKey(\OC_FilesystemView $view, $userId, $filePath) - { + public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) { // try reusing key file if part file - if (self::isPartialFilePath($filePath)) { + if ( self::isPartialFilePath( $filePath ) ) { - $result = self::getFileKey($view, $userId, self::fixPartialFilePath($filePath)); + $result = self::getFileKey( $view, $userId, self::fixPartialFilePath( $filePath ) ); - if ($result) { + if ( $result ) { return $result; @@ -236,19 +228,19 @@ class Keymanager } - $util = new Util($view, \OCP\User::getUser()); + $util = new Util( $view, \OCP\User::getUser() ); - list($owner, $filename) = $util->getUidAndFilename($filePath); - $filePath_f = ltrim($filename, '/'); + list( $owner, $filename ) = $util->getUidAndFilename( $filePath ); + $filePath_f = ltrim( $filename, '/' ); $keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key'; $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - if ($view->file_exists($keyfilePath)) { + if ( $view->file_exists( $keyfilePath ) ) { - $result = $view->file_get_contents($keyfilePath); + $result = $view->file_get_contents( $keyfilePath ); } else { @@ -272,27 +264,26 @@ class Keymanager * @note $path must be relative to data/user/files. e.g. mydoc.txt NOT * /data/admin/files/mydoc.txt */ - public static function deleteFileKey(\OC_FilesystemView $view, $userId, $path) - { + public static function deleteFileKey( \OC_FilesystemView $view, $userId, $path ) { - $trimmed = ltrim($path, '/'); + $trimmed = ltrim( $path, '/' ); $keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed; $result = false; - if ($view->is_dir($keyPath)) { + if ( $view->is_dir( $keyPath ) ) { - $result = $view->unlink($keyPath); + $result = $view->unlink( $keyPath ); - } else if ($view->file_exists($keyPath . '.key')) { + } else if ( $view->file_exists( $keyPath . '.key' ) ) { - $result = $view->unlink($keyPath . '.key'); + $result = $view->unlink( $keyPath . '.key' ); } - if (!$result) { + if ( !$result ) { - \OC_Log::write('Encryption library', 'Could not delete keyfile; does not exist: "' . $keyPath, \OC_Log::ERROR); + \OC_Log::write( 'Encryption library', 'Could not delete keyfile; does not exist: "' . $keyPath, \OC_Log::ERROR ); } @@ -307,19 +298,19 @@ class Keymanager * @note Encryption of the private key must be performed by client code * as no encryption takes place here */ - public static function setPrivateKey($key) - { + public static function setPrivateKey( $key ) { $user = \OCP\User::getUser(); - $view = new \OC_FilesystemView('/' . $user . '/files_encryption'); + $view = new \OC_FilesystemView( '/' . $user . '/files_encryption' ); $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - if (!$view->file_exists('')) $view->mkdir(''); + if ( !$view->file_exists( '' ) ) + $view->mkdir( '' ); - $result = $view->file_put_contents($user . '.private.key', $key); + $result = $view->file_put_contents( $user . '.private.key', $key ); \OC_FileProxy::$enabled = $proxyStatus; @@ -340,22 +331,21 @@ class Keymanager * @note The keyfile is not encrypted here. Client code must * asymmetrically encrypt the keyfile before passing it to this method */ - public static function setShareKey(\OC_FilesystemView $view, $path, $userId, $shareKey) - { + public static function setShareKey( \OC_FilesystemView $view, $path, $userId, $shareKey ) { // Here we need the currently logged in user, while userId can be a different user - $util = new Util($view, \OCP\User::getUser()); + $util = new Util( $view, \OCP\User::getUser() ); - list($owner, $filename) = $util->getUidAndFilename($path); + list( $owner, $filename ) = $util->getUidAndFilename( $path ); $basePath = '/' . $owner . '/files_encryption/share-keys'; - $shareKeyPath = self::keySetPreparation($view, $filename, $basePath, $owner); + $shareKeyPath = self::keySetPreparation( $view, $filename, $basePath, $owner ); // try reusing key file if part file - if (self::isPartialFilePath($shareKeyPath)) { + if ( self::isPartialFilePath( $shareKeyPath ) ) { - $writePath = $basePath . '/' . self::fixPartialFilePath($shareKeyPath) . '.' . $userId . '.shareKey'; + $writePath = $basePath . '/' . self::fixPartialFilePath( $shareKeyPath ) . '.' . $userId . '.shareKey'; } else { @@ -366,12 +356,12 @@ class Keymanager $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $result = $view->file_put_contents($writePath, $shareKey); + $result = $view->file_put_contents( $writePath, $shareKey ); \OC_FileProxy::$enabled = $proxyStatus; if ( - is_int($result) + is_int( $result ) && $result > 0 ) { @@ -392,17 +382,16 @@ class Keymanager * @param array $shareKeys * @return bool */ - public static function setShareKeys(\OC_FilesystemView $view, $path, array $shareKeys) - { + public static function setShareKeys( \OC_FilesystemView $view, $path, array $shareKeys ) { // $shareKeys must be an array with the following format: // [userId] => [encrypted key] $result = true; - foreach ($shareKeys as $userId => $shareKey) { + foreach ( $shareKeys as $userId => $shareKey ) { - if (!self::setShareKey($view, $path, $userId, $shareKey)) { + if ( !self::setShareKey( $view, $path, $userId, $shareKey ) ) { // If any of the keys are not set, flag false $result = false; @@ -426,15 +415,14 @@ class Keymanager * @note The sharekey returned is encrypted. Decryption * of the keyfile must be performed by client code */ - public static function getShareKey(\OC_FilesystemView $view, $userId, $filePath) - { + public static function getShareKey( \OC_FilesystemView $view, $userId, $filePath ) { // try reusing key file if part file - if (self::isPartialFilePath($filePath)) { + if ( self::isPartialFilePath( $filePath ) ) { - $result = self::getShareKey($view, $userId, self::fixPartialFilePath($filePath)); + $result = self::getShareKey( $view, $userId, self::fixPartialFilePath( $filePath ) ); - if ($result) { + if ( $result ) { return $result; @@ -446,14 +434,14 @@ class Keymanager \OC_FileProxy::$enabled = false; //here we need the currently logged in user, while userId can be a different user - $util = new Util($view, \OCP\User::getUser()); + $util = new Util( $view, \OCP\User::getUser() ); - list($owner, $filename) = $util->getUidAndFilename($filePath); - $shareKeyPath = \OC\Files\Filesystem::normalizePath('/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey'); + list( $owner, $filename ) = $util->getUidAndFilename( $filePath ); + $shareKeyPath = \OC\Files\Filesystem::normalizePath( '/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey' ); - if ($view->file_exists($shareKeyPath)) { + if ( $view->file_exists( $shareKeyPath ) ) { - $result = $view->file_get_contents($shareKeyPath); + $result = $view->file_get_contents( $shareKeyPath ); } else { @@ -473,16 +461,18 @@ class Keymanager * @param string $userId owner of the file * @param string $filePath path to the file, relative to the owners file dir */ - public static function delAllShareKeys(\OC_FilesystemView $view, $userId, $filePath) - { + public static function delAllShareKeys( \OC_FilesystemView $view, $userId, $filePath ) { - if ($view->is_dir($userId . '/files/' . $filePath)) { - $view->unlink($userId . '/files_encryption/share-keys/' . $filePath); + if ( $view->is_dir( $userId . '/files/' . $filePath ) ) { + $view->unlink( $userId . '/files_encryption/share-keys/' . $filePath ); } else { - $localKeyPath = $view->getLocalFile($userId . '/files_encryption/share-keys/' . $filePath); - $matches = glob(preg_quote($localKeyPath) . '*.shareKey'); - foreach ($matches as $ma) { - unlink($ma); + $localKeyPath = $view->getLocalFile( $userId . '/files_encryption/share-keys/' . $filePath ); + $matches = glob( preg_quote( $localKeyPath ) . '*.shareKey' ); + foreach ( $matches as $ma ) { + $result = unlink( $ma ); + if ( !$result ) { + \OC_Log::write( 'Encryption library', 'Keyfile or shareKey could not be deleted for file "' . $filePath . '"', \OC_Log::ERROR ); + } } } } @@ -490,30 +480,29 @@ class Keymanager /** * @brief Delete a single user's shareKey for a single file */ - public static function delShareKey(\OC_FilesystemView $view, $userIds, $filePath) - { + public static function delShareKey( \OC_FilesystemView $view, $userIds, $filePath ) { $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; //here we need the currently logged in user, while userId can be a different user - $util = new Util($view, \OCP\User::getUser()); + $util = new Util( $view, \OCP\User::getUser() ); - list($owner, $filename) = $util->getUidAndFilename($filePath); + list( $owner, $filename ) = $util->getUidAndFilename( $filePath ); - $shareKeyPath = \OC\Files\Filesystem::normalizePath('/' . $owner . '/files_encryption/share-keys/' . $filename); + $shareKeyPath = \OC\Files\Filesystem::normalizePath( '/' . $owner . '/files_encryption/share-keys/' . $filename ); - if ($view->is_dir($shareKeyPath)) { + if ( $view->is_dir( $shareKeyPath ) ) { - $localPath = \OC\Files\Filesystem::normalizePath($view->getLocalFolder($shareKeyPath)); - self::recursiveDelShareKeys($localPath, $userIds); + $localPath = \OC\Files\Filesystem::normalizePath( $view->getLocalFolder( $shareKeyPath ) ); + self::recursiveDelShareKeys( $localPath, $userIds ); } else { - foreach ($userIds as $userId) { + foreach ( $userIds as $userId ) { - if (!$view->unlink($shareKeyPath . '.' . $userId . '.shareKey')) { - \OC_Log::write('Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath . '.' . $userId . '.shareKey"', \OC_Log::ERROR); + if ( !$view->unlink( $shareKeyPath . '.' . $userId . '.shareKey' ) ) { + \OC_Log::write( 'Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath . '.' . $userId . '.shareKey"', \OC_Log::ERROR ); } } @@ -528,45 +517,42 @@ class Keymanager * @param string $dir directory * @param array $userIds user ids for which the share keys should be deleted */ - private static function recursiveDelShareKeys($dir, $userIds) - { - foreach ($userIds as $userId) { - $completePath = $dir . '/.*' . '.' . $userId . '.shareKey'; - $matches = glob(preg_quote($dir) . '/*' . preg_quote('.' . $userId . '.shareKey')); + private static function recursiveDelShareKeys( $dir, $userIds ) { + foreach ( $userIds as $userId ) { + $matches = glob( preg_quote( $dir ) . '/*' . preg_quote( '.' . $userId . '.shareKey' ) ); } /** @var $matches array */ - foreach ($matches as $ma) { - if (!unlink($ma)) { - \OC_Log::write('Encryption library', 'Could not delete shareKey; does not exist: "' . $ma . '"', \OC_Log::ERROR); + foreach ( $matches as $ma ) { + if ( !unlink( $ma ) ) { + \OC_Log::write( 'Encryption library', 'Could not delete shareKey; does not exist: "' . $ma . '"', \OC_Log::ERROR ); } } - $subdirs = $directories = glob(preg_quote($dir) . '/*', GLOB_ONLYDIR); - foreach ($subdirs as $subdir) { - self::recursiveDelShareKeys($subdir, $userIds); + $subdirs = $directories = glob( preg_quote( $dir ) . '/*', GLOB_ONLYDIR ); + foreach ( $subdirs as $subdir ) { + self::recursiveDelShareKeys( $subdir, $userIds ); } } /** * @brief Make preparations to vars and filesystem for saving a keyfile */ - public static function keySetPreparation(\OC_FilesystemView $view, $path, $basePath, $userId) - { + public static function keySetPreparation( \OC_FilesystemView $view, $path, $basePath, $userId ) { - $targetPath = ltrim($path, '/'); + $targetPath = ltrim( $path, '/' ); - $path_parts = pathinfo($targetPath); + $path_parts = pathinfo( $targetPath ); // If the file resides within a subdirectory, create it if ( - isset($path_parts['dirname']) - && !$view->file_exists($basePath . '/' . $path_parts['dirname']) + isset( $path_parts['dirname'] ) + && !$view->file_exists( $basePath . '/' . $path_parts['dirname'] ) ) { - $sub_dirs = explode(DIRECTORY_SEPARATOR, $basePath . '/' . $path_parts['dirname']); + $sub_dirs = explode( DIRECTORY_SEPARATOR, $basePath . '/' . $path_parts['dirname'] ); $dir = ''; - foreach ($sub_dirs as $sub_dir) { + foreach ( $sub_dirs as $sub_dir ) { $dir .= '/' . $sub_dir; - if (!$view->is_dir($dir)) { - $view->mkdir($dir); + if ( !$view->is_dir( $dir ) ) { + $view->mkdir( $dir ); } } } diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index cc9d239b256..eaaeae9b619 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -48,13 +48,12 @@ class Proxy extends \OC_FileProxy * * Tests if server side encryption is enabled, and file is allowed by blacklists */ - private static function shouldEncrypt($path) - { + private static function shouldEncrypt( $path ) { - if (is_null(self::$enableEncryption)) { + if ( is_null( self::$enableEncryption ) ) { if ( - \OCP\Config::getAppValue('files_encryption', 'enable_encryption', 'true') == 'true' + \OCP\Config::getAppValue( 'files_encryption', 'enable_encryption', 'true' ) == 'true' && Crypt::mode() == 'server' ) { @@ -68,27 +67,27 @@ class Proxy extends \OC_FileProxy } - if (!self::$enableEncryption) { + if ( !self::$enableEncryption ) { return false; } - if (is_null(self::$blackList)) { + if ( is_null( self::$blackList ) ) { - self::$blackList = explode(',', \OCP\Config::getAppValue('files_encryption', 'type_blacklist', '')); + self::$blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) ); } - if (Crypt::isCatfileContent($path)) { + if ( Crypt::isCatfileContent( $path ) ) { return true; } - $extension = substr($path, strrpos($path, '.') + 1); + $extension = substr( $path, strrpos( $path, '.' ) + 1 ); - if (array_search($extension, self::$blackList) === false) { + if ( array_search( $extension, self::$blackList ) === false ) { return true; @@ -102,35 +101,34 @@ class Proxy extends \OC_FileProxy * @param $data * @return bool */ - public function preFile_put_contents($path, &$data) - { + public function preFile_put_contents( $path, &$data ) { - if (self::shouldEncrypt($path)) { + if ( self::shouldEncrypt( $path ) ) { // Stream put contents should have been converted to fopen - if (!is_resource($data)) { + if ( !is_resource( $data ) ) { $userId = \OCP\USER::getUser(); - $view = new \OC_FilesystemView('/'); - $util = new Util($view, $userId); - $session = new Session($view); + $view = new \OC_FilesystemView( '/' ); + $util = new Util( $view, $userId ); + $session = new Session( $view ); $privateKey = $session->getPrivateKey(); - $filePath = $util->stripUserFilesPath($path); + $filePath = $util->stripUserFilesPath( $path ); // Set the filesize for userland, before encrypting - $size = strlen($data); + $size = strlen( $data ); // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; // Check if there is an existing key we can reuse - if ($encKeyfile = Keymanager::getFileKey($view, $userId, $filePath)) { + if ( $encKeyfile = Keymanager::getFileKey( $view, $userId, $filePath ) ) { // Fetch shareKey - $shareKey = Keymanager::getShareKey($view, $userId, $filePath); + $shareKey = Keymanager::getShareKey( $view, $userId, $filePath ); // Decrypt the keyfile - $plainKey = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + $plainKey = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); } else { @@ -140,37 +138,37 @@ class Proxy extends \OC_FileProxy } // Encrypt data - $encData = Crypt::symmetricEncryptFileContent($data, $plainKey); + $encData = Crypt::symmetricEncryptFileContent( $data, $plainKey ); $sharingEnabled = \OCP\Share::isEnabled(); // if file exists try to get sharing users - if ($view->file_exists($path)) { - $uniqueUserIds = $util->getSharingUsersArray($sharingEnabled, $filePath, $userId); + if ( $view->file_exists( $path ) ) { + $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $filePath, $userId ); } else { $uniqueUserIds[] = $userId; } // Fetch public keys for all users who will share the file - $publicKeys = Keymanager::getPublicKeys($view, $uniqueUserIds); + $publicKeys = Keymanager::getPublicKeys( $view, $uniqueUserIds ); // Encrypt plain keyfile to multiple sharefiles - $multiEncrypted = Crypt::multiKeyEncrypt($plainKey, $publicKeys); + $multiEncrypted = Crypt::multiKeyEncrypt( $plainKey, $publicKeys ); // Save sharekeys to user folders - Keymanager::setShareKeys($view, $filePath, $multiEncrypted['keys']); + Keymanager::setShareKeys( $view, $filePath, $multiEncrypted['keys'] ); // Set encrypted keyfile as common varname $encKey = $multiEncrypted['data']; // Save keyfile for newly encrypted file in parallel directory tree - Keymanager::setFileKey($view, $filePath, $userId, $encKey); + Keymanager::setFileKey( $view, $filePath, $userId, $encKey ); // Replace plain content with encrypted content by reference $data = $encData; // Update the file cache with file info - \OC\Files\Filesystem::putFileInfo($filePath, array('encrypted' => true, 'size' => strlen($data), 'unencrypted_size' => $size), ''); + \OC\Files\Filesystem::putFileInfo( $filePath, array( 'encrypted' => true, 'size' => strlen( $data ), 'unencrypted_size' => $size ), '' ); // Re-enable proxy - our work is done \OC_FileProxy::$enabled = $proxyStatus; @@ -186,52 +184,51 @@ class Proxy extends \OC_FileProxy * @param string $path Path of file from which has been read * @param string $data Data that has been read from file */ - public function postFile_get_contents($path, $data) - { + public function postFile_get_contents( $path, $data ) { $userId = \OCP\USER::getUser(); - $view = new \OC_FilesystemView('/'); - $util = new Util($view, $userId); + $view = new \OC_FilesystemView( '/' ); + $util = new Util( $view, $userId ); - $relPath = $util->stripUserFilesPath($path); + $relPath = $util->stripUserFilesPath( $path ); // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; // init session - $session = new Session($view); + $session = new Session( $view ); // If data is a catfile if ( Crypt::mode() == 'server' - && Crypt::isCatfileContent($data) + && Crypt::isCatfileContent( $data ) ) { - $privateKey = $session->getPrivateKey($userId); + $privateKey = $session->getPrivateKey( $userId ); // Get the encrypted keyfile - $encKeyfile = Keymanager::getFileKey($view, $userId, $relPath); + $encKeyfile = Keymanager::getFileKey( $view, $userId, $relPath ); // Attempt to fetch the user's shareKey - $shareKey = Keymanager::getShareKey($view, $userId, $relPath); + $shareKey = Keymanager::getShareKey( $view, $userId, $relPath ); // Decrypt keyfile with shareKey - $plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); - $plainData = Crypt::symmetricDecryptFileContent($data, $plainKeyfile); + $plainData = Crypt::symmetricDecryptFileContent( $data, $plainKeyfile ); } elseif ( Crypt::mode() == 'server' - && isset($_SESSION['legacyenckey']) - && Crypt::isEncryptedMeta($path) + && isset( $_SESSION['legacyenckey'] ) + && Crypt::isEncryptedMeta( $path ) ) { - $plainData = Crypt::legacyDecrypt($data, $session->getLegacyKey()); + $plainData = Crypt::legacyDecrypt( $data, $session->getLegacyKey() ); } \OC_FileProxy::$enabled = $proxyStatus; - if (!isset($plainData)) { + if ( !isset( $plainData ) ) { $plainData = $data; @@ -244,11 +241,10 @@ class Proxy extends \OC_FileProxy /** * @brief When a file is deleted, remove its keyfile also */ - public function preUnlink($path) - { + public function preUnlink( $path ) { // let the trashbin handle this - if (\OCP\App::isEnabled('files_trashbin')) { + if ( \OCP\App::isEnabled( 'files_trashbin' ) ) { return true; } @@ -256,29 +252,24 @@ class Proxy extends \OC_FileProxy $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $view = new \OC_FilesystemView('/'); + $view = new \OC_FilesystemView( '/' ); $userId = \OCP\USER::getUser(); - $util = new Util($view, $userId); + $util = new Util( $view, $userId ); // Format path to be relative to user files dir - $relPath = $util->stripUserFilesPath($path); + $relPath = $util->stripUserFilesPath( $path ); - list($owner, $ownerPath) = $util->getUidAndFilename($relPath); + list( $owner, $ownerPath ) = $util->getUidAndFilename( $relPath ); // Delete keyfile & shareKey so it isn't orphaned - if ( - !( - Keymanager::deleteFileKey($view, $owner, $ownerPath) - && Keymanager::delAllShareKeys($view, $owner, $ownerPath) - ) - ) { - - \OC_Log::write('Encryption library', 'Keyfile or shareKey could not be deleted for file "' . $ownerPath . '"', \OC_Log::ERROR); - + if ( !Keymanager::deleteFileKey( $view, $owner, $ownerPath ) ) { + \OC_Log::write( 'Encryption library', 'Keyfile or shareKey could not be deleted for file "' . $ownerPath . '"', \OC_Log::ERROR ); } + Keymanager::delAllShareKeys( $view, $owner, $ownerPath ); + \OC_FileProxy::$enabled = $proxyStatus; // If we don't return true then file delete will fail; better @@ -291,9 +282,8 @@ class Proxy extends \OC_FileProxy * @param $path * @return bool */ - public function postTouch($path) - { - $this->handleFile($path); + public function postTouch( $path ) { + $this->handleFile( $path ); return true; } @@ -303,21 +293,20 @@ class Proxy extends \OC_FileProxy * @param $result * @return resource */ - public function postFopen($path, &$result) - { + public function postFopen( $path, &$result ) { - if (!$result) { + if ( !$result ) { return $result; } // Reformat path for use with OC_FSV - $path_split = explode('/', $path); - $path_f = implode('/', array_slice($path_split, 3)); + $path_split = explode( '/', $path ); + $path_f = implode( '/', array_slice( $path_split, 3 ) ); // FIXME: handling for /userId/cache used by webdav for chunking. The cache chunks are NOT encrypted - if ($path_split[2] == 'cache') { + if ( count($path_split) >= 2 && $path_split[2] == 'cache' ) { return $result; } @@ -325,31 +314,31 @@ class Proxy extends \OC_FileProxy $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $meta = stream_get_meta_data($result); + $meta = stream_get_meta_data( $result ); - $view = new \OC_FilesystemView(''); + $view = new \OC_FilesystemView( '' ); - $util = new Util($view, \OCP\USER::getUser()); + $util = new Util( $view, \OCP\USER::getUser() ); // If file is already encrypted, decrypt using crypto protocol if ( Crypt::mode() == 'server' - && $util->isEncryptedPath($path) + && $util->isEncryptedPath( $path ) ) { // Close the original encrypted file - fclose($result); + fclose( $result ); // Open the file using the crypto stream wrapper // protocol and let it do the decryption work instead - $result = fopen('crypt://' . $path_f, $meta['mode']); + $result = fopen( 'crypt://' . $path_f, $meta['mode'] ); } elseif ( - self::shouldEncrypt($path) + self::shouldEncrypt( $path ) and $meta ['mode'] != 'r' and $meta['mode'] != 'rb' ) { - $result = fopen('crypt://' . $path_f, $meta['mode']); + $result = fopen( 'crypt://' . $path_f, $meta['mode'] ); } // Re-enable the proxy @@ -364,18 +353,17 @@ class Proxy extends \OC_FileProxy * @param $data * @return array */ - public function postGetFileInfo($path, $data) - { + public function postGetFileInfo( $path, $data ) { // if path is a folder do nothing - if (is_array($data) && array_key_exists('size', $data)) { + if ( is_array( $data ) && array_key_exists( 'size', $data ) ) { // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; // get file size - $data['size'] = self::postFileSize($path, $data['size']); + $data['size'] = self::postFileSize( $path, $data['size'] ); // Re-enable the proxy \OC_FileProxy::$enabled = $proxyStatus; @@ -389,52 +377,51 @@ class Proxy extends \OC_FileProxy * @param $size * @return bool */ - public function postFileSize($path, $size) - { + public function postFileSize( $path, $size ) { - $view = new \OC_FilesystemView('/'); + $view = new \OC_FilesystemView( '/' ); // if path is a folder do nothing - if ($view->is_dir($path)) { + if ( $view->is_dir( $path ) ) { return $size; } // Reformat path for use with OC_FSV - $path_split = explode('/', $path); - $path_f = implode('/', array_slice($path_split, 3)); + $path_split = explode( '/', $path ); + $path_f = implode( '/', array_slice( $path_split, 3 ) ); // if path is empty we cannot resolve anything - if (empty($path_f)) { + if ( empty( $path_f ) ) { return $size; } $fileInfo = false; // get file info from database/cache if not .part file - if(!Keymanager::isPartialFilePath($path)) { - $fileInfo = $view->getFileInfo($path); + if ( !Keymanager::isPartialFilePath( $path ) ) { + $fileInfo = $view->getFileInfo( $path ); } // if file is encrypted return real file size - if (is_array($fileInfo) && $fileInfo['encrypted'] === true) { + if ( is_array( $fileInfo ) && $fileInfo['encrypted'] === true ) { $size = $fileInfo['unencrypted_size']; } else { // self healing if file was removed from file cache - if (!is_array($fileInfo)) { + if ( !is_array( $fileInfo ) ) { $fileInfo = array(); } $userId = \OCP\User::getUser(); - $util = new Util($view, $userId); - $fixSize = $util->getFileSize($path); - if ($fixSize > 0) { + $util = new Util( $view, $userId ); + $fixSize = $util->getFileSize( $path ); + if ( $fixSize > 0 ) { $size = $fixSize; $fileInfo['encrypted'] = true; $fileInfo['unencrypted_size'] = $size; // put file info if not .part file - if(!Keymanager::isPartialFilePath($path_f)) { - $view->putFileInfo($path, $fileInfo); + if ( !Keymanager::isPartialFilePath( $path_f ) ) { + $view->putFileInfo( $path, $fileInfo ); } } @@ -445,33 +432,32 @@ class Proxy extends \OC_FileProxy /** * @param $path */ - public function handleFile($path) - { + public function handleFile( $path ) { // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $view = new \OC_FilesystemView('/'); - $session = new Session($view); + $view = new \OC_FilesystemView( '/' ); + $session = new Session( $view ); $userId = \OCP\User::getUser(); - $util = new Util($view, $userId); + $util = new Util( $view, $userId ); // Reformat path for use with OC_FSV - $path_split = explode('/', $path); - $path_f = implode('/', array_slice($path_split, 3)); + $path_split = explode( '/', $path ); + $path_f = implode( '/', array_slice( $path_split, 3 ) ); // only if file is on 'files' folder fix file size and sharing - if ($path_split[2] == 'files' && $util->fixFileSize($path)) { + if ( count($path_split) >= 2 && $path_split[2] == 'files' && $util->fixFileSize( $path ) ) { // get sharing app state $sharingEnabled = \OCP\Share::isEnabled(); // get users - $usersSharing = $util->getSharingUsersArray($sharingEnabled, $path_f); + $usersSharing = $util->getSharingUsersArray( $sharingEnabled, $path_f ); // update sharing-keys - $util->setSharedFileKeyfiles($session, $usersSharing, $path_f); + $util->setSharedFileKeyfiles( $session, $usersSharing, $path_f ); } \OC_FileProxy::$enabled = $proxyStatus; diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index 86f56e56766..2ddad0a15da 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -37,27 +37,26 @@ class Session * * @note The ownCloud key pair is used to allow public link sharing even if encryption is enabled */ - public function __construct($view) - { + public function __construct( $view ) { $this->view = $view; - if (!$this->view->is_dir('owncloud_private_key')) { + if ( !$this->view->is_dir( 'owncloud_private_key' ) ) { - $this->view->mkdir('owncloud_private_key'); + $this->view->mkdir( 'owncloud_private_key' ); } - $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); + $publicShareKeyId = \OC_Appconfig::getValue( 'files_encryption', 'publicShareKeyId' ); - if ($publicShareKeyId === null) { - $publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8); - \OC_Appconfig::setValue('files_encryption', 'publicShareKeyId', $publicShareKeyId); + if ( $publicShareKeyId === null ) { + $publicShareKeyId = 'pubShare_' . substr( md5( time() ), 0, 8 ); + \OC_Appconfig::setValue( 'files_encryption', 'publicShareKeyId', $publicShareKeyId ); } if ( - !$this->view->file_exists("/public-keys/" . $publicShareKeyId . ".public.key") - || !$this->view->file_exists("/owncloud_private_key/" . $publicShareKeyId . ".private.key") + !$this->view->file_exists( "/public-keys/" . $publicShareKeyId . ".public.key" ) + || !$this->view->file_exists( "/owncloud_private_key/" . $publicShareKeyId . ".private.key" ) ) { $keypair = Crypt::createKeypair(); @@ -68,32 +67,33 @@ class Session // Save public key - if (!$view->is_dir('/public-keys')) { - $view->mkdir('/public-keys'); + if ( !$view->is_dir( '/public-keys' ) ) { + $view->mkdir( '/public-keys' ); } - $this->view->file_put_contents('/public-keys/' . $publicShareKeyId . '.public.key', $keypair['publicKey']); + $this->view->file_put_contents( '/public-keys/' . $publicShareKeyId . '.public.key', $keypair['publicKey'] ); - // Encrypt private key empthy passphrase - $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], ''); + // Encrypt private key empty passphrase + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], '' ); // Save private key - $this->view->file_put_contents('/owncloud_private_key/' . $publicShareKeyId . '.private.key', $encryptedPrivateKey); + $this->view->file_put_contents( '/owncloud_private_key/' . $publicShareKeyId . '.private.key', $encryptedPrivateKey ); \OC_FileProxy::$enabled = $proxyStatus; } - if (\OCP\USER::getUser() === false || - (isset($_GET['service']) && $_GET['service'] == 'files' && - isset($_GET['t']))) { + if ( \OCP\USER::getUser() === false || + ( isset( $_GET['service'] ) && $_GET['service'] == 'files' && + isset( $_GET['t'] ) ) + ) { // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $encryptedKey = $this->view->file_get_contents('/owncloud_private_key/' . $publicShareKeyId . '.private.key'); - $privateKey = Crypt::symmetricDecryptFileContent($encryptedKey, ''); - $this->setPrivateKey($privateKey); + $encryptedKey = $this->view->file_get_contents( '/owncloud_private_key/' . $publicShareKeyId . '.private.key' ); + $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, '' ); + $this->setPrivateKey( $privateKey ); \OC_FileProxy::$enabled = $proxyStatus; } @@ -104,8 +104,7 @@ class Session * @param string $privateKey * @return bool */ - public function setPrivateKey($privateKey) - { + public function setPrivateKey( $privateKey ) { $_SESSION['privateKey'] = $privateKey; @@ -118,12 +117,11 @@ class Session * @returns string $privateKey The user's plaintext private key * */ - public function getPrivateKey() - { + public function getPrivateKey() { if ( - isset($_SESSION['privateKey']) - && !empty($_SESSION['privateKey']) + isset( $_SESSION['privateKey'] ) + && !empty( $_SESSION['privateKey'] ) ) { return $_SESSION['privateKey']; @@ -141,8 +139,7 @@ class Session * @param $legacyKey * @return bool */ - public function setLegacyKey($legacyKey) - { + public function setLegacyKey( $legacyKey ) { $_SESSION['legacyKey'] = $legacyKey; @@ -154,12 +151,11 @@ class Session * @returns string $legacyKey The user's plaintext legacy key * */ - public function getLegacyKey() - { + public function getLegacyKey() { if ( - isset($_SESSION['legacyKey']) - && !empty($_SESSION['legacyKey']) + isset( $_SESSION['legacyKey'] ) + && !empty( $_SESSION['legacyKey'] ) ) { return $_SESSION['legacyKey']; diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index b143b62827f..fa9df02f085 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -77,19 +77,18 @@ class Stream * @param $opened_path * @return bool */ - public function stream_open($path, $mode, $options, &$opened_path) - { + public function stream_open( $path, $mode, $options, &$opened_path ) { - if (!isset($this->rootView)) { - $this->rootView = new \OC_FilesystemView('/'); + if ( !isset( $this->rootView ) ) { + $this->rootView = new \OC_FilesystemView( '/' ); } - $util = new Util($this->rootView, \OCP\USER::getUser()); + $util = new Util( $this->rootView, \OCP\USER::getUser() ); $this->userId = $util->getUserId(); // Strip identifier text from path, this gives us the path relative to data//files - $this->relPath = \OC\Files\Filesystem::normalizePath(str_replace('crypt://', '', $path)); + $this->relPath = \OC\Files\Filesystem::normalizePath( str_replace( 'crypt://', '', $path ) ); // rawPath is relative to the data directory $this->rawPath = $util->getUserFilesDir() . $this->relPath; @@ -111,26 +110,25 @@ class Stream } else { - $this->size = $this->rootView->filesize($this->rawPath, $mode); + $this->size = $this->rootView->filesize( $this->rawPath, $mode ); } - $this->handle = $this->rootView->fopen($this->rawPath, $mode); + $this->handle = $this->rootView->fopen( $this->rawPath, $mode ); \OC_FileProxy::$enabled = $proxyStatus; - if (!is_resource($this->handle)) { + if ( !is_resource( $this->handle ) ) { - \OCP\Util::writeLog('files_encryption', 'failed to open file "' . $this->rawPath . '"', \OCP\Util::ERROR); + \OCP\Util::writeLog( 'files_encryption', 'failed to open file "' . $this->rawPath . '"', \OCP\Util::ERROR ); } else { - $this->meta = stream_get_meta_data($this->handle); + $this->meta = stream_get_meta_data( $this->handle ); } - - return is_resource($this->handle); + return is_resource( $this->handle ); } @@ -138,12 +136,11 @@ class Stream * @param $offset * @param int $whence */ - public function stream_seek($offset, $whence = SEEK_SET) - { + public function stream_seek( $offset, $whence = SEEK_SET ) { $this->flush(); - fseek($this->handle, $offset, $whence); + fseek( $this->handle, $offset, $whence ); } @@ -152,37 +149,36 @@ class Stream * @return bool|string * @throws \Exception */ - public function stream_read($count) - { + public function stream_read( $count ) { $this->writeCache = ''; - if ($count != 8192) { + if ( $count != 8192 ) { // $count will always be 8192 https://bugs.php.net/bug.php?id=21641 // This makes this function a lot simpler, but will break this class if the above 'bug' gets 'fixed' - \OCP\Util::writeLog('files_encryption', 'PHP "bug" 21641 no longer holds, decryption system requires refactoring', \OCP\Util::FATAL); + \OCP\Util::writeLog( 'files_encryption', 'PHP "bug" 21641 no longer holds, decryption system requires refactoring', \OCP\Util::FATAL ); die(); } // Get the data from the file handle - $data = fread($this->handle, 8192); + $data = fread( $this->handle, 8192 ); $result = ''; - if (strlen($data)) { + if ( strlen( $data ) ) { - if (!$this->getKey()) { + if ( !$this->getKey() ) { // Error! We don't have a key to decrypt the file with - throw new \Exception('Encryption key not found for "' . $this->rawPath . '" during attempted read via stream'); + throw new \Exception( 'Encryption key not found for "' . $this->rawPath . '" during attempted read via stream' ); } // Decrypt data - $result = Crypt::symmetricDecryptFileContent($data, $this->plainKey); + $result = Crypt::symmetricDecryptFileContent( $data, $this->plainKey ); } @@ -196,11 +192,10 @@ class Stream * @param string $key key to use for encryption * @return string encrypted data on success, false on failure */ - public function preWriteEncrypt($plainData, $key) - { + public function preWriteEncrypt( $plainData, $key ) { // Encrypt data to 'catfile', which includes IV - if ($encrypted = Crypt::symmetricEncryptFileContent($plainData, $key)) { + if ( $encrypted = Crypt::symmetricEncryptFileContent( $plainData, $key ) ) { return $encrypted; @@ -217,11 +212,10 @@ class Stream * @internal param bool $generate if true, a new key will be generated if none can be found * @return bool true on key found and set, false on key not found and new key generated and set */ - public function getKey() - { + public function getKey() { // Check if key is already set - if (isset($this->plainKey) && isset($this->encKeyfile)) { + if ( isset( $this->plainKey ) && isset( $this->encKeyfile ) ) { return true; @@ -229,18 +223,18 @@ class Stream // Fetch and decrypt keyfile // Fetch existing keyfile - $this->encKeyfile = Keymanager::getFileKey($this->rootView, $this->userId, $this->relPath); + $this->encKeyfile = Keymanager::getFileKey( $this->rootView, $this->userId, $this->relPath ); // If a keyfile already exists - if ($this->encKeyfile) { + if ( $this->encKeyfile ) { - $session = new Session($this->rootView); + $session = new Session( $this->rootView ); - $privateKey = $session->getPrivateKey($this->userId); + $privateKey = $session->getPrivateKey( $this->userId ); - $shareKey = Keymanager::getShareKey($this->rootView, $this->userId, $this->relPath); + $shareKey = Keymanager::getShareKey( $this->rootView, $this->userId, $this->relPath ); - $this->plainKey = Crypt::multiKeyDecrypt($this->encKeyfile, $shareKey, $privateKey); + $this->plainKey = Crypt::multiKeyDecrypt( $this->encKeyfile, $shareKey, $privateKey ); return true; @@ -261,8 +255,7 @@ class Stream * @note Padding is added to each encrypted block to ensure that the resulting block is exactly 8192 bytes. This is removed during stream_read * @note PHP automatically updates the file pointer after writing data to reflect it's length. There is generally no need to update the poitner manually using fseek */ - public function stream_write($data) - { + public function stream_write( $data ) { // Disable the file proxies so that encryption is not // automatically attempted when the file is written to disk - @@ -272,16 +265,16 @@ class Stream \OC_FileProxy::$enabled = false; // Get the length of the unencrypted data that we are handling - $length = strlen($data); + $length = strlen( $data ); // Find out where we are up to in the writing of data to the // file - $pointer = ftell($this->handle); + $pointer = ftell( $this->handle ); // Get / generate the keyfile for the file we're handling // If we're writing a new file (not overwriting an existing // one), save the newly generated keyfile - if (!$this->getKey()) { + if ( !$this->getKey() ) { $this->plainKey = Crypt::generateKey(); @@ -289,27 +282,27 @@ class Stream // If extra data is left over from the last round, make sure it // is integrated into the next 6126 / 8192 block - if ($this->writeCache) { + if ( $this->writeCache ) { // Concat writeCache to start of $data $data = $this->writeCache . $data; - // Clear the write cache, ready for resuse - it has been + // Clear the write cache, ready for reuse - it has been // flushed and its old contents processed $this->writeCache = ''; } - // While there still remains somed data to be processed & written - while (strlen($data) > 0) { + // While there still remains some data to be processed & written + while ( strlen( $data ) > 0 ) { - // Remaining length for this iteration, not of the + // Remaining length for this iteration, not of the // entire file (may be greater than 8192 bytes) - $remainingLength = strlen($data); + $remainingLength = strlen( $data ); - // If data remaining to be written is less than the + // If data remaining to be written is less than the // size of 1 6126 byte block - if ($remainingLength < 6126) { + if ( $remainingLength < 6126 ) { // Set writeCache to contents of $data // The writeCache will be carried over to the @@ -327,25 +320,25 @@ class Stream } else { // Read the chunk from the start of $data - $chunk = substr($data, 0, 6126); + $chunk = substr( $data, 0, 6126 ); - $encrypted = $this->preWriteEncrypt($chunk, $this->plainKey); + $encrypted = $this->preWriteEncrypt( $chunk, $this->plainKey ); // Write the data chunk to disk. This will be // attended to the last data chunk if the file // being handled totals more than 6126 bytes - fwrite($this->handle, $encrypted); + fwrite( $this->handle, $encrypted ); // Remove the chunk we just processed from // $data, leaving only unprocessed data in $data // var, for handling on the next round - $data = substr($data, 6126); + $data = substr( $data, 6126 ); } } - $this->size = max($this->size, $pointer + $length); + $this->size = max( $this->size, $pointer + $length ); $this->unencryptedSize += $length; \OC_FileProxy::$enabled = $proxyStatus; @@ -360,18 +353,17 @@ class Stream * @param $arg1 * @param $arg2 */ - public function stream_set_option($option, $arg1, $arg2) - { + public function stream_set_option( $option, $arg1, $arg2 ) { $return = false; - switch ($option) { + switch ( $option ) { case STREAM_OPTION_BLOCKING: - $return = stream_set_blocking($this->handle, $arg1); + $return = stream_set_blocking( $this->handle, $arg1 ); break; case STREAM_OPTION_READ_TIMEOUT: - $return = stream_set_timeout($this->handle, $arg1, $arg2); + $return = stream_set_timeout( $this->handle, $arg1, $arg2 ); break; case STREAM_OPTION_WRITE_BUFFER: - $return = stream_set_write_buffer($this->handle, $arg1); + $return = stream_set_write_buffer( $this->handle, $arg1 ); } return $return; @@ -380,26 +372,23 @@ class Stream /** * @return array */ - public function stream_stat() - { - return fstat($this->handle); + public function stream_stat() { + return fstat( $this->handle ); } /** * @param $mode */ - public function stream_lock($mode) - { - return flock($this->handle, $mode); + public function stream_lock( $mode ) { + return flock( $this->handle, $mode ); } /** * @return bool */ - public function stream_flush() - { + public function stream_flush() { - return fflush($this->handle); + return fflush( $this->handle ); // Not a typo: http://php.net/manual/en/function.fflush.php } @@ -407,22 +396,20 @@ class Stream /** * @return bool */ - public function stream_eof() - { - return feof($this->handle); + public function stream_eof() { + return feof( $this->handle ); } - private function flush() - { + private function flush() { - if ($this->writeCache) { + if ( $this->writeCache ) { // Set keyfile property for file in question $this->getKey(); - $encrypted = $this->preWriteEncrypt($this->writeCache, $this->plainKey); + $encrypted = $this->preWriteEncrypt( $this->writeCache, $this->plainKey ); - fwrite($this->handle, $encrypted); + fwrite( $this->handle, $encrypted ); $this->writeCache = ''; @@ -433,8 +420,7 @@ class Stream /** * @return bool */ - public function stream_close() - { + public function stream_close() { $this->flush(); @@ -448,33 +434,33 @@ class Stream \OC_FileProxy::$enabled = false; // Fetch user's public key - $this->publicKey = Keymanager::getPublicKey($this->rootView, $this->userId); + $this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId ); // Check if OC sharing api is enabled $sharingEnabled = \OCP\Share::isEnabled(); - $util = new Util($this->rootView, $this->userId); + $util = new Util( $this->rootView, $this->userId ); // Get all users sharing the file includes current user - $uniqueUserIds = $util->getSharingUsersArray($sharingEnabled, $this->relPath, $this->userId); + $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $this->relPath, $this->userId ); // Fetch public keys for all sharing users - $publicKeys = Keymanager::getPublicKeys($this->rootView, $uniqueUserIds); + $publicKeys = Keymanager::getPublicKeys( $this->rootView, $uniqueUserIds ); // Encrypt enc key for all sharing users - $this->encKeyfiles = Crypt::multiKeyEncrypt($this->plainKey, $publicKeys); + $this->encKeyfiles = Crypt::multiKeyEncrypt( $this->plainKey, $publicKeys ); - $view = new \OC_FilesystemView('/'); + $view = new \OC_FilesystemView( '/' ); // Save the new encrypted file key - Keymanager::setFileKey($this->rootView, $this->relPath, $this->userId, $this->encKeyfiles['data']); + Keymanager::setFileKey( $this->rootView, $this->relPath, $this->userId, $this->encKeyfiles['data'] ); // Save the sharekeys - Keymanager::setShareKeys($view, $this->relPath, $this->encKeyfiles['keys']); + Keymanager::setShareKeys( $view, $this->relPath, $this->encKeyfiles['keys'] ); // get file info - $fileInfo = $view->getFileInfo($this->rawPath); - if (!is_array($fileInfo)) { + $fileInfo = $view->getFileInfo( $this->rawPath ); + if ( !is_array( $fileInfo ) ) { $fileInfo = array(); } @@ -487,10 +473,10 @@ class Stream $fileInfo['unencrypted_size'] = $this->unencryptedSize; // set fileinfo - $view->putFileInfo($this->rawPath, $fileInfo); + $view->putFileInfo( $this->rawPath, $fileInfo ); } - return fclose($this->handle); + return fclose( $this->handle ); } diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index d42fe9953b5..2980aa94e0c 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -117,25 +117,25 @@ class Util * @param $userId * @param bool $client */ - public function __construct(\OC_FilesystemView $view, $userId, $client = false) - { + public function __construct( \OC_FilesystemView $view, $userId, $client = false ) { $this->view = $view; $this->userId = $userId; $this->client = $client; $this->isPublic = false; - $this->publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId'); - $this->recoveryKeyId = \OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); + $this->publicShareKeyId = \OC_Appconfig::getValue( 'files_encryption', 'publicShareKeyId' ); + $this->recoveryKeyId = \OC_Appconfig::getValue( 'files_encryption', 'recoveryKeyId' ); // if we are anonymous/public - if ($this->userId === false || - (isset($_GET['service']) && $_GET['service'] == 'files' && - isset($_GET['t']))) { + if ( $this->userId === false || + ( isset( $_GET['service'] ) && $_GET['service'] == 'files' && + isset( $_GET['t'] ) ) + ) { $this->userId = $this->publicShareKeyId; // only handle for files_sharing app - if ($GLOBALS['app'] === 'files_sharing') { + if ( $GLOBALS['app'] === 'files_sharing' ) { $this->userDir = '/' . $GLOBALS['fileOwner']; $this->fileFolderName = 'files'; $this->userFilesDir = '/' . $GLOBALS['fileOwner'] . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable? @@ -164,15 +164,14 @@ class Util /** * @return bool */ - public function ready() - { + public function ready() { if ( - !$this->view->file_exists($this->encryptionDir) - or !$this->view->file_exists($this->keyfilesPath) - or !$this->view->file_exists($this->shareKeysPath) - or !$this->view->file_exists($this->publicKeyPath) - or !$this->view->file_exists($this->privateKeyPath) + !$this->view->file_exists( $this->encryptionDir ) + or !$this->view->file_exists( $this->keyfilesPath ) + or !$this->view->file_exists( $this->shareKeysPath ) + or !$this->view->file_exists( $this->publicKeyPath ) + or !$this->view->file_exists( $this->privateKeyPath ) ) { return false; @@ -189,8 +188,7 @@ class Util * @brief Sets up user folders and keys for serverside encryption * @param string $passphrase passphrase to encrypt server-stored private key with */ - public function setupServerSide($passphrase = null) - { + public function setupServerSide( $passphrase = null ) { // Set directories to check / create $setUpDirs = array( @@ -203,11 +201,11 @@ class Util ); // Check / create all necessary dirs - foreach ($setUpDirs as $dirPath) { + foreach ( $setUpDirs as $dirPath ) { - if (!$this->view->file_exists($dirPath)) { + if ( !$this->view->file_exists( $dirPath ) ) { - $this->view->mkdir($dirPath); + $this->view->mkdir( $dirPath ); } @@ -216,8 +214,8 @@ class Util // Create user keypair // we should never override a keyfile if ( - !$this->view->file_exists($this->publicKeyPath) - && !$this->view->file_exists($this->privateKeyPath) + !$this->view->file_exists( $this->publicKeyPath ) + && !$this->view->file_exists( $this->privateKeyPath ) ) { // Generate keypair @@ -226,35 +224,35 @@ class Util \OC_FileProxy::$enabled = false; // Save public key - $this->view->file_put_contents($this->publicKeyPath, $keypair['publicKey']); + $this->view->file_put_contents( $this->publicKeyPath, $keypair['publicKey'] ); // Encrypt private key with user pwd as passphrase - $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $passphrase); + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], $passphrase ); // Save private key - $this->view->file_put_contents($this->privateKeyPath, $encryptedPrivateKey); + $this->view->file_put_contents( $this->privateKeyPath, $encryptedPrivateKey ); \OC_FileProxy::$enabled = true; } else { // check if public-key exists but private-key is missing - if($this->view->file_exists($this->publicKeyPath) && !$this->view->file_exists($this->privateKeyPath)) { - \OC_Log::write('Encryption library', 'public key exists but private key is missing for "' . $this->userId . '"', \OC_Log::FATAL); + if ( $this->view->file_exists( $this->publicKeyPath ) && !$this->view->file_exists( $this->privateKeyPath ) ) { + \OC_Log::write( 'Encryption library', 'public key exists but private key is missing for "' . $this->userId . '"', \OC_Log::FATAL ); return false; - } else if(!$this->view->file_exists($this->publicKeyPath) && $this->view->file_exists($this->privateKeyPath)) { - \OC_Log::write('Encryption library', 'private key exists but public key is missing for "' . $this->userId . '"', \OC_Log::FATAL); + } else if ( !$this->view->file_exists( $this->publicKeyPath ) && $this->view->file_exists( $this->privateKeyPath ) ) { + \OC_Log::write( 'Encryption library', 'private key exists but public key is missing for "' . $this->userId . '"', \OC_Log::FATAL ); return false; } } // If there's no record for this user's encryption preferences - if (false === $this->recoveryEnabledForUser()) { + if ( false === $this->recoveryEnabledForUser() ) { // create database configuration $sql = 'INSERT INTO `*PREFIX*encryption` (`uid`,`mode`,`recovery_enabled`) VALUES (?,?,?)'; - $args = array($this->userId, 'server-side', 0); - $query = \OCP\DB::prepare($sql); - $query->execute($args); + $args = array( $this->userId, 'server-side', 0 ); + $query = \OCP\DB::prepare( $sql ); + $query->execute( $args ); } @@ -265,8 +263,7 @@ class Util /** * @return string */ - public function getPublicShareKeyId() - { + public function getPublicShareKeyId() { return $this->publicShareKeyId; } @@ -277,8 +274,7 @@ class Util * @note If records are not being returned, check for a hidden space * at the start of the uid in db */ - public function recoveryEnabledForUser() - { + public function recoveryEnabledForUser() { $sql = 'SELECT recovery_enabled @@ -287,22 +283,22 @@ class Util WHERE uid = ?'; - $args = array($this->userId); + $args = array( $this->userId ); - $query = \OCP\DB::prepare($sql); + $query = \OCP\DB::prepare( $sql ); - $result = $query->execute($args); + $result = $query->execute( $args ); $recoveryEnabled = array(); - while ($row = $result->fetchRow()) { + while ( $row = $result->fetchRow() ) { $recoveryEnabled[] = $row['recovery_enabled']; } // If no record is found - if (empty($recoveryEnabled)) { + if ( empty( $recoveryEnabled ) ) { return false; @@ -320,19 +316,18 @@ class Util * @param bool $enabled Whether to enable or disable recovery * @return bool */ - public function setRecoveryForUser($enabled) - { + public function setRecoveryForUser( $enabled ) { $recoveryStatus = $this->recoveryEnabledForUser(); // If a record for this user already exists, update it - if (false === $recoveryStatus) { + if ( false === $recoveryStatus ) { $sql = 'INSERT INTO `*PREFIX*encryption` (`uid`,`mode`,`recovery_enabled`) VALUES (?,?,?)'; - $args = array($this->userId, 'server-side', $enabled); + $args = array( $this->userId, 'server-side', $enabled ); // Create a new record instead } else { @@ -344,13 +339,13 @@ class Util WHERE uid = ?'; - $args = array($enabled, $this->userId); + $args = array( $enabled, $this->userId ); } - $query = \OCP\DB::prepare($sql); + $query = \OCP\DB::prepare( $sql ); - if ($query->execute($args)) { + if ( $query->execute( $args ) ) { return true; @@ -369,47 +364,46 @@ class Util * @note $directory needs to be a path relative to OC data dir. e.g. * /admin/files NOT /backup OR /home/www/oc/data/admin/files */ - public function findEncFiles($directory, &$found = false) - { + public function findEncFiles( $directory, &$found = false ) { // Disable proxy - we don't want files to be decrypted before // we handle them \OC_FileProxy::$enabled = false; - if($found == false) { - $found = array('plain' => array(), 'encrypted' => array(), 'legacy' => array()); + if ( $found == false ) { + $found = array( 'plain' => array(), 'encrypted' => array(), 'legacy' => array() ); } if ( - $this->view->is_dir($directory) - && $handle = $this->view->opendir($directory) + $this->view->is_dir( $directory ) + && $handle = $this->view->opendir( $directory ) ) { - while (false !== ($file = readdir($handle))) { + while ( false !== ( $file = readdir( $handle ) ) ) { if ( $file != "." && $file != ".." ) { - $filePath = $directory . '/' . $this->view->getRelativePath('/' . $file); - $relPath = $this->stripUserFilesPath($filePath); + $filePath = $directory . '/' . $this->view->getRelativePath( '/' . $file ); + $relPath = $this->stripUserFilesPath( $filePath ); // If the path is a directory, search // its contents - if ($this->view->is_dir($filePath)) { + if ( $this->view->is_dir( $filePath ) ) { - $this->findEncFiles($filePath, $found); + $this->findEncFiles( $filePath, $found ); // If the path is a file, determine // its encryption status - } elseif ($this->view->is_file($filePath)) { + } elseif ( $this->view->is_file( $filePath ) ) { // Disable proxies again, some- // where they got re-enabled :/ \OC_FileProxy::$enabled = false; - $data = $this->view->file_get_contents($filePath); + $data = $this->view->file_get_contents( $filePath ); // If the file is encrypted // NOTE: If the userId is @@ -419,22 +413,22 @@ class Util // scanning every file like this // will eat server resources :( if ( - Keymanager::getFileKey($this->view, $this->userId, $relPath) - && Crypt::isCatfileContent($data) + Keymanager::getFileKey( $this->view, $this->userId, $relPath ) + && Crypt::isCatfileContent( $data ) ) { - $found['encrypted'][] = array('name' => $file, 'path' => $filePath); + $found['encrypted'][] = array( 'name' => $file, 'path' => $filePath ); // If the file uses old // encryption system - } elseif (Crypt::isLegacyEncryptedContent($this->tail($filePath, 3), $relPath)) { + } elseif ( Crypt::isLegacyEncryptedContent( $this->tail( $filePath, 3 ), $relPath ) ) { - $found['legacy'][] = array('name' => $file, 'path' => $filePath); + $found['legacy'][] = array( 'name' => $file, 'path' => $filePath ); // If the file is not encrypted } else { - $found['plain'][] = array('name' => $file, 'path' => $relPath); + $found['plain'][] = array( 'name' => $file, 'path' => $relPath ); } @@ -446,7 +440,7 @@ class Util \OC_FileProxy::$enabled = true; - if (empty($found)) { + if ( empty( $found ) ) { return false; @@ -469,39 +463,38 @@ class Util * @note Safe to use on large files; does not read entire file to memory * @note Derivative of http://tekkie.flashbit.net/php/tail-functionality-in-php */ - public function tail($filename, $numLines) - { + public function tail( $filename, $numLines ) { \OC_FileProxy::$enabled = false; $text = ''; $pos = -1; - $handle = $this->view->fopen($filename, 'r'); + $handle = $this->view->fopen( $filename, 'r' ); - while ($numLines > 0) { + while ( $numLines > 0 ) { --$pos; - if (fseek($handle, $pos, SEEK_END) !== 0) { + if ( fseek( $handle, $pos, SEEK_END ) !== 0 ) { - rewind($handle); + rewind( $handle ); $numLines = 0; - } elseif (fgetc($handle) === "\n") { + } elseif ( fgetc( $handle ) === "\n" ) { --$numLines; } - $block_size = (-$pos) % 8192; - if ($block_size === 0 || $numLines === 0) { + $block_size = ( -$pos ) % 8192; + if ( $block_size === 0 || $numLines === 0 ) { - $text = fread($handle, ($block_size === 0 ? 8192 : $block_size)) . $text; + $text = fread( $handle, ( $block_size === 0 ? 8192 : $block_size ) ) . $text; } } - fclose($handle); + fclose( $handle ); \OC_FileProxy::$enabled = true; @@ -513,8 +506,7 @@ class Util * @param $path * @return boolean */ - public function isEncryptedPath($path) - { + public function isEncryptedPath( $path ) { // Disable encryption proxy so data retrieved is in its // original form @@ -523,15 +515,15 @@ class Util // we only need 24 byte from the last chunk $data = ''; - $handle = $this->view->fopen($path, 'r'); - if (!fseek($handle, -24, SEEK_END)) { - $data = fgets($handle); + $handle = $this->view->fopen( $path, 'r' ); + if ( !fseek( $handle, -24, SEEK_END ) ) { + $data = fgets( $handle ); } // re-enable proxy \OC_FileProxy::$enabled = $proxyStatus; - return Crypt::isCatfileContent($data); + return Crypt::isCatfileContent( $data ); } @@ -540,8 +532,7 @@ class Util * @param string $path absolute path * @return bool */ - public function getFileSize($path) - { + public function getFileSize( $path ) { $result = 0; @@ -550,33 +541,33 @@ class Util \OC_FileProxy::$enabled = false; // Reformat path for use with OC_FSV - $pathSplit = explode('/', $path); - $pathRelative = implode('/', array_slice($pathSplit, 3)); + $pathSplit = explode( '/', $path ); + $pathRelative = implode( '/', array_slice( $pathSplit, 3 ) ); - if ($pathSplit[2] == 'files' && $this->view->file_exists($path) && $this->isEncryptedPath($path)) { + if ( $pathSplit[2] == 'files' && $this->view->file_exists( $path ) && $this->isEncryptedPath( $path ) ) { // get the size from filesystem - $fullPath = $this->view->getLocalFile($path); - $size = filesize($fullPath); + $fullPath = $this->view->getLocalFile( $path ); + $size = filesize( $fullPath ); // calculate last chunk nr - $lastChunckNr = floor($size / 8192); + $lastChunkNr = floor( $size / 8192 ); // open stream - $stream = fopen('crypt://' . $pathRelative, "r"); + $stream = fopen( 'crypt://' . $pathRelative, "r" ); - if (is_resource($stream)) { + if ( is_resource( $stream ) ) { // calculate last chunk position - $lastChunckPos = ($lastChunckNr * 8192); + $lastChunckPos = ( $lastChunkNr * 8192 ); // seek to end - fseek($stream, $lastChunckPos); + fseek( $stream, $lastChunckPos ); // get the content of the last chunk - $lastChunkContent = fread($stream, 8192); + $lastChunkContent = fread( $stream, 8192 ); // calc the real file size with the size of the last chunk - $realSize = (($lastChunckNr * 6126) + strlen($lastChunkContent)); + $realSize = ( ( $lastChunkNr * 6126 ) + strlen( $lastChunkContent ) ); // store file size $result = $realSize; @@ -593,8 +584,7 @@ class Util * @param $path absolute path * @return true / false if file is encrypted */ - public function fixFileSize($path) - { + public function fixFileSize( $path ) { $result = false; @@ -602,18 +592,18 @@ class Util $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $realSize = $this->getFileSize($path); + $realSize = $this->getFileSize( $path ); - if ($realSize > 0) { + if ( $realSize > 0 ) { - $cached = $this->view->getFileInfo($path); + $cached = $this->view->getFileInfo( $path ); $cached['encrypted'] = true; // set the size $cached['unencrypted_size'] = $realSize; // put file info - $this->view->putFileInfo($path, $cached); + $this->view->putFileInfo( $path, $cached ); $result = true; @@ -628,13 +618,12 @@ class Util * @brief Format a path to be relative to the /user/files/ directory * @note e.g. turns '/admin/files/test.txt' into 'test.txt' */ - public function stripUserFilesPath($path) - { + public function stripUserFilesPath( $path ) { - $trimmed = ltrim($path, '/'); - $split = explode('/', $trimmed); - $sliced = array_slice($split, 2); - $relPath = implode('/', $sliced); + $trimmed = ltrim( $path, '/' ); + $split = explode( '/', $trimmed ); + $sliced = array_slice( $split, 2 ); + $relPath = implode( '/', $sliced ); return $relPath; @@ -644,13 +633,12 @@ class Util * @param $path * @return bool */ - public function isSharedPath($path) - { + public function isSharedPath( $path ) { - $trimmed = ltrim($path, '/'); - $split = explode('/', $trimmed); + $trimmed = ltrim( $path, '/' ); + $split = explode( '/', $trimmed ); - if ($split[2] == "Shared") { + if ( $split[2] == "Shared" ) { return true; @@ -670,16 +658,15 @@ class Util * @return bool * @note Encryption is recursive */ - public function encryptAll($dirPath, $legacyPassphrase = null, $newPassphrase = null) - { + public function encryptAll( $dirPath, $legacyPassphrase = null, $newPassphrase = null ) { - if ($found = $this->findEncFiles($dirPath)) { + if ( $found = $this->findEncFiles( $dirPath ) ) { // Disable proxy to prevent file being encrypted twice \OC_FileProxy::$enabled = false; // Encrypt unencrypted files - foreach ($found['plain'] as $plainFile) { + foreach ( $found['plain'] as $plainFile ) { //relative to data//file $relPath = $plainFile['path']; @@ -688,80 +675,80 @@ class Util $rawPath = $this->userId . '/files/' . $plainFile['path']; // Open plain file handle for binary reading - $plainHandle1 = $this->view->fopen($rawPath, 'rb'); + $plainHandle1 = $this->view->fopen( $rawPath, 'rb' ); // 2nd handle for moving plain file - view->rename() doesn't work, this is a workaround - $plainHandle2 = $this->view->fopen($rawPath . '.plaintmp', 'wb'); + $plainHandle2 = $this->view->fopen( $rawPath . '.plaintmp', 'wb' ); // Move plain file to a temporary location - stream_copy_to_stream($plainHandle1, $plainHandle2); + stream_copy_to_stream( $plainHandle1, $plainHandle2 ); // Close access to original file // $this->view->fclose( $plainHandle1 ); // not implemented in view{} // Delete original plain file so we can rename enc file later - $this->view->unlink($rawPath); + $this->view->unlink( $rawPath ); // Open enc file handle for binary writing, with same filename as original plain file - $encHandle = fopen('crypt://' . $relPath, 'wb'); + $encHandle = fopen( 'crypt://' . $relPath, 'wb' ); // Save data from plain stream to new encrypted file via enc stream // NOTE: Stream{} will be invoked for handling // the encryption, and should handle all keys // and their generation etc. automatically - stream_copy_to_stream($plainHandle2, $encHandle); + stream_copy_to_stream( $plainHandle2, $encHandle ); // get file size - $size = $this->view->filesize($rawPath . '.plaintmp'); + $size = $this->view->filesize( $rawPath . '.plaintmp' ); // Delete temporary plain copy of file - $this->view->unlink($rawPath . '.plaintmp'); + $this->view->unlink( $rawPath . '.plaintmp' ); // Add the file to the cache - \OC\Files\Filesystem::putFileInfo($plainFile['path'], array('encrypted' => true, 'size' => $size, 'unencrypted_size' => $size)); + \OC\Files\Filesystem::putFileInfo( $plainFile['path'], array( 'encrypted' => true, 'size' => $size, 'unencrypted_size' => $size ) ); } // Encrypt legacy encrypted files if ( - !empty($legacyPassphrase) - && !empty($newPassphrase) + !empty( $legacyPassphrase ) + && !empty( $newPassphrase ) ) { - foreach ($found['legacy'] as $legacyFile) { + foreach ( $found['legacy'] as $legacyFile ) { // Fetch data from file - $legacyData = $this->view->file_get_contents($legacyFile['path']); + $legacyData = $this->view->file_get_contents( $legacyFile['path'] ); $sharingEnabled = \OCP\Share::isEnabled(); // if file exists try to get sharing users - if ($this->view->file_exists($legacyFile['path'])) { - $uniqueUserIds = $this->getSharingUsersArray($sharingEnabled, $legacyFile['path'], $this->userId); + if ( $this->view->file_exists( $legacyFile['path'] ) ) { + $uniqueUserIds = $this->getSharingUsersArray( $sharingEnabled, $legacyFile['path'], $this->userId ); } else { $uniqueUserIds[] = $this->userId; } // Fetch public keys for all users who will share the file - $publicKeys = Keymanager::getPublicKeys($this->view, $uniqueUserIds); + $publicKeys = Keymanager::getPublicKeys( $this->view, $uniqueUserIds ); // Recrypt data, generate catfile - $recrypted = Crypt::legacyKeyRecryptKeyfile($legacyData, $legacyPassphrase, $publicKeys, $newPassphrase, $legacyFile['path']); + $recrypted = Crypt::legacyKeyRecryptKeyfile( $legacyData, $legacyPassphrase, $publicKeys, $newPassphrase, $legacyFile['path'] ); $rawPath = $legacyFile['path']; - $relPath = $this->stripUserFilesPath($rawPath); + $relPath = $this->stripUserFilesPath( $rawPath ); // Save keyfile - Keymanager::setFileKey($this->view, $relPath, $this->userId, $recrypted['filekey']); + Keymanager::setFileKey( $this->view, $relPath, $this->userId, $recrypted['filekey'] ); // Save sharekeys to user folders - Keymanager::setShareKeys($this->view, $relPath, $recrypted['sharekeys']); + Keymanager::setShareKeys( $this->view, $relPath, $recrypted['sharekeys'] ); // Overwrite the existing file with the encrypted one - $this->view->file_put_contents($rawPath, $recrypted['data']); + $this->view->file_put_contents( $rawPath, $recrypted['data'] ); - $size = strlen($recrypted['data']); + $size = strlen( $recrypted['data'] ); // Add the file to the cache - \OC\Files\Filesystem::putFileInfo($rawPath, array('encrypted' => true, 'size' => $size), ''); + \OC\Files\Filesystem::putFileInfo( $rawPath, array( 'encrypted' => true, 'size' => $size ), '' ); } } @@ -781,10 +768,9 @@ class Util * @param string $pathName Name of the directory to return the path of * @return string path */ - public function getPath($pathName) - { + public function getPath( $pathName ) { - switch ($pathName) { + switch ( $pathName ) { case 'publicKeyDir': @@ -815,9 +801,10 @@ class Util return $this->privateKeyPath; break; - } + return false; + } /** @@ -825,18 +812,17 @@ class Util * @param int $fileId id of the file * @return string path of the file */ - public static function fileIdToPath($fileId) - { + public static function fileIdToPath( $fileId ) { - $query = \OC_DB::prepare('SELECT `path`' + $query = \OC_DB::prepare( 'SELECT `path`' . ' FROM `*PREFIX*filecache`' - . ' WHERE `fileid` = ?'); + . ' WHERE `fileid` = ?' ); - $result = $query->execute(array($fileId)); + $result = $query->execute( array( $fileId ) ); $row = $result->fetchRow(); - return substr($row['path'], 5); + return substr( $row['path'], 5 ); } @@ -845,16 +831,15 @@ class Util * @param array $unfilteredUsers users to be checked for sharing readiness * @return multi-dimensional array. keys: ready, unready */ - public function filterShareReadyUsers($unfilteredUsers) - { + public function filterShareReadyUsers( $unfilteredUsers ) { // This array will collect the filtered IDs $readyIds = $unreadyIds = array(); // Loop through users and create array of UIDs that need new keyfiles - foreach ($unfilteredUsers as $user) { + foreach ( $unfilteredUsers as $user ) { - $util = new Util($this->view, $user); + $util = new Util( $this->view, $user ); // Check that the user is encryption capable, or is the // public system user 'ownCloud' (for public shares) @@ -874,15 +859,15 @@ class Util // Log warning; we can't do necessary setup here // because we don't have the user passphrase - \OC_Log::write('Encryption library', '"' . $user . '" is not setup for encryption', \OC_Log::WARN); + \OC_Log::write( 'Encryption library', '"' . $user . '" is not setup for encryption', \OC_Log::WARN ); } } return array( - 'ready' => $readyIds - , 'unready' => $unreadyIds + 'ready' => $readyIds, + 'unready' => $unreadyIds ); } @@ -897,32 +882,31 @@ class Util * @note This was used when 2 types of encryption for keyfiles was used, * but now we've switched to exclusively using openssl_seal() */ - public function decryptUnknownKeyfile($filePath, $fileOwner, $privateKey) - { + public function decryptUnknownKeyfile( $filePath, $fileOwner, $privateKey ) { // Get the encrypted keyfile // NOTE: the keyfile format depends on how it was encrypted! At // this stage we don't know how it was encrypted - $encKeyfile = Keymanager::getFileKey($this->view, $this->userId, $filePath); + $encKeyfile = Keymanager::getFileKey( $this->view, $this->userId, $filePath ); // We need to decrypt the keyfile // Has the file been shared yet? if ( $this->userId == $fileOwner - && !Keymanager::getShareKey($this->view, $this->userId, $filePath) // NOTE: we can't use isShared() here because it's a post share hook so it always returns true + && !Keymanager::getShareKey( $this->view, $this->userId, $filePath ) // NOTE: we can't use isShared() here because it's a post share hook so it always returns true ) { // The file has no shareKey, and its keyfile must be // decrypted conventionally - $plainKeyfile = Crypt::keyDecrypt($encKeyfile, $privateKey); + $plainKeyfile = Crypt::keyDecrypt( $encKeyfile, $privateKey ); } else { // The file has a shareKey and must use it for decryption - $shareKey = Keymanager::getShareKey($this->view, $this->userId, $filePath); + $shareKey = Keymanager::getShareKey( $this->view, $this->userId, $filePath ); - $plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); } @@ -937,23 +921,22 @@ class Util * @param string $filePath path of the file to be shared * @return bool */ - public function setSharedFileKeyfiles(Session $session, array $users, $filePath) - { + public function setSharedFileKeyfiles( Session $session, array $users, $filePath ) { // Make sure users are capable of sharing - $filteredUids = $this->filterShareReadyUsers($users); + $filteredUids = $this->filterShareReadyUsers( $users ); // If we're attempting to share to unready users - if (!empty($filteredUids['unready'])) { + if ( !empty( $filteredUids['unready'] ) ) { - \OC_Log::write('Encryption library', 'Sharing to these user(s) failed as they are unready for encryption:"' . print_r($filteredUids['unready'], 1), \OC_Log::WARN); + \OC_Log::write( 'Encryption library', 'Sharing to these user(s) failed as they are unready for encryption:"' . print_r( $filteredUids['unready'], 1 ), \OC_Log::WARN ); return false; } // Get public keys for each user, ready for generating sharekeys - $userPubKeys = Keymanager::getPublicKeys($this->view, $filteredUids['ready']); + $userPubKeys = Keymanager::getPublicKeys( $this->view, $filteredUids['ready'] ); // Note proxy status then disable it $proxyStatus = \OC_FileProxy::$enabled; @@ -962,22 +945,22 @@ class Util // Get the current users's private key for decrypting existing keyfile $privateKey = $session->getPrivateKey(); - $fileOwner = \OC\Files\Filesystem::getOwner($filePath); + $fileOwner = \OC\Files\Filesystem::getOwner( $filePath ); // Decrypt keyfile - $plainKeyfile = $this->decryptUnknownKeyfile($filePath, $fileOwner, $privateKey); + $plainKeyfile = $this->decryptUnknownKeyfile( $filePath, $fileOwner, $privateKey ); // Re-enc keyfile to (additional) sharekeys - $multiEncKey = Crypt::multiKeyEncrypt($plainKeyfile, $userPubKeys); + $multiEncKey = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys ); // Save the recrypted key to it's owner's keyfiles directory // Save new sharekeys to all necessary user directory if ( - !Keymanager::setFileKey($this->view, $filePath, $fileOwner, $multiEncKey['data']) - || !Keymanager::setShareKeys($this->view, $filePath, $multiEncKey['keys']) + !Keymanager::setFileKey( $this->view, $filePath, $fileOwner, $multiEncKey['data'] ) + || !Keymanager::setShareKeys( $this->view, $filePath, $multiEncKey['keys'] ) ) { - \OC_Log::write('Encryption library', 'Keyfiles could not be saved for users sharing ' . $filePath, \OC_Log::ERROR); + \OC_Log::write( 'Encryption library', 'Keyfiles could not be saved for users sharing ' . $filePath, \OC_Log::ERROR ); return false; @@ -993,12 +976,11 @@ class Util * @brief Find, sanitise and format users sharing a file * @note This wraps other methods into a portable bundle */ - public function getSharingUsersArray($sharingEnabled, $filePath, $currentUserId = false) - { + public function getSharingUsersArray( $sharingEnabled, $filePath, $currentUserId = false ) { // Check if key recovery is enabled if ( - \OC_Appconfig::getValue('files_encryption', 'recoveryAdminEnabled') + \OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' ) && $this->recoveryEnabledForUser() ) { @@ -1011,14 +993,15 @@ class Util } // Make sure that a share key is generated for the owner too - list($owner, $ownerPath) = $this->getUidAndFilename($filePath); + list( $owner, $ownerPath ) = $this->getUidAndFilename( $filePath ); - if ($sharingEnabled) { + $userIds = array(); + if ( $sharingEnabled ) { // Find out who, if anyone, is sharing the file - $result = \OCP\Share::getUsersSharingFile($ownerPath, $owner, true, true, true); + $result = \OCP\Share::getUsersSharingFile( $ownerPath, $owner, true, true, true ); $userIds = $result['users']; - if ($result['public']) { + if ( $result['public'] ) { $userIds[] = $this->publicShareKeyId; } @@ -1026,10 +1009,10 @@ class Util // If recovery is enabled, add the // Admin UID to list of users to share to - if ($recoveryEnabled) { + if ( $recoveryEnabled ) { // Find recoveryAdmin user ID - $recoveryKeyId = \OC_Appconfig::getValue('files_encryption', 'recoveryKeyId'); + $recoveryKeyId = \OC_Appconfig::getValue( 'files_encryption', 'recoveryKeyId' ); // Add recoveryAdmin to list of users sharing $userIds[] = $recoveryKeyId; @@ -1037,14 +1020,14 @@ class Util } // add current user if given - if ($currentUserId != false) { + if ( $currentUserId != false ) { $userIds[] = $currentUserId; } // Remove duplicate UIDs - $uniqueUserIds = array_unique($userIds); + $uniqueUserIds = array_unique( $userIds ); return $uniqueUserIds; @@ -1055,8 +1038,7 @@ class Util * @param $status * @return bool */ - public function setMigrationStatus($status) - { + public function setMigrationStatus( $status ) { $sql = 'UPDATE *PREFIX*encryption @@ -1065,11 +1047,11 @@ class Util WHERE uid = ?'; - $args = array($status, $this->userId); + $args = array( $status, $this->userId ); - $query = \OCP\DB::prepare($sql); + $query = \OCP\DB::prepare( $sql ); - if ($query->execute($args)) { + if ( $query->execute( $args ) ) { return true; @@ -1087,8 +1069,7 @@ class Util * @note If records are not being returned, check for a hidden space * at the start of the uid in db */ - public function getMigrationStatus() - { + public function getMigrationStatus() { $sql = 'SELECT migration_status @@ -1097,22 +1078,21 @@ class Util WHERE uid = ?'; - $args = array($this->userId); + $args = array( $this->userId ); - $query = \OCP\DB::prepare($sql); + $query = \OCP\DB::prepare( $sql ); - $result = $query->execute($args); + $result = $query->execute( $args ); $migrationStatus = array(); - while ($row = $result->fetchRow()) { - + $row = $result->fetchRow(); + if($row) { $migrationStatus[] = $row['migration_status']; - } // If no record is found - if (empty($migrationStatus)) { + if ( empty( $migrationStatus ) ) { return false; @@ -1132,83 +1112,74 @@ class Util * relative to /Shared are also acceptable * @return array */ - public function getUidAndFilename($path) - { + public function getUidAndFilename( $path ) { - $view = new \OC\Files\View($this->userFilesDir); - $fileOwnerUid = $view->getOwner($path); + $view = new \OC\Files\View( $this->userFilesDir ); + $fileOwnerUid = $view->getOwner( $path ); // handle public access - if ($this->isPublic) { + if ( $this->isPublic ) { $filename = $path; $fileOwnerUid = $GLOBALS['fileOwner']; - return array($fileOwnerUid, $filename); + return array( $fileOwnerUid, $filename ); } else { // Check that UID is valid - if (!\OCP\User::userExists($fileOwnerUid)) { - throw new \Exception('Could not find owner (UID = "' . var_export($fileOwnerUid, 1) . '") of file "' . $path . '"'); + if ( !\OCP\User::userExists( $fileOwnerUid ) ) { + throw new \Exception( 'Could not find owner (UID = "' . var_export( $fileOwnerUid, 1 ) . '") of file "' . $path . '"' ); } // NOTE: Bah, this dependency should be elsewhere - \OC\Files\Filesystem::initMountPoints($fileOwnerUid); + \OC\Files\Filesystem::initMountPoints( $fileOwnerUid ); // If the file owner is the currently logged in user - if ($fileOwnerUid == $this->userId) { + if ( $fileOwnerUid == $this->userId ) { // Assume the path supplied is correct $filename = $path; } else { - $info = $view->getFileInfo($path); - $ownerView = new \OC\Files\View('/' . $fileOwnerUid . '/files'); + $info = $view->getFileInfo( $path ); + $ownerView = new \OC\Files\View( '/' . $fileOwnerUid . '/files' ); // Fetch real file path from DB - $filename = $ownerView->getPath($info['fileid']); // TODO: Check that this returns a path without including the user data dir + $filename = $ownerView->getPath( $info['fileid'] ); // TODO: Check that this returns a path without including the user data dir } - return array($fileOwnerUid, $filename); + return array( $fileOwnerUid, $filename ); } } /** - * @brief geo recursively through a dir and collect all files and sub files. + * @brief go recursively through a dir and collect all files and sub files. * @param string $dir relative to the users files folder * @return array with list of files relative to the users files folder */ - public function getAllFiles($dir) - { + public function getAllFiles( $dir ) { $result = array(); - $content = $this->view->getDirectoryContent($this->userFilesDir . $dir); + $content = $this->view->getDirectoryContent( $this->userFilesDir . $dir ); // handling for re shared folders - $path_split = explode('/', $dir); - $shared = ''; - - if ($path_split[1] === 'Shared') { - - $shared = '/Shared'; + $path_split = explode( '/', $dir ); - } - - foreach ($content as $c) { + foreach ( $content as $c ) { - $sharedPart = $path_split[sizeof($path_split) - 1]; - $targetPathSplit = array_reverse(explode('/', $c['path'])); + $sharedPart = $path_split[sizeof( $path_split ) - 1]; + $targetPathSplit = array_reverse( explode( '/', $c['path'] ) ); $path = ''; // rebuild path - foreach ($targetPathSplit as $pathPart) { + foreach ( $targetPathSplit as $pathPart ) { - if ($pathPart !== $sharedPart) { + if ( $pathPart !== $sharedPart ) { $path = '/' . $pathPart . $path; @@ -1222,9 +1193,9 @@ class Util $path = $dir . $path; - if ($c['type'] === "dir") { + if ( $c['type'] === "dir" ) { - $result = array_merge($result, $this->getAllFiles($path)); + $result = array_merge( $result, $this->getAllFiles( $path ) ); } else { @@ -1242,14 +1213,13 @@ class Util * @param int $id of the current share * @return array of the parent */ - public static function getShareParent($id) - { + public static function getShareParent( $id ) { - $query = \OC_DB::prepare('SELECT `file_target`, `item_type`' + $query = \OC_DB::prepare( 'SELECT `file_target`, `item_type`' . ' FROM `*PREFIX*share`' - . ' WHERE `id` = ?'); + . ' WHERE `id` = ?' ); - $result = $query->execute(array($id)); + $result = $query->execute( array( $id ) ); $row = $result->fetchRow(); @@ -1262,14 +1232,13 @@ class Util * @param int $id of the current share * @return array of the parent */ - public static function getParentFromShare($id) - { + public static function getParentFromShare( $id ) { - $query = \OC_DB::prepare('SELECT `parent`' + $query = \OC_DB::prepare( 'SELECT `parent`' . ' FROM `*PREFIX*share`' - . ' WHERE `id` = ?'); + . ' WHERE `id` = ?' ); - $result = $query->execute(array($id)); + $result = $query->execute( array( $id ) ); $row = $result->fetchRow(); @@ -1283,22 +1252,23 @@ class Util * @internal param int $Id of a share * @return string owner */ - public function getOwnerFromSharedFile($id) - { + public function getOwnerFromSharedFile( $id ) { + + $query = \OC_DB::prepare( 'SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1 ); + $source = $query->execute( array( $id ) )->fetchRow(); - $query = \OC_DB::prepare('SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1); - $source = $query->execute(array($id))->fetchRow(); + $fileOwner = false; - if (isset($source['parent'])) { + if ( isset( $source['parent'] ) ) { $parent = $source['parent']; - while (isset($parent)) { + while ( isset( $parent ) ) { - $query = \OC_DB::prepare('SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1); - $item = $query->execute(array($parent))->fetchRow(); + $query = \OC_DB::prepare( 'SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1 ); + $item = $query->execute( array( $parent ) )->fetchRow(); - if (isset($item['parent'])) { + if ( isset( $item['parent'] ) ) { $parent = $item['parent']; @@ -1324,16 +1294,14 @@ class Util /** * @return string */ - public function getUserId() - { + public function getUserId() { return $this->userId; } /** * @return string */ - public function getUserFilesDir() - { + public function getUserFilesDir() { return $this->userFilesDir; } @@ -1341,8 +1309,7 @@ class Util * @param $password * @return bool */ - public function checkRecoveryPassword($password) - { + public function checkRecoveryPassword( $password ) { $pathKey = '/owncloud_private_key/' . $this->recoveryKeyId . ".private.key"; $pathControlData = '/control-file/controlfile.enc'; @@ -1350,16 +1317,16 @@ class Util $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $recoveryKey = $this->view->file_get_contents($pathKey); + $recoveryKey = $this->view->file_get_contents( $pathKey ); - $decryptedRecoveryKey = Crypt::symmetricDecryptFileContent($recoveryKey, $password); + $decryptedRecoveryKey = Crypt::symmetricDecryptFileContent( $recoveryKey, $password ); - $controlData = $this->view->file_get_contents($pathControlData); - $decryptedControlData = Crypt::keyDecrypt($controlData, $decryptedRecoveryKey); + $controlData = $this->view->file_get_contents( $pathControlData ); + $decryptedControlData = Crypt::keyDecrypt( $controlData, $decryptedRecoveryKey ); \OC_FileProxy::$enabled = $proxyStatus; - if ($decryptedControlData === 'ownCloud') { + if ( $decryptedControlData === 'ownCloud' ) { return true; } @@ -1369,27 +1336,26 @@ class Util /** * @return string */ - public function getRecoveryKeyId() - { + public function getRecoveryKeyId() { return $this->recoveryKeyId; } /** * @brief add recovery key to all encrypted files */ - public function addRecoveryKeys($path = '/') - { - $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path); - foreach ($dirContent as $item) { - $filePath = substr($item['path'], 25); - if ($item['type'] == 'dir') { - $this->addRecoveryKeys($filePath . '/'); + public function addRecoveryKeys( $path = '/' ) { + $dirContent = $this->view->getDirectoryContent( $this->keyfilesPath . $path ); + foreach ( $dirContent as $item ) { + // get relative path from files_encryption/keyfiles/ + $filePath = substr( $item['path'], strlen('files_encryption/keyfiles') ); + if ( $item['type'] == 'dir' ) { + $this->addRecoveryKeys( $filePath . '/' ); } else { - $session = new Session(new \OC_FilesystemView('/')); + $session = new Session( new \OC_FilesystemView( '/' ) ); $sharingEnabled = \OCP\Share::isEnabled(); - $file = substr($filePath, 0, -4); - $usersSharing = $this->getSharingUsersArray($sharingEnabled, $file); - $this->setSharedFileKeyfiles($session, $usersSharing, $file); + $file = substr( $filePath, 0, -4 ); + $usersSharing = $this->getSharingUsersArray( $sharingEnabled, $file ); + $this->setSharedFileKeyfiles( $session, $usersSharing, $file ); } } } @@ -1397,16 +1363,16 @@ class Util /** * @brief remove recovery key to all encrypted files */ - public function removeRecoveryKeys($path = '/') - { - $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path); - foreach ($dirContent as $item) { - $filePath = substr($item['path'], 25); - if ($item['type'] == 'dir') { - $this->removeRecoveryKeys($filePath . '/'); + public function removeRecoveryKeys( $path = '/' ) { + $dirContent = $this->view->getDirectoryContent( $this->keyfilesPath . $path ); + foreach ( $dirContent as $item ) { + // get relative path from files_encryption/keyfiles + $filePath = substr( $item['path'], strlen('files_encryption/keyfiles') ); + if ( $item['type'] == 'dir' ) { + $this->removeRecoveryKeys( $filePath . '/' ); } else { - $file = substr($filePath, 0, -4); - $this->view->unlink($this->shareKeysPath . '/' . $file . '.' . $this->recoveryKeyId . '.shareKey'); + $file = substr( $filePath, 0, -4 ); + $this->view->unlink( $this->shareKeysPath . '/' . $file . '.' . $this->recoveryKeyId . '.shareKey' ); } } } @@ -1416,40 +1382,39 @@ class Util * @param string $file * @param string $privateKey recovery key to decrypt the file */ - private function recoverFile($file, $privateKey) - { + private function recoverFile( $file, $privateKey ) { $sharingEnabled = \OCP\Share::isEnabled(); // Find out who, if anyone, is sharing the file - if ($sharingEnabled) { - $result = \OCP\Share::getUsersSharingFile($file, $this->userId, true, true, true); + if ( $sharingEnabled ) { + $result = \OCP\Share::getUsersSharingFile( $file, $this->userId, true, true, true ); $userIds = $result['users']; $userIds[] = $this->recoveryKeyId; - if ($result['public']) { + if ( $result['public'] ) { $userIds[] = $this->publicShareKeyId; } } else { - $userIds = array($this->userId, $this->recoveryKeyId); + $userIds = array( $this->userId, $this->recoveryKeyId ); } - $filteredUids = $this->filterShareReadyUsers($userIds); + $filteredUids = $this->filterShareReadyUsers( $userIds ); $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; //decrypt file key - $encKeyfile = $this->view->file_get_contents($this->keyfilesPath . $file . ".key"); - $shareKey = $this->view->file_get_contents($this->shareKeysPath . $file . "." . $this->recoveryKeyId . ".shareKey"); - $plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + $encKeyfile = $this->view->file_get_contents( $this->keyfilesPath . $file . ".key" ); + $shareKey = $this->view->file_get_contents( $this->shareKeysPath . $file . "." . $this->recoveryKeyId . ".shareKey" ); + $plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey ); // encrypt file key again to all users, this time with the new public key for the recovered use - $userPubKeys = Keymanager::getPublicKeys($this->view, $filteredUids['ready']); - $multiEncKey = Crypt::multiKeyEncrypt($plainKeyfile, $userPubKeys); + $userPubKeys = Keymanager::getPublicKeys( $this->view, $filteredUids['ready'] ); + $multiEncKey = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys ); // write new keys to filesystem TDOO! - $this->view->file_put_contents($this->keyfilesPath . $file . '.key', $multiEncKey['data']); - foreach ($multiEncKey['keys'] as $userId => $shareKey) { + $this->view->file_put_contents( $this->keyfilesPath . $file . '.key', $multiEncKey['data'] ); + foreach ( $multiEncKey['keys'] as $userId => $shareKey ) { $shareKeyPath = $this->shareKeysPath . $file . '.' . $userId . '.shareKey'; - $this->view->file_put_contents($shareKeyPath, $shareKey); + $this->view->file_put_contents( $shareKeyPath, $shareKey ); } // Return proxy to original status @@ -1461,16 +1426,15 @@ class Util * @param string $path to look for files keys * @param string $privateKey private recovery key which is used to decrypt the files */ - private function recoverAllFiles($path, $privateKey) - { - $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path); - foreach ($dirContent as $item) { - $filePath = substr($item['path'], 25); - if ($item['type'] == 'dir') { - $this->recoverAllFiles($filePath . '/', $privateKey); + private function recoverAllFiles( $path, $privateKey ) { + $dirContent = $this->view->getDirectoryContent( $this->keyfilesPath . $path ); + foreach ( $dirContent as $item ) { + $filePath = substr( $item['path'], 25 ); + if ( $item['type'] == 'dir' ) { + $this->recoverAllFiles( $filePath . '/', $privateKey ); } else { - $file = substr($filePath, 0, -4); - $this->recoverFile($file, $privateKey); + $file = substr( $filePath, 0, -4 ); + $this->recoverFile( $file, $privateKey ); } } } @@ -1479,19 +1443,18 @@ class Util * @brief recover users files in case of password lost * @param string $recoveryPassword */ - public function recoverUsersFiles($recoveryPassword) - { + public function recoverUsersFiles( $recoveryPassword ) { // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $encryptedKey = $this->view->file_get_contents('/owncloud_private_key/' . $this->recoveryKeyId . '.private.key'); - $privateKey = Crypt::symmetricDecryptFileContent($encryptedKey, $recoveryPassword); + $encryptedKey = $this->view->file_get_contents( '/owncloud_private_key/' . $this->recoveryKeyId . '.private.key' ); + $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $recoveryPassword ); \OC_FileProxy::$enabled = $proxyStatus; - $this->recoverAllFiles('/', $privateKey); + $this->recoverAllFiles( '/', $privateKey ); } } diff --git a/apps/files_encryption/settings-admin.php b/apps/files_encryption/settings-admin.php index 66efc584367..6cc5b997fdb 100644 --- a/apps/files_encryption/settings-admin.php +++ b/apps/files_encryption/settings-admin.php @@ -15,7 +15,6 @@ $view = new OC_FilesystemView( '' ); $recoveryAdminEnabled = OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' ); -$tmpl->assign( 'encryption_mode', \OC_Appconfig::getValue( 'files_encryption', 'mode', 'none' ) ); $tmpl->assign( 'recoveryEnabled', $recoveryAdminEnabled ); \OCP\Util::addscript( 'files_encryption', 'settings-admin' ); diff --git a/apps/files_encryption/settings-personal.php b/apps/files_encryption/settings-personal.php index ada8ffbc318..57f7f584523 100644 --- a/apps/files_encryption/settings-personal.php +++ b/apps/files_encryption/settings-personal.php @@ -26,4 +26,3 @@ $tmpl->assign( 'recoveryEnabledForUser', $recoveryEnabledForUser ); return $tmpl->fetchPage(); -return null; diff --git a/apps/files_encryption/templates/settings-personal.php b/apps/files_encryption/templates/settings-personal.php index 14e8ce960a2..04d6e79179e 100644 --- a/apps/files_encryption/templates/settings-personal.php +++ b/apps/files_encryption/templates/settings-personal.php @@ -29,18 +29,5 @@


- -- cgit v1.2.3