From c8946ea6086c642a5c367f2e5f63d58bc185c331 Mon Sep 17 00:00:00 2001 From: Sam Tuke Date: Sat, 4 May 2013 16:14:38 +0200 Subject: [PATCH] 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 +- .../templates/settings-admin.php | 11 +- .../templates/settings-personal.php | 38 +++--- 10 files changed, 215 insertions(+), 89 deletions(-) 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" )); ?> +

+ -- 2.39.5