Development snapshot
Added comments Added methods
This commit is contained in:
parent
1b880f2f96
commit
2d267501a1
6 changed files with 240 additions and 136 deletions
|
@ -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 );
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
Loading…
Reference in a new issue