Development snapshot

Added comments
Added methods
This commit is contained in:
Sam Tuke 2013-02-20 19:18:00 +00:00
parent 1b880f2f96
commit 2d267501a1
6 changed files with 240 additions and 136 deletions

View file

@ -178,10 +178,34 @@ class Hooks {
$session = new Session();
$userId = \OCP\User::getUser();
$util = new Util( $view, $userId );
$path = $util->fileIdToPath( $params['itemSource'] );
$path = Util::getFilePath( $params['itemSource'] );
return Crypt::updateKeyfile( $view, $session, $path );
$usersSharing = \OCP\Share::getUsersSharingFile( $path, true );
$allPaths = $util->getPaths( $path );
$failed = array();
foreach ( $allPaths as $path ) {
if ( ! $util->setSharedFileKeyfiles( $session, $usersSharing, $path ) ) {
$failed[] = $path;
}
}
// If no attempts to set keyfiles failed
if ( empty( $failed ) ) {
return true;
} else {
return false;
}
}
@ -190,11 +214,13 @@ class Hooks {
*/
public static function postUnshare( $params ) {
$view = new \OC_FilesystemView( '/' );
$session = new Session();
$path = Util::getFilePath( $params['itemSource'] );
return Crypt::updateKeyfile( $view, $session, $path );
// $view = new \OC_FilesystemView( '/' );
// $session = new Session();
// $userId = \OCP\User::getUser();
// $util = new Util( $view, $userId );
// $path = $util->fileIdToPath( $params['itemSource'] );
//
// return Crypt::updateKeyfile( $view, $util, $session, $userId, $path );
}
@ -203,11 +229,13 @@ class Hooks {
*/
public static function postUnshareAll( $params ) {
$view = new \OC_FilesystemView( '/' );
$session = new Session();
$path = Util::getFilePath( $params['itemSource'] );
return Crypt::updateKeyfile( $view, $session, $path );
// $view = new \OC_FilesystemView( '/' );
// $session = new Session();
// $userId = \OCP\User::getUser();
// $util = new Util( $view, $userId );
// $path = $util->fileIdToPath( $params['itemSource'] );
//
// return Crypt::updateKeyfile( $view, $util, $session, $userId, $path );
}

View file

@ -744,106 +744,4 @@ class Crypt {
}
/**
* @brief Encrypt keyfile to multiple users
* @param array $users list of users which should be able to access the file
* @param string $filePath path of the file to be shared
*/
private static function encKeyfileToMultipleUsers( \OC_FilesystemView $view, Util $util, Session $session, $userId, array $users, $filePath ) {
// Make sure users are capable of sharing
$filteredUids = $util->filterShareReadyUsers( $users );
// Get public keys for each user, ready for generating sharekeys
$userPubKeys = Keymanager::getPublicKeys( $view, $filteredUids ); // TODO: check this includes the owner's public key
\OC_FileProxy::$enabled = false;
// Get the current users's private key for decrypting existing keyfile
$privateKey = $session->getPrivateKey();
// We need to get a decrypted key for the file
// Determine how to decrypt the keyfile by checking if current user is owner
if ( $userId == \OC\Files\Filesystem::getOwner( $filePath ) ) {
// If current user is owner, decrypt without using sharekey
} else {
// Current user is resharing a file they don't own
// Decrypt keyfile using sharekey
}
// get the existing keyfile
$encKeyfile = Keymanager::getFileKey( $view, $owner, $filePath );
// decrypt the existing keyfile
$plainKeyfile = Crypt::keyDecrypt( $encKeyfile, $privateKey );
trigger_error("PUBKEYS = ". var_export($userPubKeys, 1));
// re-enc keyfile to sharekeys
$shareKeys = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys );
// save sharekeys
if ( ! Keymanager::setShareKeys( $view, $filePath, $shareKeys['keys'] ) ) {
trigger_error( "SET Share keys failed" );
}
// Delete existing keyfile
// Do this last to ensure file is recoverable in case of error
// Keymanager::deleteFileKey( $view, $userId, $params['fileTarget'] );
\OC_FileProxy::$enabled = true;
return true;
}
/**
* @brief update keyfile encryption for given path and all sub folders/files
* @param path which needs to be updated
* @return bool success
*/
public static function updateKeyfile( \OC_FilesystemView $view, Util $util, Session $session, $path ) {
// Make path include 'files' dir for OC_FSV operations
$fPath = 'files' . $path;
$result = true;
if ( ! $view->is_dir( $fPath ) ) {
$shares = \OCP\Share::getUsersSharingFile( $path, true );
$result = self::encKeyfileToMultipleUsers( $view, $util, $session, $shares, $path );
} else {
$content = $view->getDirectoryContent( $fPath );
foreach ( $content as $c ) {
$path = substr($c['path'], 5);
if ( $view->is_dir( $fPath ) ) {
$result &= self::updateKeyfile( $path );
} else {
$shares = \OCP\Share::getUsersSharingFile( $path, true );
$result &= self::encKeyfileToMultipleUsers( $view, $util, $session, $shares, $path );
}
}
}
return $result;
}
}

