Added method for setting user keyfile recovery preference

Fixed method for checking if keyfile recovery is enabled for a user
Added unit test for above 2 methods
Made proxy{} always use sharing
Made proxy{} work regardless of sharing API enabled or not
Implemented proxy-based sharing to admin if user keyfile recovery is enabled
This commit is contained in:
Sam Tuke 2013-03-20 19:26:59 +01:00
parent c89fd49870
commit fd4e59b748
5 changed files with 127 additions and 32 deletions

View File

@ -40,7 +40,6 @@ class Hooks {
\OC\Files\Filesystem::init( $params['uid'] . '/' . 'files' . '/' ); \OC\Files\Filesystem::init( $params['uid'] . '/' . 'files' . '/' );
$view = new \OC_FilesystemView( '/' ); $view = new \OC_FilesystemView( '/' );
$util = new Util( $view, $params['uid'] ); $util = new Util( $view, $params['uid'] );
// Check files_encryption infrastructure is ready for action // Check files_encryption infrastructure is ready for action
@ -61,7 +60,6 @@ class Hooks {
$privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $params['password'] ); $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $params['password'] );
$session = new Session(); $session = new Session();
$session->setPrivateKey( $privateKey, $params['uid'] ); $session->setPrivateKey( $privateKey, $params['uid'] );
$view1 = new \OC_FilesystemView( '/' . $params['uid'] ); $view1 = new \OC_FilesystemView( '/' . $params['uid'] );

View File

@ -57,6 +57,7 @@ class Keymanager {
return $view->file_get_contents( '/public-keys/' . '/' . $userId . '.public.key' ); return $view->file_get_contents( '/public-keys/' . '/' . $userId . '.public.key' );
\OC_FileProxy::$enabled = true; \OC_FileProxy::$enabled = true;
} }
/** /**

View File

@ -131,32 +131,50 @@ class Proxy extends \OC_FileProxy {
// Encrypt data // Encrypt data
$encData = Crypt::symmetricEncryptFileContent( $data, $plainKey ); $encData = Crypt::symmetricEncryptFileContent( $data, $plainKey );
// Check if the keyfile needs to be shared // Check if key recovery is enabled
if ( $userIds = \OCP\Share::getUsersSharingFile( $filePath, true ) ) { $recoveryEnabled = $util->recoveryEnabled();
$publicKeys = Keymanager::getPublicKeys( $rootView, $userIds );
\OC_FileProxy::$enabled = false;
// Encrypt plain keyfile to multiple sharefiles
$multiEncrypted = Crypt::multiKeyEncrypt( $plainKey, $publicKeys );
// Save sharekeys to user folders
// TODO: openssl_seal generates new shareKeys (envelope keys) each time data is encrypted, but will data still be decryptable using old shareKeys? If so we don't need to replace the old shareKeys here, we only need to set the new ones
Keymanager::setShareKeys( $rootView, $filePath, $multiEncrypted['keys'] );
// Set encrypted keyfile as common varname
$encKey = $multiEncrypted['encrypted'];
} else { // Make sure that a share key is generated for the owner too
$userIds = array( $userId );
$publicKey = Keymanager::getPublicKey( $rootView, $userId ); if ( \OCP\Share::isEnabled() ) {
// Encrypt plain data to a single user // Find out who, if anyone, is sharing the file
$encKey = Crypt::keyEncrypt( $plainKey, $publicKey ); $shareUids = \OCP\Share::getUsersSharingFile( $filePath, true );
$userIds = array_merge( $userIds, $shareUids );
} }
// If recovery is enabled, add the
// Admin UID to list of users to share to
if ( $recoveryEnabled ) {
// FIXME: Create a separate admin user purely for recovery, and create method in util for fetching this id from DB?
$adminUid = 'recoveryAdmin';
$userIds[] = $adminUid;
}
// Remove duplicate UIDs
$uniqueUserIds = array_unique ( $userIds );
// Fetch public keys for all users who will share the file
$publicKeys = Keymanager::getPublicKeys( $rootView, $uniqueUserIds );
\OC_FileProxy::$enabled = false;
// Encrypt plain keyfile to multiple sharefiles
$multiEncrypted = Crypt::multiKeyEncrypt( $plainKey, $publicKeys );
// Save sharekeys to user folders
// TODO: openssl_seal generates new shareKeys (envelope keys) each time data is encrypted, but will data still be decryptable using old shareKeys? If so we don't need to replace the old shareKeys here, we only need to set the new ones
Keymanager::setShareKeys( $rootView, $filePath, $multiEncrypted['keys'] );
// Set encrypted keyfile as common varname
$encKey = $multiEncrypted['data'];
// Save the key if its new // Save the key if its new
if ( ! $keyPreExists ) { if ( ! $keyPreExists ) {

View File

@ -31,7 +31,12 @@
# ---------------- # ----------------
# Re-use existing keyfiles so they don't need version control (part implemented, stream{} and util{} remain) # 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 # Make sure user knows if large files weren't encrypted
# Trashbin support
# Test
# ----
# Test that writing files works when recovery is enabled, and sharing API is disabled
# Test trashbin support
// Old Todo: // Old Todo:
@ -202,20 +207,73 @@ class Util {
} }
public function recoveryEnabled( ) { /**
* @brief Check whether pwd recovery is enabled for a given user
* @return bool
* @note If records are not being returned, check for a hidden space
* at the start of the uid in db
*/
public function recoveryEnabled() {
$sql = 'SELECT * FROM `*PREFIX*myusers` WHERE id = ?'; $sql = 'SELECT
$args = array(1); recovery
FROM
`*PREFIX*encryption`
WHERE
uid = ?';
$args = array( $this->userId );
$query = \OCP\DB::prepare($sql); $query = \OCP\DB::prepare( $sql );
$result = $query->execute($args);
$result = $query->execute( $args );
while($row = $result->fetchRow()) {
$userName = $row['username']; // Set default in case no records found
} $recoveryEnabled = 0;
while( $row = $result->fetchRow() ) {
$recoveryEnabled = $row['recovery'];
}
return $recoveryEnabled;
} }
/**
* @brief Enable / disable pwd recovery for a given user
* @param bool $enabled Whether to enable or disable recovery
* @return bool
*/
public function setRecovery( $enabled ) {
$sql = 'UPDATE
*PREFIX*encryption
SET
recovery = ?
WHERE
uid = ?';
// Ensure value is an integer
$enabled = intval( $enabled );
$args = array( $enabled, $this->userId );
$query = \OCP\DB::prepare( $sql );
if ( $query->execute( $args ) ) {
return true;
} else {
return false;
}
}
/** /**
* @brief Find all files and their encryption status within a directory * @brief Find all files and their encryption status within a directory
* @param string $directory The path of the parent directory to search * @param string $directory The path of the parent directory to search

View File

@ -164,6 +164,26 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase {
# then false will be returned. Use strict ordering? # then false will be returned. Use strict ordering?
} }
function testRecoveryEnabled() {
$util = new Encryption\Util( $this->view, $this->userId );
// Record the value so we can return it to it's original state later
$enabled = $util->recoveryEnabled();
$this->assertTrue( $util->setRecovery( 1 ) );
$this->assertEquals( 1, $util->recoveryEnabled() );
$this->assertTrue( $util->setRecovery( 0 ) );
$this->assertEquals( 0, $util->recoveryEnabled() );
// Return the setting to it's previous state
$this->assertTrue( $util->setRecovery( $enabled ) );
}
// /** // /**
// * @brief test decryption using legacy blowfish method // * @brief test decryption using legacy blowfish method