View file

@ -305,8 +305,8 @@ class Keymanager {
/**
* @brief retrieve shareKey for an encrypted file
* @param \OC_FilesystemView $view
* @param $userId
* @param $filePath
* @param string $userId
* @param string $filePath
* @internal param \OCA\Encryption\file $string name
* @return string file key or false
* @note The sharekey returned is encrypted. Decryption

View file

@ -169,6 +169,24 @@ class Proxy extends \OC_FileProxy {
* @param string $data Data that has been read from file
*/
public function postFile_get_contents( $path, $data ) {
// FIXME: $path for shared files is just /uid/files/Shared/filepath
$userId = \OCP\USER::getUser();
$view = new \OC_FilesystemView( '/' );
$util = new Util( $view, $userId );
if ( $util->isSharedPath( $path ) ) {
$relPath = $util->stripSharedFilePath( $path );
} else {
$relPath = $util->stripUserFilesPath( $path );
}
// TODO check for existing key file and reuse it if possible to avoid problems with versioning etc.
// Disable encryption proxy to prevent recursive calls
\OC_FileProxy::$enabled = false;
@ -178,27 +196,34 @@ class Proxy extends \OC_FileProxy {
Crypt::mode() == 'server'
&& Crypt::isCatfile( $data )
) {
$view = new \OC_FilesystemView( '/' );
// TODO use get owner to find correct location of key files for shared files
$userId = \OCP\USER::getUser();
$session = new Session();
$util = new Util( $view, $userId );
$filePath = $util->stripUserFilesPath( $path );
$privateKey = $session->getPrivateKey( $userId );
// Get the file owner so we can retrieve its keyfile
$fileOwner = \OC\Files\Filesystem::getOwner( $relPath ); //NOTE: This might be false! make sure the path passed to it is right
$fileOwner = 'admin'; // FIXME: Manually set the correct UID for now
// Get the encrypted keyfile
$encKeyfile = Keymanager::getFileKey( $view, $userId, $filePath );
$encKeyfile = Keymanager::getFileKey( $view, $fileOwner, $relPath );
trigger_error("\$encKeyfile = ". var_export($encKeyfile, 1));
// Attempt to fetch the user's shareKey
$shareKey = Keymanager::getShareKey( $view, $userId, $relPath );
trigger_error("\$shareKey = ".var_export($shareKey, 1));
// Check if key is shared or not
if ( \OCP\Share::isSharedFile( $filePath ) ) {
// If key is shared, fetch the user's shareKey
$shareKey = Keymanager::getShareKey( $view, $userId, $filePath );
if ( $shareKey ) {
\OC_FileProxy::$enabled = false;
// Decrypt keyfile with shareKey
$plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey );
trigger_error("PROXY plainkeyfile = ". var_export($plainKeyfile, 1));
} else {

View file

@ -224,7 +224,7 @@ class Util {
* @note $directory needs to be a path relative to OC data dir. e.g.
* /admin/files NOT /backup OR /home/www/oc/data/admin/files
*/
public function findFiles( $directory ) {
public function findEncFiles( $directory ) {
// Disable proxy - we don't want files to be decrypted before
// we handle them
@ -251,7 +251,7 @@ class Util {
// its contents
if ( $this->view->is_dir( $filePath ) ) {
$this->findFiles( $filePath );
$this->findEncFiles( $filePath );
// If the path is a file, determine
// its encryption status
@ -348,6 +348,38 @@ class Util {
}
/**
* @brief Format a shared path to be relative to the /user/files/ directory
* @note Expects a path like /uid/files/Shared/filepath
*/
public function stripSharedFilePath( $path ) {
$trimmed = ltrim( $path, '/' );
$split = explode( '/', $trimmed );
$sliced = array_slice( $split, 3 );
$relPath = implode( '/', $sliced );
return $relPath;
}
public function isSharedPath( $path ) {
$trimmed = ltrim( $path, '/' );
$split = explode( '/', $trimmed );
if ( $split[2] == "Shared" ) {
return true;
} else {
return false;
}
}
/**
* @brief Encrypt all files in a directory
* @param string $publicKey the public key to encrypt files with
@ -356,7 +388,7 @@ class Util {
*/
public function encryptAll( $publicKey, $dirPath, $legacyPassphrase = null, $newPassphrase = null ) {
if ( $found = $this->findFiles( $dirPath ) ) {
if ( $found = $this->findEncFiles( $dirPath ) ) {
// Disable proxy to prevent file being encrypted twice
\OC_FileProxy::$enabled = false;
@ -478,13 +510,18 @@ class Util {
* @param $fileId id of the file
* @return path of the file
*/
public static function getFilePath($fileId) {
$query = \OC_DB::prepare('SELECT `path`'
public static function fileIdToPath( $fileId ) {
$query = \OC_DB::prepare( 'SELECT `path`'
.' FROM `*PREFIX*filecache`'
.' WHERE `fileid` = ?');
$result = $query->execute(array($fileId));
.' WHERE `fileid` = ?' );
$result = $query->execute( array( $fileId ) );
$row = $result->fetchRow();
return substr($row['path'], 5);
return substr( $row['path'], 5 );
}
/**
@ -527,5 +564,121 @@ class Util {
return $userIds;
}
/**
* @brief Expand given path to all sub files & folders
* @param Session $session
* @param string $path path which needs to be updated
* @return bool outcome of attempt to set keyfiles
*/
public function getPaths( $path ) {
// Default return value is success
$result = true;
// Make path include 'files' dir for OC_FSV operations
$fPath = 'files' . $path;
// If we're handling a single file
if ( ! $this->view->is_dir( $fPath ) ) {
$pathsArray[] = $path;
// If we're handling a folder (recursively)
} else {
$subFiles = $this->view->getDirectoryContent( $fPath );
foreach ( $subFiles as $file ) {
$filePath = substr( $file['path'], 5 );
// If this is a nested file
if ( ! $this->view->is_dir( $fPath ) ) {
// Add the file path to array
$pathsArray[] = $path;
} else {
// If this is a nested folder
$dirPaths = $this->getPaths( $filePath );
// Add all subfiles & folders to the array
$pathsArray = array_merge( $dirPaths, $pathsArray );
}
}
}
return $pathsArray;
}
/**
* @brief Encrypt keyfile to multiple users
* @param array $users list of users which should be able to access the file
* @param string $filePath path of the file to be shared
*/
public function setSharedFileKeyfiles( Session $session, array $users, $filePath ) {
// Make sure users are capable of sharing
$filteredUids = $this->filterShareReadyUsers( $users );
// Get public keys for each user, ready for generating sharekeys
$userPubKeys = Keymanager::getPublicKeys( $this->view, $filteredUids ); // TODO: check this includes the owner's public key
\OC_FileProxy::$enabled = false;
// Get the current users's private key for decrypting existing keyfile
$privateKey = $session->getPrivateKey();
$fileOwner = \OC\Files\Filesystem::getOwner( $filePath );
// Get the encrypted keyfile
// NOTE: the keyfile format depends on how it was encrypted! At
// this stage we don't know how it was encrypted
$encKeyfile = Keymanager::getFileKey( $this->view, $this->userId, $filePath );
// We need to decrypt the keyfile
// Has the file been shared yet?
if (
$this->userId == $fileOwner
&& ! Keymanager::getShareKey( $this->view, $this->userId, $filePath ) // NOTE: we can't use isShared() here because it's a post share hook so it always returns true
) {
// The file has no shareKey, and its keyfile must be
// decrypted conventionally
$plainKeyfile = Crypt::keyDecrypt( $encKeyfile, $privateKey );
} else {
// The file has a shareKey and must use it for decryption
$shareKey = Keymanager::getShareKey( $this->view, $this->userId, $filePath );
$plainKeyfile = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey );
}
// Re-enc keyfile to (additional) sharekeys
$newShareKeys = Crypt::multiKeyEncrypt( $plainKeyfile, $userPubKeys );
// Save new sharekeys to all necessary user folders
if ( ! Keymanager::setShareKeys( $this->view, $filePath, $newShareKeys['keys'] ) ) {
trigger_error( "SET Share keys failed" );
}
// Delete existing keyfile
// Do this last to ensure file is recoverable in case of error
// Keymanager::deleteFileKey( $this->view, $this->userId, $params['fileTarget'] );
\OC_FileProxy::$enabled = true;
return true;
}
}

View file

@ -150,13 +150,13 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase {
}
function testFindFiles() {
function testFindEncFiles() {
// $this->view->chroot( "/data/{$this->userId}/files" );
$util = new Encryption\Util( $this->view, $this->userId );
$files = $util->findFiles( '/', 'encrypted' );
$files = $util->findEncFiles( '/', 'encrypted' );
var_dump( $files );