reformat code added and changed phpdoc
This commit is contained in:
parent
b1d0e8f40b
commit
3b850a2524
File diff suppressed because it is too large
Load Diff
|
@ -23,76 +23,82 @@
|
||||||
|
|
||||||
namespace OCA\Encryption;
|
namespace OCA\Encryption;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Class to manage registration of hooks an various helper methods
|
* @brief Class to manage registration of hooks an various helper methods
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Class Helper
|
* Class Helper
|
||||||
* @package OCA\Encryption
|
* @package OCA\Encryption
|
||||||
*/
|
*/
|
||||||
class Helper {
|
class Helper
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief register share related hooks
|
* @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', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared');
|
||||||
\OCP\Util::connectHook( 'OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared' );
|
\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', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief register user related hooks
|
* @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_login', 'OCA\Encryption\Hooks', 'login');
|
||||||
\OCP\Util::connectHook( 'OC_User', 'post_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_createUser', 'OCA\Encryption\Hooks', 'postCreateUser');
|
||||||
\OCP\Util::connectHook( 'OC_User', 'post_deleteUser', 'OCA\Encryption\Hooks', 'postDeleteUser' );
|
\OCP\Util::connectHook('OC_User', 'post_deleteUser', 'OCA\Encryption\Hooks', 'postDeleteUser');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief register webdav related hooks
|
* @brief register webdav related hooks
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public static function registerWebdavHooks() {
|
public static function registerWebdavHooks()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief register filesystem related hooks
|
* @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');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief setup user for files_encryption
|
* @brief setup user for files_encryption
|
||||||
*
|
*
|
||||||
* @param Util $util
|
* @param Util $util
|
||||||
* @param string $password
|
* @param string $password
|
||||||
* @return bool
|
* @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() ) {
|
// Check files_encryption infrastructure is ready for action
|
||||||
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief enable recovery
|
* @brief enable recovery
|
||||||
|
@ -103,7 +109,8 @@ class Helper {
|
||||||
* @internal param string $password
|
* @internal param string $password
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function adminEnableRecovery($recoveryKeyId, $recoveryPassword) {
|
public static function adminEnableRecovery($recoveryKeyId, $recoveryPassword)
|
||||||
|
{
|
||||||
$view = new \OC\Files\View('/');
|
$view = new \OC\Files\View('/');
|
||||||
|
|
||||||
if ($recoveryKeyId === null) {
|
if ($recoveryKeyId === null) {
|
||||||
|
@ -139,7 +146,7 @@ class Helper {
|
||||||
$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.
|
// create control file which let us check later on if the entered password was correct.
|
||||||
$encryptedControlData = \OCA\Encryption\Crypt::keyEncrypt("ownCloud", $keypair['publicKey']);
|
$encryptedControlData = \OCA\Encryption\Crypt::keyEncrypt("ownCloud", $keypair['publicKey']);
|
||||||
if (!$view->is_dir('/control-file')) {
|
if (!$view->is_dir('/control-file')) {
|
||||||
$view->mkdir('/control-file');
|
$view->mkdir('/control-file');
|
||||||
}
|
}
|
||||||
|
@ -170,7 +177,8 @@ class Helper {
|
||||||
* @param $recoveryPassword
|
* @param $recoveryPassword
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function adminDisableRecovery($recoveryPassword) {
|
public static function adminDisableRecovery($recoveryPassword)
|
||||||
|
{
|
||||||
$util = new Util(new \OC_FilesystemView('/'), \OCP\User::getUser());
|
$util = new Util(new \OC_FilesystemView('/'), \OCP\User::getUser());
|
||||||
$return = $util->checkRecoveryPassword($recoveryPassword);
|
$return = $util->checkRecoveryPassword($recoveryPassword);
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,8 @@ namespace OCA\Encryption;
|
||||||
* @brief Class to manage storage and retrieval of encryption keys
|
* @brief Class to manage storage and retrieval of encryption keys
|
||||||
* @note Where a method requires a view object, it's root must be '/'
|
* @note Where a method requires a view object, it's root must be '/'
|
||||||
*/
|
*/
|
||||||
class Keymanager {
|
class Keymanager
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief retrieve the ENCRYPTED private key from a user
|
* @brief retrieve the ENCRYPTED private key from a user
|
||||||
|
@ -37,17 +38,18 @@ class Keymanager {
|
||||||
* @return string private key or false (hopefully)
|
* @return string private key or false (hopefully)
|
||||||
* @note the key returned by this method must be decrypted before use
|
* @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;
|
$path = '/' . $user . '/' . 'files_encryption' . '/' . $user . '.private.key';
|
||||||
\OC_FileProxy::$enabled = false;
|
|
||||||
|
|
||||||
$key = $view->file_get_contents( $path );
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
|
$key = $view->file_get_contents($path);
|
||||||
|
|
||||||
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
|
||||||
|
|
||||||
return $key;
|
return $key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,104 +59,111 @@ class Keymanager {
|
||||||
* @param $userId
|
* @param $userId
|
||||||
* @return string public key or false
|
* @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;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\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;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieve a user's public and private key
|
* @brief Retrieve a user's public and private key
|
||||||
* @param \OC_FilesystemView $view
|
* @param \OC_FilesystemView $view
|
||||||
* @param $userId
|
* @param $userId
|
||||||
* @return array keys: privateKey, publicKey
|
* @return array keys: privateKey, publicKey
|
||||||
*/
|
*/
|
||||||
public static function getUserKeys( \OC_FilesystemView $view, $userId ) {
|
public static function getUserKeys(\OC_FilesystemView $view, $userId)
|
||||||
|
{
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'publicKey' => self::getPublicKey( $view, $userId )
|
'publicKey' => self::getPublicKey($view, $userId)
|
||||||
, 'privateKey' => self::getPrivateKey( $view, $userId )
|
, 'privateKey' => self::getPrivateKey($view, $userId)
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieve public keys for given users
|
* @brief Retrieve public keys for given users
|
||||||
* @param \OC_FilesystemView $view
|
* @param \OC_FilesystemView $view
|
||||||
* @param array $userIds
|
* @param array $userIds
|
||||||
* @return array of public keys for the specified users
|
* @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();
|
$keys = array();
|
||||||
|
|
||||||
foreach ( $userIds as $userId ) {
|
foreach ($userIds as $userId) {
|
||||||
|
|
||||||
$keys[$userId] = self::getPublicKey( $view, $userId );
|
$keys[$userId] = self::getPublicKey($view, $userId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $keys;
|
return $keys;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief store file encryption key
|
* @brief store file encryption key
|
||||||
*
|
*
|
||||||
|
* @param \OC_FilesystemView $view
|
||||||
* @param string $path relative path of the file, including filename
|
* @param string $path relative path of the file, including filename
|
||||||
* @param string $key
|
* @param $userId
|
||||||
|
* @param $catfile
|
||||||
|
* @internal param string $key
|
||||||
* @return bool true/false
|
* @return bool true/false
|
||||||
* @note The keyfile is not encrypted here. Client code must
|
* @note The keyfile is not encrypted here. Client code must
|
||||||
* asymmetrically encrypt the keyfile before passing it to this method
|
* 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;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
//here we need the currently logged in user, while userId can be a different user
|
//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/keyfiles';
|
$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
|
// create all parent folders
|
||||||
$info = pathinfo( $basePath . '/' . $targetPath );
|
$info = pathinfo($basePath . '/' . $targetPath);
|
||||||
$keyfileFolderName = $view->getLocalFolder( $info['dirname'] );
|
$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
|
// 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 {
|
} else {
|
||||||
|
|
||||||
$result = $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile );
|
$result = $view->file_put_contents($basePath . '/' . $targetPath . '.key', $catfile);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,15 +172,16 @@ class Keymanager {
|
||||||
* @return string File path without .part extension
|
* @return string File path without .part extension
|
||||||
* @note this is needed for reusing keys
|
* @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;
|
$newLength = strlen($path) - 5;
|
||||||
$fPath = substr($path, 0, $newLength);
|
$fPath = substr($path, 0, $newLength);
|
||||||
|
|
||||||
return $fPath;
|
return $fPath;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
return $path;
|
return $path;
|
||||||
|
@ -185,19 +195,21 @@ class Keymanager {
|
||||||
* @param string $path Path that may identify a .part file
|
* @param string $path Path that may identify a .part file
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function isPartialFilePath( $path ) {
|
public static function isPartialFilePath($path)
|
||||||
|
{
|
||||||
if ( preg_match('/\.part$/', $path ) ) {
|
|
||||||
|
if (preg_match('/\.part$/', $path)) {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief retrieve keyfile for an encrypted file
|
* @brief retrieve keyfile for an encrypted file
|
||||||
* @param \OC_FilesystemView $view
|
* @param \OC_FilesystemView $view
|
||||||
|
@ -208,227 +220,239 @@ class Keymanager {
|
||||||
* @note The keyfile returned is asymmetrically encrypted. Decryption
|
* @note The keyfile returned is asymmetrically encrypted. Decryption
|
||||||
* of the keyfile must be performed by client code
|
* 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
|
// 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;
|
return $result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$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);
|
||||||
$filePath_f = ltrim( $filename, '/' );
|
$filePath_f = ltrim($filename, '/');
|
||||||
|
|
||||||
$keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key';
|
$keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key';
|
||||||
|
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
if ( $view->file_exists( $keyfilePath ) ) {
|
|
||||||
|
|
||||||
$result = $view->file_get_contents( $keyfilePath );
|
if ($view->file_exists($keyfilePath)) {
|
||||||
|
|
||||||
|
$result = $view->file_get_contents($keyfilePath);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
$result = false;
|
$result = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Delete a keyfile
|
* @brief Delete a keyfile
|
||||||
*
|
*
|
||||||
* @param OC_FilesystemView $view
|
* @param \OC_FilesystemView $view
|
||||||
* @param string $userId username
|
* @param string $userId username
|
||||||
* @param string $path path of the file the key belongs to
|
* @param string $path path of the file the key belongs to
|
||||||
* @return bool Outcome of unlink operation
|
* @return bool Outcome of unlink operation
|
||||||
* @note $path must be relative to data/user/files. e.g. mydoc.txt NOT
|
* @note $path must be relative to data/user/files. e.g. mydoc.txt NOT
|
||||||
* /data/admin/files/mydoc.txt
|
* /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, '/' );
|
|
||||||
$keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed;
|
$trimmed = ltrim($path, '/');
|
||||||
|
$keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed;
|
||||||
|
|
||||||
$result = false;
|
$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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief store private key from the user
|
* @brief store private key from the user
|
||||||
* @param string key
|
* @param string $key
|
||||||
* @return bool
|
* @return bool
|
||||||
* @note Encryption of the private key must be performed by client code
|
* @note Encryption of the private key must be performed by client code
|
||||||
* as no encryption takes place here
|
* as no encryption takes place here
|
||||||
*/
|
*/
|
||||||
public static function setPrivateKey( $key ) {
|
public static function setPrivateKey($key)
|
||||||
|
{
|
||||||
|
|
||||||
$user = \OCP\User::getUser();
|
$user = \OCP\User::getUser();
|
||||||
|
|
||||||
$view = new \OC_FilesystemView( '/' . $user . '/files_encryption' );
|
$view = new \OC_FilesystemView('/' . $user . '/files_encryption');
|
||||||
|
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\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;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief store private keys from the user
|
* @brief store private keys from the user
|
||||||
*
|
*
|
||||||
* @param string privatekey
|
* @param string $privatekey
|
||||||
* @param string publickey
|
* @param string $publickey
|
||||||
* @return bool true/false
|
* @return bool true/false
|
||||||
*/
|
*/
|
||||||
public static function setUserKeys($privatekey, $publickey) {
|
public static function setUserKeys($privatekey, $publickey)
|
||||||
|
{
|
||||||
return ( self::setPrivateKey( $privatekey ) && self::setPublicKey( $publickey ) );
|
|
||||||
|
return (self::setPrivateKey($privatekey) && self::setPublicKey($publickey));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief store public key of the user
|
* @brief store public key of the user
|
||||||
*
|
*
|
||||||
* @param string key
|
* @param string $key
|
||||||
* @return bool true/false
|
* @return bool true/false
|
||||||
*/
|
*/
|
||||||
public static function setPublicKey( $key ) {
|
public static function setPublicKey($key)
|
||||||
|
{
|
||||||
$view = new \OC_FilesystemView( '/public-keys' );
|
|
||||||
|
$view = new \OC_FilesystemView('/public-keys');
|
||||||
|
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
if ( !$view->file_exists( '' ) ) $view->mkdir( '' );
|
if (!$view->file_exists('')) $view->mkdir('');
|
||||||
|
|
||||||
$result = $view->file_put_contents( \OCP\User::getUser() . '.public.key', $key );
|
$result = $view->file_put_contents(\OCP\User::getUser() . '.public.key', $key);
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief store share key
|
* @brief store share key
|
||||||
*
|
*
|
||||||
|
* @param \OC_FilesystemView $view
|
||||||
* @param string $path relative path of the file, including filename
|
* @param string $path relative path of the file, including filename
|
||||||
* @param string $key
|
* @param $userId
|
||||||
* @param null $view
|
* @param $shareKey
|
||||||
* @param string $dbClassName
|
* @internal param string $key
|
||||||
|
* @internal param string $dbClassName
|
||||||
* @return bool true/false
|
* @return bool true/false
|
||||||
* @note The keyfile is not encrypted here. Client code must
|
* @note The keyfile is not encrypted here. Client code must
|
||||||
* asymmetrically encrypt the keyfile before passing it to this method
|
* 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
|
// 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';
|
$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
|
// 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 {
|
} else {
|
||||||
|
|
||||||
$writePath = $basePath . '/' . $shareKeyPath . '.' . $userId . '.shareKey';
|
$writePath = $basePath . '/' . $shareKeyPath . '.' . $userId . '.shareKey';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
$result = $view->file_put_contents( $writePath, $shareKey );
|
$result = $view->file_put_contents($writePath, $shareKey);
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
is_int( $result )
|
is_int($result)
|
||||||
&& $result > 0
|
&& $result > 0
|
||||||
) {
|
) {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief store multiple share keys for a single file
|
* @brief store multiple share keys for a single file
|
||||||
|
* @param \OC_FilesystemView $view
|
||||||
|
* @param $path
|
||||||
|
* @param array $shareKeys
|
||||||
* @return bool
|
* @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:
|
// $shareKeys must be an array with the following format:
|
||||||
// [userId] => [encrypted key]
|
// [userId] => [encrypted key]
|
||||||
|
|
||||||
$result = true;
|
$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
|
// If any of the keys are not set, flag false
|
||||||
$result = false;
|
$result = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns false if any of the keys weren't set
|
// Returns false if any of the keys weren't set
|
||||||
return $result;
|
return $result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief retrieve shareKey for an encrypted file
|
* @brief retrieve shareKey for an encrypted file
|
||||||
* @param \OC_FilesystemView $view
|
* @param \OC_FilesystemView $view
|
||||||
|
@ -439,59 +463,61 @@ class Keymanager {
|
||||||
* @note The sharekey returned is encrypted. Decryption
|
* @note The sharekey returned is encrypted. Decryption
|
||||||
* of the keyfile must be performed by client code
|
* 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
|
// 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;
|
return $result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
//here we need the currently logged in user, while userId can be a different user
|
//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 . '.' . $userId . '.shareKey');
|
$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 {
|
} else {
|
||||||
|
|
||||||
$result = false;
|
$result = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief delete all share keys of a given file
|
* @brief delete all share keys of a given file
|
||||||
* @param \OC_FilesystemView $view
|
* @param \OC_FilesystemView $view
|
||||||
* @param type $userId owner of the file
|
* @param string $userId owner of the file
|
||||||
* @param type $filePath path to the file, relative to the owners file dir
|
* @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 {
|
} else {
|
||||||
$localKeyPath = $view->getLocalFile($userId.'/files_encryption/share-keys/'.$filePath);
|
$localKeyPath = $view->getLocalFile($userId . '/files_encryption/share-keys/' . $filePath);
|
||||||
$matches = glob(preg_quote($localKeyPath).'*.shareKey');
|
$matches = glob(preg_quote($localKeyPath) . '*.shareKey');
|
||||||
foreach ($matches as $ma) {
|
foreach ($matches as $ma) {
|
||||||
unlink($ma);
|
unlink($ma);
|
||||||
}
|
}
|
||||||
|
@ -501,13 +527,14 @@ class Keymanager {
|
||||||
/**
|
/**
|
||||||
* @brief Delete a single user's shareKey for a single file
|
* @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;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
//here we need the currently logged in user, while userId can be a different user
|
//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);
|
||||||
|
|
||||||
|
@ -515,7 +542,7 @@ class Keymanager {
|
||||||
|
|
||||||
$result = false;
|
$result = false;
|
||||||
|
|
||||||
if ( $view->is_dir($shareKeyPath) ) {
|
if ($view->is_dir($shareKeyPath)) {
|
||||||
|
|
||||||
$localPath = \OC_Filesystem::normalizePath($view->getLocalFolder($shareKeyPath));
|
$localPath = \OC_Filesystem::normalizePath($view->getLocalFolder($shareKeyPath));
|
||||||
$result = self::recursiveDelShareKeys($localPath, $userIds);
|
$result = self::recursiveDelShareKeys($localPath, $userIds);
|
||||||
|
@ -523,40 +550,42 @@ class Keymanager {
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
foreach ($userIds as $userId) {
|
foreach ($userIds as $userId) {
|
||||||
$view->unlink($shareKeyPath.'.'.$userId.'.shareKey');
|
$view->unlink($shareKeyPath . '.' . $userId . '.shareKey');
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = true;
|
$result = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! $result ) {
|
if (!$result) {
|
||||||
|
|
||||||
\OC_Log::write( 'Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath, \OC_Log::ERROR );
|
\OC_Log::write('Encryption library', 'Could not delete shareKey; does not exist: "' . $shareKeyPath, \OC_Log::ERROR);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief recursively delete share keys from given users
|
* @brief recursively delete share keys from given users
|
||||||
*
|
*
|
||||||
* @param type $dir directory
|
* @param string $dir directory
|
||||||
* @param type $userIds user ids for which the share keys should be deleted
|
* @param array $userIds user ids for which the share keys should be deleted
|
||||||
*/
|
*/
|
||||||
private static function recursiveDelShareKeys($dir, $userIds) {
|
private static function recursiveDelShareKeys($dir, $userIds)
|
||||||
|
{
|
||||||
foreach ($userIds as $userId) {
|
foreach ($userIds as $userId) {
|
||||||
$completePath = $dir.'/.*'.'.'.$userId.'.shareKey';
|
$completePath = $dir . '/.*' . '.' . $userId . '.shareKey';
|
||||||
$matches = glob(preg_quote($dir).'/*'.preg_quote('.'.$userId.'.shareKey'));
|
$matches = glob(preg_quote($dir) . '/*' . preg_quote('.' . $userId . '.shareKey'));
|
||||||
}
|
}
|
||||||
foreach ($matches as $ma) {
|
/** @var $matches array */
|
||||||
|
foreach ($matches as $ma) {
|
||||||
unlink($ma);
|
unlink($ma);
|
||||||
}
|
}
|
||||||
$subdirs = $directories = glob(preg_quote($dir) . '/*' , GLOB_ONLYDIR);
|
$subdirs = $directories = glob(preg_quote($dir) . '/*', GLOB_ONLYDIR);
|
||||||
foreach ( $subdirs as $subdir ) {
|
foreach ($subdirs as $subdir) {
|
||||||
self::recursiveDelShareKeys($subdir, $userIds);
|
self::recursiveDelShareKeys($subdir, $userIds);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -565,16 +594,17 @@ class Keymanager {
|
||||||
/**
|
/**
|
||||||
* @brief Make preparations to vars and filesystem for saving a keyfile
|
* @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 the file resides within a subdirectory, create it
|
||||||
if (
|
if (
|
||||||
isset( $path_parts['dirname'] )
|
isset($path_parts['dirname'])
|
||||||
&& ! $view->file_exists( $basePath . '/' . $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 = '';
|
$dir = '';
|
||||||
|
@ -585,41 +615,26 @@ class Keymanager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $targetPath;
|
return $targetPath;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief change password of private encryption key
|
|
||||||
*
|
|
||||||
* @param string $oldpasswd old password
|
|
||||||
* @param string $newpasswd new password
|
|
||||||
* @return bool true/false
|
|
||||||
*/
|
|
||||||
public static function changePasswd($oldpasswd, $newpasswd) {
|
|
||||||
|
|
||||||
if ( \OCP\User::checkPassword(\OCP\User::getUser(), $newpasswd) ) {
|
|
||||||
return Crypt::changekeypasscode($oldpasswd, $newpasswd);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Fetch the legacy encryption key from user files
|
* @brief Fetch the legacy encryption key from user files
|
||||||
* @param string $login used to locate the legacy key
|
* @internal param string $login used to locate the legacy key
|
||||||
* @param string $passphrase used to decrypt the legacy key
|
* @internal param string $passphrase used to decrypt the legacy key
|
||||||
* @return true / false
|
* @return boolean
|
||||||
*
|
*
|
||||||
* if the key is left out, the default handeler will be used
|
* if the key is left out, the default handeler will be used
|
||||||
*/
|
*/
|
||||||
public function getLegacyKey() {
|
public function getLegacyKey()
|
||||||
|
{
|
||||||
|
|
||||||
$user = \OCP\User::getUser();
|
$user = \OCP\User::getUser();
|
||||||
$view = new \OC_FilesystemView( '/' . $user );
|
$view = new \OC_FilesystemView('/' . $user);
|
||||||
return $view->file_get_contents( 'encryption.key' );
|
return $view->file_get_contents('encryption.key');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,41 +1,46 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ownCloud
|
* ownCloud
|
||||||
*
|
*
|
||||||
* @author Sam Tuke, Robin Appelman
|
* @author Sam Tuke, Robin Appelman
|
||||||
* @copyright 2012 Sam Tuke samtuke@owncloud.com, Robin Appelman
|
* @copyright 2012 Sam Tuke samtuke@owncloud.com, Robin Appelman
|
||||||
* icewind1991@gmail.com
|
* icewind1991@gmail.com
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
* version 3 of the License, or any later version.
|
* version 3 of the License, or any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public
|
* You should have received a copy of the GNU Affero General Public
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Encryption proxy which handles filesystem operations before and after
|
* @brief Encryption proxy which handles filesystem operations before and after
|
||||||
* execution and encrypts, and handles keyfiles accordingly. Used for
|
* execution and encrypts, and handles keyfiles accordingly. Used for
|
||||||
* webui.
|
* webui.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace OCA\Encryption;
|
namespace OCA\Encryption;
|
||||||
|
|
||||||
class Proxy extends \OC_FileProxy {
|
/**
|
||||||
|
* Class Proxy
|
||||||
|
* @package OCA\Encryption
|
||||||
|
*/
|
||||||
|
class Proxy extends \OC_FileProxy
|
||||||
|
{
|
||||||
|
|
||||||
private static $blackList = null; //mimetypes blacklisted from encryption
|
private static $blackList = null; //mimetypes blacklisted from encryption
|
||||||
|
|
||||||
private static $enableEncryption = null;
|
private static $enableEncryption = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a file requires encryption
|
* Check if a file requires encryption
|
||||||
* @param string $path
|
* @param string $path
|
||||||
|
@ -43,461 +48,481 @@ class Proxy extends \OC_FileProxy {
|
||||||
*
|
*
|
||||||
* Tests if server side encryption is enabled, and file is allowed by blacklists
|
* 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'
|
if (
|
||||||
&& Crypt::mode() == 'server'
|
\OCP\Config::getAppValue('files_encryption', 'enable_encryption', 'true') == 'true'
|
||||||
|
&& Crypt::mode() == 'server'
|
||||||
) {
|
) {
|
||||||
|
|
||||||
self::$enableEncryption = true;
|
self::$enableEncryption = true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
self::$enableEncryption = false;
|
self::$enableEncryption = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !self::$enableEncryption ) {
|
if (!self::$enableEncryption) {
|
||||||
|
|
||||||
return false;
|
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;
|
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;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function preFile_put_contents( $path, &$data ) {
|
|
||||||
|
|
||||||
if ( self::shouldEncrypt( $path ) ) {
|
/**
|
||||||
|
* @param $path
|
||||||
|
* @param $data
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function preFile_put_contents($path, &$data)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (self::shouldEncrypt($path)) {
|
||||||
|
|
||||||
// Stream put contents should have been converted to fopen
|
// Stream put contents should have been converted to fopen
|
||||||
if ( !is_resource( $data ) ) {
|
if (!is_resource($data)) {
|
||||||
|
|
||||||
$userId = \OCP\USER::getUser();
|
$userId = \OCP\USER::getUser();
|
||||||
$view = new \OC_FilesystemView( '/' );
|
$view = new \OC_FilesystemView('/');
|
||||||
$util = new Util( $view, $userId );
|
$util = new Util($view, $userId);
|
||||||
$session = new Session( $view );
|
$session = new Session($view);
|
||||||
$privateKey = $session->getPrivateKey();
|
$privateKey = $session->getPrivateKey();
|
||||||
$filePath = $util->stripUserFilesPath( $path );
|
$filePath = $util->stripUserFilesPath($path);
|
||||||
// Set the filesize for userland, before encrypting
|
// Set the filesize for userland, before encrypting
|
||||||
$size = strlen( $data );
|
$size = strlen($data);
|
||||||
|
|
||||||
// Disable encryption proxy to prevent recursive calls
|
// Disable encryption proxy to prevent recursive calls
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
// Check if there is an existing key we can reuse
|
// 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
|
// Fetch shareKey
|
||||||
$shareKey = Keymanager::getShareKey( $view, $userId, $filePath );
|
$shareKey = Keymanager::getShareKey($view, $userId, $filePath);
|
||||||
|
|
||||||
// Decrypt the keyfile
|
// Decrypt the keyfile
|
||||||
$plainKey = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey );
|
$plainKey = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Make a new key
|
// Make a new key
|
||||||
$plainKey = Crypt::generateKey();
|
$plainKey = Crypt::generateKey();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt data
|
// Encrypt data
|
||||||
$encData = Crypt::symmetricEncryptFileContent( $data, $plainKey );
|
$encData = Crypt::symmetricEncryptFileContent($data, $plainKey);
|
||||||
|
|
||||||
$sharingEnabled = \OCP\Share::isEnabled();
|
$sharingEnabled = \OCP\Share::isEnabled();
|
||||||
|
|
||||||
// if file exists try to get sharing users
|
// if file exists try to get sharing users
|
||||||
if($view->file_exists($path)) {
|
if ($view->file_exists($path)) {
|
||||||
$uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $filePath, $userId );
|
$uniqueUserIds = $util->getSharingUsersArray($sharingEnabled, $filePath, $userId);
|
||||||
} else {
|
} else {
|
||||||
$uniqueUserIds[] = $userId;
|
$uniqueUserIds[] = $userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch public keys for all users who will share the file
|
// 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
|
// Encrypt plain keyfile to multiple sharefiles
|
||||||
$multiEncrypted = Crypt::multiKeyEncrypt( $plainKey, $publicKeys );
|
$multiEncrypted = Crypt::multiKeyEncrypt($plainKey, $publicKeys);
|
||||||
|
|
||||||
// Save sharekeys to user folders
|
// Save sharekeys to user folders
|
||||||
Keymanager::setShareKeys( $view, $filePath, $multiEncrypted['keys'] );
|
Keymanager::setShareKeys($view, $filePath, $multiEncrypted['keys']);
|
||||||
|
|
||||||
// Set encrypted keyfile as common varname
|
// Set encrypted keyfile as common varname
|
||||||
$encKey = $multiEncrypted['data'];
|
$encKey = $multiEncrypted['data'];
|
||||||
|
|
||||||
// Save keyfile for newly encrypted file in parallel directory tree
|
// 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
|
// Replace plain content with encrypted content by reference
|
||||||
$data = $encData;
|
$data = $encData;
|
||||||
|
|
||||||
// Update the file cache with file info
|
// Update the file cache with file info
|
||||||
\OC\Files\Filesystem::putFileInfo( $filePath, array( 'encrypted'=>true, 'size' => strlen($size), 'unencrypted_size' => $size), '' );
|
\OC\Files\Filesystem::putFileInfo($filePath, array('encrypted' => true, 'size' => strlen($size), 'unencrypted_size' => $size), '');
|
||||||
|
|
||||||
// Re-enable proxy - our work is done
|
// Re-enable proxy - our work is done
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $path Path of file from which has been read
|
* @param string $path Path of file from which has been read
|
||||||
* @param string $data Data that has been read from file
|
* @param string $data Data that has been read from file
|
||||||
*/
|
*/
|
||||||
public function postFile_get_contents( $path, $data ) {
|
public function postFile_get_contents($path, $data)
|
||||||
|
{
|
||||||
|
|
||||||
|
// FIXME: $path for shared files is just /uid/files/Shared/filepath
|
||||||
|
|
||||||
// FIXME: $path for shared files is just /uid/files/Shared/filepath
|
|
||||||
|
|
||||||
$userId = \OCP\USER::getUser();
|
$userId = \OCP\USER::getUser();
|
||||||
$view = new \OC_FilesystemView( '/' );
|
$view = new \OC_FilesystemView('/');
|
||||||
$util = new Util( $view, $userId );
|
$util = new Util($view, $userId);
|
||||||
|
|
||||||
$relPath = $util->stripUserFilesPath( $path );
|
$relPath = $util->stripUserFilesPath($path);
|
||||||
|
|
||||||
|
|
||||||
// TODO check for existing key file and reuse it if possible to avoid problems with versioning etc.
|
// TODO check for existing key file and reuse it if possible to avoid problems with versioning etc.
|
||||||
// Disable encryption proxy to prevent recursive calls
|
// Disable encryption proxy to prevent recursive calls
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
// If data is a catfile
|
// If data is a catfile
|
||||||
if (
|
if (
|
||||||
Crypt::mode() == 'server'
|
Crypt::mode() == 'server'
|
||||||
&& Crypt::isCatfileContent( $data ) // TODO: Do we really need this check? Can't we assume it is properly encrypted?
|
&& 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
|
// TODO: use get owner to find correct location of key files for shared files
|
||||||
$session = new Session( $view );
|
$session = new Session($view);
|
||||||
$privateKey = $session->getPrivateKey( $userId );
|
$privateKey = $session->getPrivateKey($userId);
|
||||||
|
|
||||||
// Get the encrypted keyfile
|
// Get the encrypted keyfile
|
||||||
$encKeyfile = Keymanager::getFileKey( $view, $userId, $relPath );
|
$encKeyfile = Keymanager::getFileKey($view, $userId, $relPath);
|
||||||
|
|
||||||
// Attempt to fetch the user's shareKey
|
// Attempt to fetch the user's shareKey
|
||||||
$shareKey = Keymanager::getShareKey( $view, $userId, $relPath );
|
$shareKey = Keymanager::getShareKey($view, $userId, $relPath);
|
||||||
|
|
||||||
// Decrypt keyfile with shareKey
|
// 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 (
|
} elseif (
|
||||||
Crypt::mode() == 'server'
|
Crypt::mode() == 'server'
|
||||||
&& isset( $_SESSION['legacyenckey'] )
|
&& isset($_SESSION['legacyenckey'])
|
||||||
&& Crypt::isEncryptedMeta( $path )
|
&& Crypt::isEncryptedMeta($path)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
$plainData = Crypt::legacyDecrypt( $data, $session->getLegacyKey() );
|
$plainData = Crypt::legacyDecrypt($data, $session->getLegacyKey());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
if ( ! isset( $plainData ) ) {
|
if (!isset($plainData)) {
|
||||||
|
|
||||||
$plainData = $data;
|
$plainData = $data;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $plainData;
|
return $plainData;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief When a file is deleted, remove its keyfile also
|
* @brief When a file is deleted, remove its keyfile also
|
||||||
*/
|
*/
|
||||||
public function preUnlink( $path ) {
|
public function preUnlink($path)
|
||||||
|
{
|
||||||
|
|
||||||
// let the trashbin handle this
|
// let the trashbin handle this
|
||||||
if ( \OCP\App::isEnabled('files_trashbin') ) {
|
if (\OCP\App::isEnabled('files_trashbin')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable encryption proxy to prevent recursive calls
|
// Disable encryption proxy to prevent recursive calls
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
$view = new \OC_FilesystemView( '/' );
|
$view = new \OC_FilesystemView('/');
|
||||||
|
|
||||||
$userId = \OCP\USER::getUser();
|
$userId = \OCP\USER::getUser();
|
||||||
|
|
||||||
$util = new Util( $view, $userId );
|
$util = new Util($view, $userId);
|
||||||
|
|
||||||
// Format path to be relative to user files dir
|
// 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
|
// Delete keyfile & shareKey so it isn't orphaned
|
||||||
if (
|
if (
|
||||||
! (
|
!(
|
||||||
Keymanager::deleteFileKey( $view, $owner, $ownerPath )
|
Keymanager::deleteFileKey($view, $owner, $ownerPath)
|
||||||
&& Keymanager::delAllShareKeys( $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 );
|
\OC_Log::write('Encryption library', 'Keyfile or shareKey could not be deleted for file "' . $ownerPath . '"', \OC_Log::ERROR);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
// If we don't return true then file delete will fail; better
|
// If we don't return true then file delete will fail; better
|
||||||
// to leave orphaned keyfiles than to disallow file deletion
|
// to leave orphaned keyfiles than to disallow file deletion
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief When a file is renamed, rename its keyfile also
|
* @brief When a file is renamed, rename its keyfile also
|
||||||
* @return bool Result of rename()
|
* @param $path
|
||||||
* @note This is pre rather than post because using post didn't work
|
* @return bool Result of rename()
|
||||||
*/
|
* @note This is pre rather than post because using post didn't work
|
||||||
public function postWrite( $path )
|
*/
|
||||||
{
|
public function postWrite($path)
|
||||||
$this->handleFile($path);
|
{
|
||||||
|
$this->handleFile($path);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function postTouch( $path )
|
/**
|
||||||
{
|
* @param $path
|
||||||
$this->handleFile($path);
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function postTouch($path)
|
||||||
|
{
|
||||||
|
$this->handleFile($path);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function postFopen( $path, &$result ){
|
/**
|
||||||
|
* @param $path
|
||||||
|
* @param $result
|
||||||
|
* @return resource
|
||||||
|
*/
|
||||||
|
public function postFopen($path, &$result)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
|
||||||
if ( !$result ) {
|
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reformat path for use with OC_FSV
|
// Reformat path for use with OC_FSV
|
||||||
$path_split = explode( '/', $path );
|
$path_split = explode('/', $path);
|
||||||
$path_f = implode( '/', array_slice( $path_split, 3 ) );
|
$path_f = implode('/', array_slice($path_split, 3));
|
||||||
|
|
||||||
// FIXME: handling for /userId/cache used by webdav for chunking. The cache chunks are NOT encrypted
|
// FIXME: handling for /userId/cache used by webdav for chunking. The cache chunks are NOT encrypted
|
||||||
if($path_split[2] == 'cache') {
|
if ($path_split[2] == 'cache') {
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable encryption proxy to prevent recursive calls
|
// Disable encryption proxy to prevent recursive calls
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
|
$meta = stream_get_meta_data($result);
|
||||||
|
|
||||||
|
$view = new \OC_FilesystemView('');
|
||||||
|
|
||||||
|
$util = new Util($view, \OCP\USER::getUser());
|
||||||
|
|
||||||
$meta = stream_get_meta_data( $result );
|
|
||||||
|
|
||||||
$view = new \OC_FilesystemView( '' );
|
|
||||||
|
|
||||||
$util = new Util( $view, \OCP\USER::getUser());
|
|
||||||
|
|
||||||
// If file is already encrypted, decrypt using crypto protocol
|
// If file is already encrypted, decrypt using crypto protocol
|
||||||
if (
|
if (
|
||||||
Crypt::mode() == 'server'
|
Crypt::mode() == 'server'
|
||||||
&& $util->isEncryptedPath( $path )
|
&& $util->isEncryptedPath($path)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// Close the original encrypted file
|
// Close the original encrypted file
|
||||||
fclose( $result );
|
fclose($result);
|
||||||
|
|
||||||
// Open the file using the crypto stream wrapper
|
// Open the file using the crypto stream wrapper
|
||||||
// protocol and let it do the decryption work instead
|
// 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 )
|
|
||||||
and $meta ['mode'] != 'r'
|
|
||||||
and $meta['mode'] != 'rb'
|
|
||||||
) {
|
|
||||||
// If the file is not yet encrypted, but should be
|
|
||||||
// encrypted when it's saved (it's not read only)
|
|
||||||
|
|
||||||
// NOTE: this is the case for new files saved via WebDAV
|
|
||||||
|
|
||||||
// if (
|
|
||||||
// $view->file_exists( $path )
|
|
||||||
// and $view->filesize( $path ) > 0
|
|
||||||
// ) {
|
|
||||||
// $x = $view->file_get_contents( $path );
|
|
||||||
//
|
|
||||||
// $tmp = tmpfile();
|
|
||||||
|
|
||||||
// // Make a temporary copy of the original file
|
|
||||||
// \OCP\Files::streamCopy( $result, $tmp );
|
|
||||||
//
|
|
||||||
// // Close the original stream, we'll return another one
|
|
||||||
// fclose( $result );
|
|
||||||
//
|
|
||||||
// $view->file_put_contents( $path_f, $tmp );
|
|
||||||
//
|
|
||||||
// fclose( $tmp );
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
$result = fopen( 'crypt://'.$path_f, $meta['mode'] );
|
|
||||||
|
} elseif (
|
||||||
|
self::shouldEncrypt($path)
|
||||||
|
and $meta ['mode'] != 'r'
|
||||||
|
and $meta['mode'] != 'rb'
|
||||||
|
) {
|
||||||
|
$result = fopen('crypt://' . $path_f, $meta['mode']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-enable the proxy
|
// Re-enable the proxy
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function postGetMimeType( $path, $mime ) {
|
/**
|
||||||
|
* @param $path
|
||||||
|
* @param $mime
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function postGetMimeType($path, $mime)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (Crypt::isCatfileContent($path)) {
|
||||||
|
|
||||||
|
$mime = \OCP\Files::getMimeType('crypt://' . $path, 'w');
|
||||||
|
|
||||||
if ( Crypt::isCatfileContent( $path ) ) {
|
|
||||||
|
|
||||||
$mime = \OCP\Files::getMimeType( 'crypt://' . $path, 'w' );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $mime;
|
return $mime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function postGetFileInfo( $path, $data ) {
|
/**
|
||||||
|
* @param $path
|
||||||
|
* @param $data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function postGetFileInfo($path, $data)
|
||||||
|
{
|
||||||
|
|
||||||
// if path is a folder do nothing
|
// 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
|
// Disable encryption proxy to prevent recursive calls
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
// get file size
|
// get file size
|
||||||
$data['size'] = self::postFileSize($path, $data['size']);
|
$data['size'] = self::postFileSize($path, $data['size']);
|
||||||
|
|
||||||
// Re-enable the proxy
|
// Re-enable the proxy
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function postStat($path, $data)
|
/**
|
||||||
{
|
* @param $path
|
||||||
// check if file is encrypted
|
* @param $data
|
||||||
if (Crypt::isCatfileContent($path)) {
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function postStat($path, $data)
|
||||||
|
{
|
||||||
|
// check if file is encrypted
|
||||||
|
if (Crypt::isCatfileContent($path)) {
|
||||||
|
|
||||||
// get file info from cache
|
// get file info from cache
|
||||||
$cached = \OC\Files\Filesystem::getFileInfo($path, '');
|
$cached = \OC\Files\Filesystem::getFileInfo($path, '');
|
||||||
|
|
||||||
// set the real file size
|
// set the real file size
|
||||||
$data['size'] = $cached['unencrypted_size'];
|
$data['size'] = $cached['unencrypted_size'];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function postFileSize($path, $size)
|
/**
|
||||||
{
|
* @param $path
|
||||||
|
* @param $size
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function postFileSize($path, $size)
|
||||||
|
{
|
||||||
|
|
||||||
$view = new \OC_FilesystemView('/');
|
$view = new \OC_FilesystemView('/');
|
||||||
|
|
||||||
// if path is a folder do nothing
|
// if path is a folder do nothing
|
||||||
if ($view->is_dir($path)) {
|
if ($view->is_dir($path)) {
|
||||||
return $size;
|
return $size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reformat path for use with OC_FSV
|
// Reformat path for use with OC_FSV
|
||||||
$path_split = explode('/', $path);
|
$path_split = explode('/', $path);
|
||||||
$path_f = implode('/', array_slice($path_split, 3));
|
$path_f = implode('/', array_slice($path_split, 3));
|
||||||
|
|
||||||
// if path is empty we cannot resolve anything
|
// if path is empty we cannot resolve anything
|
||||||
if(empty($path_f)) {
|
if (empty($path_f)) {
|
||||||
return $size;
|
return $size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get file info from database/cache
|
// get file info from database/cache
|
||||||
$fileInfo = \OC\Files\Filesystem::getFileInfo($path_f);
|
$fileInfo = \OC\Files\Filesystem::getFileInfo($path_f);
|
||||||
|
|
||||||
// if file is encrypted return real file size
|
// 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'];
|
$size = $fileInfo['unencrypted_size'];
|
||||||
} else {
|
} else {
|
||||||
// self healing if file was removed from file cache
|
// self healing if file was removed from file cache
|
||||||
if(is_array($fileInfo)) {
|
if (is_array($fileInfo)) {
|
||||||
$userId = \OCP\User::getUser();
|
$userId = \OCP\User::getUser();
|
||||||
$util = new Util( $view, $userId );
|
$util = new Util($view, $userId);
|
||||||
$fixSize = $util->getFileSize($path);
|
$fixSize = $util->getFileSize($path);
|
||||||
if($fixSize > 0) {
|
if ($fixSize > 0) {
|
||||||
$size = $fixSize;
|
$size = $fixSize;
|
||||||
|
|
||||||
$fileInfo['encrypted'] = true;
|
$fileInfo['encrypted'] = true;
|
||||||
$fileInfo['unencrypted_size'] = $size;
|
$fileInfo['unencrypted_size'] = $size;
|
||||||
|
|
||||||
// put file info
|
// put file info
|
||||||
$view->putFileInfo( $path_f, $fileInfo );
|
$view->putFileInfo($path_f, $fileInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $size;
|
return $size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleFile($path) {
|
/**
|
||||||
|
* @param $path
|
||||||
|
*/
|
||||||
|
public function handleFile($path)
|
||||||
|
{
|
||||||
|
|
||||||
// Disable encryption proxy to prevent recursive calls
|
// Disable encryption proxy to prevent recursive calls
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
$view = new \OC_FilesystemView('/');
|
$view = new \OC_FilesystemView('/');
|
||||||
$session = new Session($view);
|
$session = new Session($view);
|
||||||
$userId = \OCP\User::getUser();
|
$userId = \OCP\User::getUser();
|
||||||
$util = new Util( $view, $userId );
|
$util = new Util($view, $userId);
|
||||||
|
|
||||||
// Reformat path for use with OC_FSV
|
// Reformat path for use with OC_FSV
|
||||||
$path_split = explode( '/', $path );
|
$path_split = explode('/', $path);
|
||||||
$path_f = implode( '/', array_slice( $path_split, 3 ) );
|
$path_f = implode('/', array_slice($path_split, 3));
|
||||||
|
|
||||||
// only if file is on 'files' folder fix file size and sharing
|
// only if file is on 'files' folder fix file size and sharing
|
||||||
if($path_split[2] == 'files' && $util->fixFileSize($path)) {
|
if ($path_split[2] == 'files' && $util->fixFileSize($path)) {
|
||||||
|
|
||||||
// get sharing app state
|
// get sharing app state
|
||||||
$sharingEnabled = \OCP\Share::isEnabled();
|
$sharingEnabled = \OCP\Share::isEnabled();
|
||||||
|
|
||||||
// get users
|
// get users
|
||||||
$usersSharing = $util->getSharingUsersArray($sharingEnabled, $path_f);
|
$usersSharing = $util->getSharingUsersArray($sharingEnabled, $path_f);
|
||||||
|
|
||||||
// update sharing-keys
|
// update sharing-keys
|
||||||
$util->setSharedFileKeyfiles($session, $usersSharing, $path_f);
|
$util->setSharedFileKeyfiles($session, $usersSharing, $path_f);
|
||||||
}
|
}
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,73 +26,75 @@ namespace OCA\Encryption;
|
||||||
* Class for handling encryption related session data
|
* Class for handling encryption related session data
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Session {
|
class Session
|
||||||
|
{
|
||||||
|
|
||||||
private $view;
|
private $view;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief if session is started, check if ownCloud key pair is set up, if not create it
|
* @brief if session is started, check if ownCloud key pair is set up, if not create it
|
||||||
*
|
* @param \OC_FilesystemView $view
|
||||||
* The ownCloud key pair is used to allow public link sharing even if encryption is enabled
|
*
|
||||||
|
* @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;
|
$this->view = $view;
|
||||||
|
|
||||||
|
if (!$this->view->is_dir('owncloud_private_key')) {
|
||||||
|
|
||||||
|
$this->view->mkdir('owncloud_private_key');
|
||||||
|
|
||||||
if ( ! $this->view->is_dir( '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) {
|
if ($publicShareKeyId === null) {
|
||||||
$publicShareKeyId = 'pubShare_'.substr(md5(time()),0,8);
|
$publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8);
|
||||||
\OC_Appconfig::setValue('files_encryption', 'publicShareKeyId', $publicShareKeyId);
|
\OC_Appconfig::setValue('files_encryption', 'publicShareKeyId', $publicShareKeyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
! $this->view->file_exists( "/public-keys/".$publicShareKeyId.".public.key" )
|
!$this->view->file_exists("/public-keys/" . $publicShareKeyId . ".public.key")
|
||||||
|| ! $this->view->file_exists( "/owncloud_private_key/".$publicShareKeyId.".private.key" )
|
|| !$this->view->file_exists("/owncloud_private_key/" . $publicShareKeyId . ".private.key")
|
||||||
) {
|
) {
|
||||||
|
|
||||||
$keypair = Crypt::createKeypair();
|
|
||||||
|
|
||||||
// Disable encryption proxy to prevent recursive calls
|
$keypair = Crypt::createKeypair();
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
|
||||||
\OC_FileProxy::$enabled = false;
|
// Disable encryption proxy to prevent recursive calls
|
||||||
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
|
// Save public key
|
||||||
|
|
||||||
|
if (!$view->is_dir('/public-keys')) {
|
||||||
|
$view->mkdir('/public-keys');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->view->file_put_contents('/public-keys/' . $publicShareKeyId . '.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/' . $publicShareKeyId . '.private.key', $encryptedPrivateKey);
|
||||||
|
|
||||||
// Save public key
|
|
||||||
|
|
||||||
if (!$view->is_dir('/public-keys')) {
|
|
||||||
$view->mkdir('/public-keys');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->view->file_put_contents( '/public-keys/'.$publicShareKeyId.'.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/'.$publicShareKeyId.'.private.key', $encryptedPrivateKey );
|
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(\OCP\USER::getUser() === false) {
|
if (\OCP\USER::getUser() === false) {
|
||||||
// Disable encryption proxy to prevent recursive calls
|
// Disable encryption proxy to prevent recursive calls
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
$encryptedKey = $this->view->file_get_contents( '/owncloud_private_key/'.$publicShareKeyId.'.private.key' );
|
$encryptedKey = $this->view->file_get_contents('/owncloud_private_key/' . $publicShareKeyId . '.private.key');
|
||||||
$privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, '' );
|
$privateKey = Crypt::symmetricDecryptFileContent($encryptedKey, '');
|
||||||
$this->setPrivateKey($privateKey);
|
$this->setPrivateKey($privateKey);
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -100,71 +102,72 @@ class Session {
|
||||||
* @param string $privateKey
|
* @param string $privateKey
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function setPrivateKey( $privateKey ) {
|
public function setPrivateKey($privateKey)
|
||||||
|
{
|
||||||
|
|
||||||
$_SESSION['privateKey'] = $privateKey;
|
$_SESSION['privateKey'] = $privateKey;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets user private key from session
|
* @brief Gets user private key from session
|
||||||
* @returns string $privateKey The user's plaintext private key
|
* @returns string $privateKey The user's plaintext private key
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function getPrivateKey() {
|
public function getPrivateKey()
|
||||||
|
{
|
||||||
if (
|
|
||||||
isset( $_SESSION['privateKey'] )
|
if (
|
||||||
&& !empty( $_SESSION['privateKey'] )
|
isset($_SESSION['privateKey'])
|
||||||
|
&& !empty($_SESSION['privateKey'])
|
||||||
) {
|
) {
|
||||||
|
|
||||||
return $_SESSION['privateKey'];
|
return $_SESSION['privateKey'];
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets user legacy key to session
|
* @brief Sets user legacy key to session
|
||||||
|
* @param $legacyKey
|
||||||
* @return bool
|
* @return bool
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public function setLegacyKey( $legacyKey ) {
|
public function setLegacyKey($legacyKey)
|
||||||
|
{
|
||||||
if ( $_SESSION['legacyKey'] = $legacyKey ) {
|
|
||||||
|
$_SESSION['legacyKey'] = $legacyKey;
|
||||||
return true;
|
|
||||||
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets user legacy key from session
|
* @brief Gets user legacy key from session
|
||||||
* @returns string $legacyKey The user's plaintext legacy key
|
* @returns string $legacyKey The user's plaintext legacy key
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function getLegacyKey() {
|
public function getLegacyKey()
|
||||||
|
{
|
||||||
if (
|
|
||||||
isset( $_SESSION['legacyKey'] )
|
if (
|
||||||
&& !empty( $_SESSION['legacyKey'] )
|
isset($_SESSION['legacyKey'])
|
||||||
|
&& !empty($_SESSION['legacyKey'])
|
||||||
) {
|
) {
|
||||||
|
|
||||||
return $_SESSION['legacyKey'];
|
return $_SESSION['legacyKey'];
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
* ownCloud
|
* ownCloud
|
||||||
*
|
*
|
||||||
* @author Robin Appelman
|
* @author Robin Appelman
|
||||||
* @copyright 2012 Sam Tuke <samtuke@owncloud.com>, 2011 Robin Appelman
|
* @copyright 2012 Sam Tuke <samtuke@owncloud.com>, 2011 Robin Appelman
|
||||||
* <icewind1991@gmail.com>
|
* <icewind1991@gmail.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
|
@ -32,30 +32,31 @@ namespace OCA\Encryption;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Provides 'crypt://' stream wrapper protocol.
|
* @brief Provides 'crypt://' stream wrapper protocol.
|
||||||
* @note We use a stream wrapper because it is the most secure way to handle
|
* @note We use a stream wrapper because it is the most secure way to handle
|
||||||
* decrypted content transfers. There is no safe way to decrypt the entire file
|
* decrypted content transfers. There is no safe way to decrypt the entire file
|
||||||
* somewhere on the server, so we have to encrypt and decrypt blocks on the fly.
|
* somewhere on the server, so we have to encrypt and decrypt blocks on the fly.
|
||||||
* @note Paths used with this protocol MUST BE RELATIVE. Use URLs like:
|
* @note Paths used with this protocol MUST BE RELATIVE. Use URLs like:
|
||||||
* crypt://filename, or crypt://subdirectory/filename, NOT
|
* crypt://filename, or crypt://subdirectory/filename, NOT
|
||||||
* crypt:///home/user/owncloud/data. Otherwise keyfiles will be put in
|
* crypt:///home/user/owncloud/data. Otherwise keyfiles will be put in
|
||||||
* [owncloud]/data/user/files_encryption/keyfiles/home/user/owncloud/data and
|
* [owncloud]/data/user/files_encryption/keyfiles/home/user/owncloud/data and
|
||||||
* will not be accessible to other methods.
|
* will not be accessible to other methods.
|
||||||
* @note Data read and written must always be 8192 bytes long, as this is the
|
* @note Data read and written must always be 8192 bytes long, as this is the
|
||||||
* buffer size used internally by PHP. The encryption process makes the input
|
* buffer size used internally by PHP. The encryption process makes the input
|
||||||
* data longer, and input is chunked into smaller pieces in order to result in
|
* data longer, and input is chunked into smaller pieces in order to result in
|
||||||
* a 8192 encrypted block size.
|
* a 8192 encrypted block size.
|
||||||
* @note When files are deleted via webdav, or when they are updated and the
|
* @note When files are deleted via webdav, or when they are updated and the
|
||||||
* previous version deleted, this is handled by OC\Files\View, and thus the
|
* previous version deleted, this is handled by OC\Files\View, and thus the
|
||||||
* encryption proxies are used and keyfiles deleted.
|
* encryption proxies are used and keyfiles deleted.
|
||||||
*/
|
*/
|
||||||
class Stream {
|
class Stream
|
||||||
|
{
|
||||||
|
|
||||||
public static $sourceStreams = array();
|
public static $sourceStreams = array();
|
||||||
|
private $plainKey;
|
||||||
|
private $encKeyfiles;
|
||||||
|
|
||||||
// TODO: make all below properties private again once unit testing is
|
private $rawPath; // The raw path relative to the data dir
|
||||||
// configured correctly
|
private $relPath; // rel path to users file dir
|
||||||
public $rawPath; // The raw path relative to the data dir
|
|
||||||
public $relPath; // rel path to users file dir
|
|
||||||
private $userId;
|
private $userId;
|
||||||
private $handle; // Resource returned by fopen
|
private $handle; // Resource returned by fopen
|
||||||
private $path;
|
private $path;
|
||||||
|
@ -63,226 +64,238 @@ class Stream {
|
||||||
private $meta = array(); // Header / meta for source stream
|
private $meta = array(); // Header / meta for source stream
|
||||||
private $count;
|
private $count;
|
||||||
private $writeCache;
|
private $writeCache;
|
||||||
public $size;
|
private $size;
|
||||||
public $unencryptedSize;
|
private $unencryptedSize;
|
||||||
private $publicKey;
|
private $publicKey;
|
||||||
private $keyfile;
|
private $keyfile;
|
||||||
private $encKeyfile;
|
private $encKeyfile;
|
||||||
private static $view; // a fsview object set to user dir
|
private static $view; // a fsview object set to user dir
|
||||||
private $rootView; // a fsview object set to '/'
|
private $rootView; // a fsview object set to '/'
|
||||||
|
|
||||||
public function stream_open( $path, $mode, $options, &$opened_path ) {
|
/**
|
||||||
|
* @param $path
|
||||||
|
* @param $mode
|
||||||
|
* @param $options
|
||||||
|
* @param $opened_path
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function stream_open($path, $mode, $options, &$opened_path)
|
||||||
|
{
|
||||||
|
|
||||||
if ( ! isset( $this->rootView ) ) {
|
if (!isset($this->rootView)) {
|
||||||
$this->rootView = new \OC_FilesystemView( '/' );
|
$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();
|
$this->userId = $util->getUserId();
|
||||||
|
|
||||||
|
// Strip identifier text from path, this gives us the path relative to data/<user>/files
|
||||||
|
$this->relPath = \OC\Files\Filesystem::normalizePath(str_replace('crypt://', '', $path));
|
||||||
|
|
||||||
// Strip identifier text from path, this gives us the path relative to data/<user>/files
|
|
||||||
$this->relPath = \OC\Files\Filesystem::normalizePath(str_replace( 'crypt://', '', $path ));
|
|
||||||
|
|
||||||
// rawPath is relative to the data directory
|
// rawPath is relative to the data directory
|
||||||
$this->rawPath = $util->getUserFilesDir() . $this->relPath;
|
$this->rawPath = $util->getUserFilesDir() . $this->relPath;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
dirname( $this->rawPath ) == 'streams'
|
dirname($this->rawPath) == 'streams'
|
||||||
and isset( self::$sourceStreams[basename( $this->rawPath )] )
|
and isset(self::$sourceStreams[basename($this->rawPath)])
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// Is this just for unit testing purposes?
|
// Is this just for unit testing purposes?
|
||||||
|
|
||||||
$this->handle = self::$sourceStreams[basename( $this->rawPath )]['stream'];
|
$this->handle = self::$sourceStreams[basename($this->rawPath)]['stream'];
|
||||||
|
|
||||||
$this->path = self::$sourceStreams[basename( $this->rawPath )]['path'];
|
$this->path = self::$sourceStreams[basename($this->rawPath)]['path'];
|
||||||
|
|
||||||
$this->size = self::$sourceStreams[basename( $this->rawPath )]['size'];
|
$this->size = self::$sourceStreams[basename($this->rawPath)]['size'];
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Disable fileproxies so we can get the file size and open the source file without recursive encryption
|
// Disable fileproxies so we can get the file size and open the source file without recursive encryption
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
$mode == 'w'
|
$mode == 'w'
|
||||||
or $mode == 'w+'
|
or $mode == 'w+'
|
||||||
or $mode == 'wb'
|
or $mode == 'wb'
|
||||||
or $mode == 'wb+'
|
or $mode == 'wb+'
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// We're writing a new file so start write counter with 0 bytes
|
// We're writing a new file so start write counter with 0 bytes
|
||||||
$this->size = 0;
|
$this->size = 0;
|
||||||
$this->unencryptedSize = 0;
|
$this->unencryptedSize = 0;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
$this->size = $this->rootView->filesize( $this->rawPath, $mode );
|
$this->size = $this->rootView->filesize($this->rawPath, $mode);
|
||||||
|
|
||||||
//$this->size = filesize( $this->rawPath );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//$this->handle = fopen( $this->rawPath, $mode );
|
$this->handle = $this->rootView->fopen($this->rawPath, $mode);
|
||||||
|
|
||||||
$this->handle = $this->rootView->fopen( $this->rawPath, $mode );
|
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\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 {
|
} 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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function stream_seek( $offset, $whence = SEEK_SET ) {
|
/**
|
||||||
|
* @param $offset
|
||||||
|
* @param int $whence
|
||||||
|
*/
|
||||||
|
public function stream_seek($offset, $whence = SEEK_SET)
|
||||||
|
{
|
||||||
|
|
||||||
$this->flush();
|
$this->flush();
|
||||||
|
|
||||||
fseek( $this->handle, $offset, $whence );
|
fseek($this->handle, $offset, $whence);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function stream_tell() {
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function stream_tell()
|
||||||
|
{
|
||||||
return ftell($this->handle);
|
return ftell($this->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function stream_read( $count ) {
|
/**
|
||||||
|
* @param $count
|
||||||
|
* @return bool|string
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function stream_read($count)
|
||||||
|
{
|
||||||
|
|
||||||
$this->writeCache = '';
|
$this->writeCache = '';
|
||||||
|
|
||||||
if ( $count != 8192 ) {
|
if ($count != 8192) {
|
||||||
|
|
||||||
// $count will always be 8192 https://bugs.php.net/bug.php?id=21641
|
// $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'
|
// 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();
|
die();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// $pos = ftell( $this->handle );
|
|
||||||
//
|
|
||||||
// Get the data from the file handle
|
// Get the data from the file handle
|
||||||
$data = fread( $this->handle, 8192 );
|
$data = fread($this->handle, 8192);
|
||||||
|
|
||||||
$result = '';
|
|
||||||
|
|
||||||
if ( strlen( $data ) ) {
|
|
||||||
|
|
||||||
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' );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decrypt data
|
|
||||||
$result = Crypt::symmetricDecryptFileContent( $data, $this->plainKey );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// $length = $this->size - $pos;
|
$result = '';
|
||||||
//
|
|
||||||
// if ( $length < 8192 ) {
|
if (strlen($data)) {
|
||||||
//
|
|
||||||
// $result = substr( $result, 0, $length );
|
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');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt data
|
||||||
|
$result = Crypt::symmetricDecryptFileContent($data, $this->plainKey);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Encrypt and pad data ready for writing to disk
|
* @brief Encrypt and pad data ready for writing to disk
|
||||||
* @param string $plainData data to be encrypted
|
* @param string $plainData data to be encrypted
|
||||||
* @param string $key key to use for encryption
|
* @param string $key key to use for encryption
|
||||||
* @return encrypted data on success, false on failure
|
* @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
|
// Encrypt data to 'catfile', which includes IV
|
||||||
if ( $encrypted = Crypt::symmetricEncryptFileContent( $plainData, $key ) ) {
|
if ($encrypted = Crypt::symmetricEncryptFileContent($plainData, $key)) {
|
||||||
|
|
||||||
return $encrypted;
|
return $encrypted;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Fetch the plain encryption key for the file and set it as plainKey property
|
* @brief Fetch the plain encryption key for the file and set it as plainKey property
|
||||||
* @param bool $generate if true, a new key will be generated if none can be found
|
* @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
|
* @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
|
// Check if key is already set
|
||||||
if ( isset( $this->plainKey ) && isset( $this->encKeyfile ) ) {
|
if (isset($this->plainKey) && isset($this->encKeyfile)) {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch and decrypt keyfile
|
// Fetch and decrypt keyfile
|
||||||
// Fetch existing 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 a keyfile already exists
|
||||||
if ( $this->encKeyfile ) {
|
if ($this->encKeyfile) {
|
||||||
$this->setUserProperty();
|
$this->setUserProperty();
|
||||||
|
|
||||||
$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;
|
return true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUserProperty() {
|
public function setUserProperty()
|
||||||
|
{
|
||||||
|
|
||||||
// Only get the user again if it isn't already set
|
// Only get the user again if it isn't already set
|
||||||
if ( empty( $this->userId ) ) {
|
if (empty($this->userId)) {
|
||||||
|
|
||||||
// TODO: Move this user call out of here - it belongs
|
// TODO: Move this user call out of here - it belongs
|
||||||
// elsewhere
|
// elsewhere
|
||||||
$this->userId = \OCP\User::getUser();
|
$this->userId = \OCP\User::getUser();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add a method for getting the user in case OCP\User::
|
// TODO: Add a method for getting the user in case OCP\User::
|
||||||
// getUser() doesn't work (can that scenario ever occur?)
|
// getUser() doesn't work (can that scenario ever occur?)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handle plain data from the stream, and write it in 8192 byte blocks
|
* @brief Handle plain data from the stream, and write it in 8192 byte blocks
|
||||||
* @param string $data data to be written to disk
|
* @param string $data data to be written to disk
|
||||||
|
@ -292,89 +305,64 @@ 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 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
|
* @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
|
// Disable the file proxies so that encryption is not
|
||||||
// automatically attempted when the file is written to disk -
|
// automatically attempted when the file is written to disk -
|
||||||
// we are handling that separately here and we don't want to
|
// we are handling that separately here and we don't want to
|
||||||
// get into an infinite loop
|
// get into an infinite loop
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
// Get the length of the unencrypted data that we are handling
|
// Get the length of the unencrypted data that we are handling
|
||||||
$length = strlen( $data );
|
$length = strlen($data);
|
||||||
|
|
||||||
// So far this round, no data has been written
|
// So far this round, no data has been written
|
||||||
$written = 0;
|
$written = 0;
|
||||||
|
|
||||||
// Find out where we are up to in the writing of data to the
|
// Find out where we are up to in the writing of data to the
|
||||||
// file
|
// file
|
||||||
$pointer = ftell( $this->handle );
|
$pointer = ftell($this->handle);
|
||||||
|
|
||||||
// Make sure the userId is set
|
// Make sure the userId is set
|
||||||
$this->setUserProperty();
|
$this->setUserProperty();
|
||||||
|
|
||||||
// Get / generate the keyfile for the file we're handling
|
// Get / generate the keyfile for the file we're handling
|
||||||
// If we're writing a new file (not overwriting an existing
|
// If we're writing a new file (not overwriting an existing
|
||||||
// one), save the newly generated keyfile
|
// one), save the newly generated keyfile
|
||||||
if ( ! $this->getKey() ) {
|
if (!$this->getKey()) {
|
||||||
|
|
||||||
$this->plainKey = Crypt::generateKey();
|
$this->plainKey = Crypt::generateKey();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// If extra data is left over from the last round, make sure it
|
// If extra data is left over from the last round, make sure it
|
||||||
// is integrated into the next 6126 / 8192 block
|
// is integrated into the next 6126 / 8192 block
|
||||||
if ( $this->writeCache ) {
|
if ($this->writeCache) {
|
||||||
|
|
||||||
// Concat writeCache to start of $data
|
// Concat writeCache to start of $data
|
||||||
$data = $this->writeCache . $data;
|
$data = $this->writeCache . $data;
|
||||||
|
|
||||||
// Clear the write cache, ready for resuse - it has been
|
// Clear the write cache, ready for resuse - it has been
|
||||||
// flushed and its old contents processed
|
// flushed and its old contents processed
|
||||||
$this->writeCache = '';
|
$this->writeCache = '';
|
||||||
|
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// // Make sure we always start on a block start
|
|
||||||
if ( 0 != ( $pointer % 8192 ) ) {
|
|
||||||
// if the current position of
|
|
||||||
// file indicator is not aligned to a 8192 byte block, fix it
|
|
||||||
// so that it is
|
|
||||||
|
|
||||||
// fseek( $this->handle, - ( $pointer % 8192 ), SEEK_CUR );
|
|
||||||
//
|
|
||||||
// $pointer = ftell( $this->handle );
|
|
||||||
//
|
|
||||||
// $unencryptedNewBlock = fread( $this->handle, 8192 );
|
|
||||||
//
|
|
||||||
// fseek( $this->handle, - ( $currentPos % 8192 ), SEEK_CUR );
|
|
||||||
//
|
|
||||||
// $block = Crypt::symmetricDecryptFileContent( $unencryptedNewBlock, $this->plainKey );
|
|
||||||
//
|
|
||||||
// $x = substr( $block, 0, $currentPos % 8192 );
|
|
||||||
//
|
|
||||||
// $data = $x . $data;
|
|
||||||
//
|
|
||||||
// fseek( $this->handle, - ( $currentPos % 8192 ), SEEK_CUR );
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
// $currentPos = ftell( $this->handle );
|
// While there still remains somed data to be processed & written
|
||||||
|
while (strlen($data) > 0) {
|
||||||
// // While there still remains somed data to be processed & written
|
|
||||||
while( strlen( $data ) > 0 ) {
|
// Remaining length for this iteration, not of the
|
||||||
|
// entire file (may be greater than 8192 bytes)
|
||||||
// // Remaining length for this iteration, not of the
|
$remainingLength = strlen( $data );
|
||||||
// // entire file (may be greater than 8192 bytes)
|
|
||||||
// $remainingLength = strlen( $data );
|
// If data remaining to be written is less than the
|
||||||
//
|
// size of 1 6126 byte block
|
||||||
// // If data remaining to be written is less than the
|
if (strlen($data) < 6126) {
|
||||||
// // size of 1 6126 byte block
|
|
||||||
if ( strlen( $data ) < 6126 ) {
|
|
||||||
|
|
||||||
// Set writeCache to contents of $data
|
// Set writeCache to contents of $data
|
||||||
// The writeCache will be carried over to the
|
// The writeCache will be carried over to the
|
||||||
// next write round, and added to the start of
|
// next write round, and added to the start of
|
||||||
|
@ -387,148 +375,174 @@ class Stream {
|
||||||
|
|
||||||
// Clear $data ready for next round
|
// Clear $data ready for next round
|
||||||
$data = '';
|
$data = '';
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Read the chunk from the start of $data
|
// 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
|
// Write the data chunk to disk. This will be
|
||||||
// attended to the last data chunk if the file
|
// attended to the last data chunk if the file
|
||||||
// being handled totals more than 6126 bytes
|
// being handled totals more than 6126 bytes
|
||||||
fwrite( $this->handle, $encrypted );
|
fwrite($this->handle, $encrypted);
|
||||||
|
|
||||||
$writtenLen = strlen( $encrypted );
|
$writtenLen = strlen($encrypted);
|
||||||
//fseek( $this->handle, $writtenLen, SEEK_CUR );
|
|
||||||
|
|
||||||
// Remove the chunk we just processed from
|
// Remove the chunk we just processed from
|
||||||
// $data, leaving only unprocessed data in $data
|
// $data, leaving only unprocessed data in $data
|
||||||
// var, for handling on the next round
|
// var, for handling on the next round
|
||||||
$data = substr( $data, 6126 );
|
$data = substr($data, 6126);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->size = max( $this->size, $pointer + $length );
|
|
||||||
$this->unencryptedSize += $length;
|
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
}
|
||||||
|
|
||||||
|
$this->size = max($this->size, $pointer + $length);
|
||||||
|
$this->unencryptedSize += $length;
|
||||||
|
|
||||||
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
return $length;
|
return $length;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function stream_set_option( $option, $arg1, $arg2 ) {
|
/**
|
||||||
switch($option) {
|
* @param $option
|
||||||
|
* @param $arg1
|
||||||
|
* @param $arg2
|
||||||
|
*/
|
||||||
|
public function stream_set_option($option, $arg1, $arg2)
|
||||||
|
{
|
||||||
|
switch ($option) {
|
||||||
case STREAM_OPTION_BLOCKING:
|
case STREAM_OPTION_BLOCKING:
|
||||||
stream_set_blocking( $this->handle, $arg1 );
|
stream_set_blocking($this->handle, $arg1);
|
||||||
break;
|
break;
|
||||||
case STREAM_OPTION_READ_TIMEOUT:
|
case STREAM_OPTION_READ_TIMEOUT:
|
||||||
stream_set_timeout( $this->handle, $arg1, $arg2 );
|
stream_set_timeout($this->handle, $arg1, $arg2);
|
||||||
break;
|
break;
|
||||||
case STREAM_OPTION_WRITE_BUFFER:
|
case STREAM_OPTION_WRITE_BUFFER:
|
||||||
stream_set_write_buffer( $this->handle, $arg1, $arg2 );
|
stream_set_write_buffer($this->handle, $arg1, $arg2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function stream_stat() {
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function stream_stat()
|
||||||
|
{
|
||||||
return fstat($this->handle);
|
return fstat($this->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function stream_lock( $mode ) {
|
/**
|
||||||
flock( $this->handle, $mode );
|
* @param $mode
|
||||||
}
|
*/
|
||||||
|
public function stream_lock($mode)
|
||||||
public function stream_flush() {
|
{
|
||||||
|
flock($this->handle, $mode);
|
||||||
return fflush( $this->handle );
|
|
||||||
// Not a typo: http://php.net/manual/en/function.fflush.php
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function stream_eof() {
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function stream_flush()
|
||||||
|
{
|
||||||
|
|
||||||
|
return fflush($this->handle);
|
||||||
|
// Not a typo: http://php.net/manual/en/function.fflush.php
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function stream_eof()
|
||||||
|
{
|
||||||
return feof($this->handle);
|
return feof($this->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function flush() {
|
private function flush()
|
||||||
|
{
|
||||||
if ( $this->writeCache ) {
|
|
||||||
|
if ($this->writeCache) {
|
||||||
|
|
||||||
// Set keyfile property for file in question
|
// Set keyfile property for file in question
|
||||||
$this->getKey();
|
$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 = '';
|
$this->writeCache = '';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function stream_close() {
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function stream_close()
|
||||||
|
{
|
||||||
|
|
||||||
$this->flush();
|
$this->flush();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
$this->meta['mode']!='r'
|
$this->meta['mode'] != 'r'
|
||||||
and $this->meta['mode']!='rb'
|
and $this->meta['mode'] != 'rb'
|
||||||
and $this->size > 0
|
and $this->size > 0
|
||||||
) {
|
) {
|
||||||
// Disable encryption proxy to prevent recursive calls
|
// Disable encryption proxy to prevent recursive calls
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
// Fetch user's public key
|
// 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
|
// Check if OC sharing api is enabled
|
||||||
$sharingEnabled = \OCP\Share::isEnabled();
|
$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
|
// 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
|
// 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
|
// 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
|
// 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
|
// Save the sharekeys
|
||||||
Keymanager::setShareKeys( $view, $this->relPath, $this->encKeyfiles['keys'] );
|
Keymanager::setShareKeys($view, $this->relPath, $this->encKeyfiles['keys']);
|
||||||
|
|
||||||
// get file info
|
// get file info
|
||||||
$fileInfo = $view->getFileInfo($this->rawPath);
|
$fileInfo = $view->getFileInfo($this->rawPath);
|
||||||
if(!is_array($fileInfo)) {
|
if (!is_array($fileInfo)) {
|
||||||
$fileInfo = array();
|
$fileInfo = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-enable proxy - our work is done
|
// Re-enable proxy - our work is done
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
// set encryption data
|
// set encryption data
|
||||||
$fileInfo['encrypted'] = true;
|
$fileInfo['encrypted'] = true;
|
||||||
$fileInfo['size'] = $this->size;
|
$fileInfo['size'] = $this->size;
|
||||||
$fileInfo['unencrypted_size'] = $this->unencryptedSize;
|
$fileInfo['unencrypted_size'] = $this->unencryptedSize;
|
||||||
|
|
||||||
// set fileinfo
|
// set fileinfo
|
||||||
$view->putFileInfo( $this->rawPath, $fileInfo);
|
$view->putFileInfo($this->rawPath, $fileInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fclose( $this->handle );
|
return fclose($this->handle);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -6,21 +6,22 @@
|
||||||
* See the COPYING-README file.
|
* See the COPYING-README file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once realpath( dirname(__FILE__).'/../../../lib/base.php' );
|
require_once realpath(dirname(__FILE__) . '/../../../lib/base.php');
|
||||||
require_once realpath( dirname(__FILE__).'/../lib/crypt.php' );
|
require_once realpath(dirname(__FILE__) . '/../lib/crypt.php');
|
||||||
require_once realpath( dirname(__FILE__).'/../lib/keymanager.php' );
|
require_once realpath(dirname(__FILE__) . '/../lib/keymanager.php');
|
||||||
require_once realpath( dirname(__FILE__).'/../lib/proxy.php' );
|
require_once realpath(dirname(__FILE__) . '/../lib/proxy.php');
|
||||||
require_once realpath( dirname(__FILE__).'/../lib/stream.php' );
|
require_once realpath(dirname(__FILE__) . '/../lib/stream.php');
|
||||||
require_once realpath( dirname(__FILE__).'/../lib/util.php' );
|
require_once realpath(dirname(__FILE__) . '/../lib/util.php');
|
||||||
require_once realpath( dirname(__FILE__).'/../lib/helper.php' );
|
require_once realpath(dirname(__FILE__) . '/../lib/helper.php');
|
||||||
require_once realpath( dirname(__FILE__).'/../appinfo/app.php' );
|
require_once realpath(dirname(__FILE__) . '/../appinfo/app.php');
|
||||||
|
|
||||||
use OCA\Encryption;
|
use OCA\Encryption;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Test_Encryption_Keymanager
|
* Class Test_Encryption_Keymanager
|
||||||
*/
|
*/
|
||||||
class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
|
||||||
public $userId;
|
public $userId;
|
||||||
public $pass;
|
public $pass;
|
||||||
|
@ -31,38 +32,39 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||||
public $view;
|
public $view;
|
||||||
public $randomKey;
|
public $randomKey;
|
||||||
|
|
||||||
function setUp() {
|
function setUp()
|
||||||
// reset backend
|
{
|
||||||
\OC_User::clearBackends();
|
// reset backend
|
||||||
\OC_User::useBackend('database');
|
\OC_User::clearBackends();
|
||||||
|
\OC_User::useBackend('database');
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
// set content for encrypting / decrypting in tests
|
// set content for encrypting / decrypting in tests
|
||||||
$this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) );
|
$this->dataLong = file_get_contents(realpath(dirname(__FILE__) . '/../lib/crypt.php'));
|
||||||
$this->dataShort = 'hats';
|
$this->dataShort = 'hats';
|
||||||
$this->dataUrl = realpath( dirname(__FILE__).'/../lib/crypt.php' );
|
$this->dataUrl = realpath(dirname(__FILE__) . '/../lib/crypt.php');
|
||||||
$this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' );
|
$this->legacyData = realpath(dirname(__FILE__) . '/legacy-text.txt');
|
||||||
$this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' );
|
$this->legacyEncryptedData = realpath(dirname(__FILE__) . '/legacy-encrypted-text.txt');
|
||||||
$this->randomKey = Encryption\Crypt::generateKey();
|
$this->randomKey = Encryption\Crypt::generateKey();
|
||||||
|
|
||||||
$keypair = Encryption\Crypt::createKeypair();
|
$keypair = Encryption\Crypt::createKeypair();
|
||||||
$this->genPublicKey = $keypair['publicKey'];
|
$this->genPublicKey = $keypair['publicKey'];
|
||||||
$this->genPrivateKey = $keypair['privateKey'];
|
$this->genPrivateKey = $keypair['privateKey'];
|
||||||
|
|
||||||
$this->view = new \OC_FilesystemView( '/' );
|
$this->view = new \OC_FilesystemView('/');
|
||||||
|
|
||||||
\OC_User::setUserId( 'admin' );
|
\OC_User::setUserId('admin');
|
||||||
$this->userId = 'admin';
|
$this->userId = 'admin';
|
||||||
$this->pass = 'admin';
|
$this->pass = 'admin';
|
||||||
|
|
||||||
$userHome = \OC_User::getHome($this->userId);
|
$userHome = \OC_User::getHome($this->userId);
|
||||||
$this->dataDir = str_replace('/'.$this->userId, '', $userHome);
|
$this->dataDir = str_replace('/' . $this->userId, '', $userHome);
|
||||||
|
|
||||||
// Filesystem related hooks
|
// Filesystem related hooks
|
||||||
\OCA\Encryption\Helper::registerFilesystemHooks();
|
\OCA\Encryption\Helper::registerFilesystemHooks();
|
||||||
|
|
||||||
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
||||||
|
|
||||||
// remember files_trashbin state
|
// remember files_trashbin state
|
||||||
$this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
|
$this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
|
||||||
|
@ -70,19 +72,20 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||||
// we don't want to tests with app files_trashbin enabled
|
// we don't want to tests with app files_trashbin enabled
|
||||||
\OC_App::disable('files_trashbin');
|
\OC_App::disable('files_trashbin');
|
||||||
|
|
||||||
\OC_Util::tearDownFS();
|
\OC_Util::tearDownFS();
|
||||||
\OC_User::setUserId('');
|
\OC_User::setUserId('');
|
||||||
\OC\Files\Filesystem::tearDown();
|
\OC\Files\Filesystem::tearDown();
|
||||||
\OC_Util::setupFS($this->userId);
|
\OC_Util::setupFS($this->userId);
|
||||||
\OC_User::setUserId($this->userId);
|
\OC_User::setUserId($this->userId);
|
||||||
|
|
||||||
$params['uid'] = $this->userId;
|
$params['uid'] = $this->userId;
|
||||||
$params['password'] = $this->pass;
|
$params['password'] = $this->pass;
|
||||||
OCA\Encryption\Hooks::login($params);
|
OCA\Encryption\Hooks::login($params);
|
||||||
}
|
}
|
||||||
|
|
||||||
function tearDown(){
|
function tearDown()
|
||||||
|
{
|
||||||
|
|
||||||
\OC_FileProxy::$enabled = true;
|
\OC_FileProxy::$enabled = true;
|
||||||
\OC_FileProxy::clearProxies();
|
\OC_FileProxy::clearProxies();
|
||||||
|
|
||||||
|
@ -94,11 +97,12 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function testGetPrivateKey() {
|
function testGetPrivateKey()
|
||||||
|
{
|
||||||
$key = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId );
|
|
||||||
|
|
||||||
$privateKey = Encryption\Crypt::symmetricDecryptFileContent( $key, $this->pass);
|
$key = Encryption\Keymanager::getPrivateKey($this->view, $this->userId);
|
||||||
|
|
||||||
|
$privateKey = Encryption\Crypt::symmetricDecryptFileContent($key, $this->pass);
|
||||||
|
|
||||||
$res = openssl_pkey_get_private($privateKey);
|
$res = openssl_pkey_get_private($privateKey);
|
||||||
|
|
||||||
|
@ -107,12 +111,13 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||||
$sslInfo = openssl_pkey_get_details($res);
|
$sslInfo = openssl_pkey_get_details($res);
|
||||||
|
|
||||||
$this->assertArrayHasKey('key', $sslInfo);
|
$this->assertArrayHasKey('key', $sslInfo);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function testGetPublicKey() {
|
|
||||||
|
|
||||||
$publiceKey = Encryption\Keymanager::getPublicKey( $this->view, $this->userId );
|
}
|
||||||
|
|
||||||
|
function testGetPublicKey()
|
||||||
|
{
|
||||||
|
|
||||||
|
$publiceKey = Encryption\Keymanager::getPublicKey($this->view, $this->userId);
|
||||||
|
|
||||||
$res = openssl_pkey_get_public($publiceKey);
|
$res = openssl_pkey_get_public($publiceKey);
|
||||||
|
|
||||||
|
@ -122,40 +127,41 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
$this->assertArrayHasKey('key', $sslInfo);
|
$this->assertArrayHasKey('key', $sslInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testSetFileKey() {
|
function testSetFileKey()
|
||||||
|
{
|
||||||
|
|
||||||
# NOTE: This cannot be tested until we are able to break out
|
# NOTE: This cannot be tested until we are able to break out
|
||||||
# of the FileSystemView data directory root
|
# of the FileSystemView data directory root
|
||||||
|
|
||||||
$key = Encryption\Crypt::symmetricEncryptFileContentKeyfile( $this->randomKey, 'hat' );
|
|
||||||
|
|
||||||
$file = 'unittest-'.time().'.txt';
|
|
||||||
|
|
||||||
// Disable encryption proxy to prevent recursive calls
|
$key = Encryption\Crypt::symmetricEncryptFileContentKeyfile($this->randomKey, 'hat');
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
|
||||||
\OC_FileProxy::$enabled = false;
|
|
||||||
|
|
||||||
$this->view->file_put_contents($this->userId . '/files/' . $file, $key['encrypted']);
|
$file = 'unittest-' . time() . '.txt';
|
||||||
|
|
||||||
// Re-enable proxy - our work is done
|
// Disable encryption proxy to prevent recursive calls
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
|
$this->view->file_put_contents($this->userId . '/files/' . $file, $key['encrypted']);
|
||||||
|
|
||||||
|
// Re-enable proxy - our work is done
|
||||||
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
//$view = new \OC_FilesystemView( '/' . $this->userId . '/files_encryption/keyfiles' );
|
//$view = new \OC_FilesystemView( '/' . $this->userId . '/files_encryption/keyfiles' );
|
||||||
Encryption\Keymanager::setFileKey( $this->view, $file, $this->userId, $key['key'] );
|
Encryption\Keymanager::setFileKey($this->view, $file, $this->userId, $key['key']);
|
||||||
|
|
||||||
// Disable encryption proxy to prevent recursive calls
|
// Disable encryption proxy to prevent recursive calls
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = true;
|
\OC_FileProxy::$enabled = true;
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
$this->view->unlink('/'.$this->userId . '/files/' . $file);
|
$this->view->unlink('/' . $this->userId . '/files/' . $file);
|
||||||
|
|
||||||
// Re-enable proxy - our work is done
|
// Re-enable proxy - our work is done
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * @depends testGetPrivateKey
|
// * @depends testGetPrivateKey
|
||||||
// */
|
// */
|
||||||
|
@ -171,10 +177,11 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||||
// $this->assertEquals( '-----BEGIN PRIVATE KEY-----', substr( $decrypted, 0, 27 ) );
|
// $this->assertEquals( '-----BEGIN PRIVATE KEY-----', substr( $decrypted, 0, 27 ) );
|
||||||
//
|
//
|
||||||
// }
|
// }
|
||||||
|
|
||||||
function testGetUserKeys() {
|
function testGetUserKeys()
|
||||||
|
{
|
||||||
$keys = Encryption\Keymanager::getUserKeys( $this->view, $this->userId );
|
|
||||||
|
$keys = Encryption\Keymanager::getUserKeys($this->view, $this->userId);
|
||||||
|
|
||||||
$resPublic = openssl_pkey_get_public($keys['publicKey']);
|
$resPublic = openssl_pkey_get_public($keys['publicKey']);
|
||||||
|
|
||||||
|
@ -184,7 +191,7 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
$this->assertArrayHasKey('key', $sslInfoPublic);
|
$this->assertArrayHasKey('key', $sslInfoPublic);
|
||||||
|
|
||||||
$privateKey = Encryption\Crypt::symmetricDecryptFileContent( $keys['privateKey'], $this->pass);
|
$privateKey = Encryption\Crypt::symmetricDecryptFileContent($keys['privateKey'], $this->pass);
|
||||||
|
|
||||||
$resPrivate = openssl_pkey_get_private($privateKey);
|
$resPrivate = openssl_pkey_get_private($privateKey);
|
||||||
|
|
||||||
|
|
|
@ -50,446 +50,446 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase
|
||||||
public $subsubfolder;
|
public $subsubfolder;
|
||||||
|
|
||||||
function setUp()
|
function setUp()
|
||||||
{
|
{
|
||||||
// reset backend
|
// reset backend
|
||||||
\OC_User::clearBackends();
|
\OC_User::clearBackends();
|
||||||
\OC_User::useBackend('database');
|
\OC_User::useBackend('database');
|
||||||
|
|
||||||
$this->dataShort = 'hats';
|
$this->dataShort = 'hats';
|
||||||
$this->view = new \OC_FilesystemView('/');
|
$this->view = new \OC_FilesystemView('/');
|
||||||
|
|
||||||
$userHome = \OC_User::getHome('admin');
|
$userHome = \OC_User::getHome('admin');
|
||||||
$this->dataDir = str_replace('/admin', '', $userHome);
|
$this->dataDir = str_replace('/admin', '', $userHome);
|
||||||
|
|
||||||
$this->folder1 = '/folder1';
|
$this->folder1 = '/folder1';
|
||||||
$this->subfolder = '/subfolder1';
|
$this->subfolder = '/subfolder1';
|
||||||
$this->subsubfolder = '/subsubfolder1';
|
$this->subsubfolder = '/subsubfolder1';
|
||||||
|
|
||||||
$this->filename = 'share-tmp.test';
|
$this->filename = 'share-tmp.test';
|
||||||
|
|
||||||
// enable resharing
|
// enable resharing
|
||||||
\OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'yes');
|
\OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'yes');
|
||||||
|
|
||||||
// clear share hooks
|
// clear share hooks
|
||||||
\OC_Hook::clear('OCP\\Share');
|
\OC_Hook::clear('OCP\\Share');
|
||||||
\OC::registerShareHooks();
|
\OC::registerShareHooks();
|
||||||
\OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup');
|
\OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup');
|
||||||
|
|
||||||
// Sharing related hooks
|
// Sharing related hooks
|
||||||
\OCA\Encryption\Helper::registerShareHooks();
|
\OCA\Encryption\Helper::registerShareHooks();
|
||||||
|
|
||||||
// Filesystem related hooks
|
// Filesystem related hooks
|
||||||
\OCA\Encryption\Helper::registerFilesystemHooks();
|
\OCA\Encryption\Helper::registerFilesystemHooks();
|
||||||
|
|
||||||
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
||||||
|
|
||||||
// remember files_trashbin state
|
// remember files_trashbin state
|
||||||
$this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
|
$this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
|
||||||
|
|
||||||
// we don't want to tests with app files_trashbin enabled
|
// we don't want to tests with app files_trashbin enabled
|
||||||
\OC_App::disable('files_trashbin');
|
\OC_App::disable('files_trashbin');
|
||||||
|
|
||||||
// create users
|
// create users
|
||||||
$this->loginHelper('user1', true);
|
$this->loginHelper('user1', true);
|
||||||
$this->loginHelper('user2', true);
|
$this->loginHelper('user2', true);
|
||||||
$this->loginHelper('user3', true);
|
$this->loginHelper('user3', true);
|
||||||
|
|
||||||
// create group and assign users
|
// create group and assign users
|
||||||
\OC_Group::createGroup('group1');
|
\OC_Group::createGroup('group1');
|
||||||
\OC_Group::addToGroup('user2', 'group1');
|
\OC_Group::addToGroup('user2', 'group1');
|
||||||
\OC_Group::addToGroup('user3', 'group1');
|
\OC_Group::addToGroup('user3', 'group1');
|
||||||
}
|
}
|
||||||
|
|
||||||
function tearDown()
|
function tearDown()
|
||||||
{
|
{
|
||||||
// reset app files_trashbin
|
// reset app files_trashbin
|
||||||
if ($this->stateFilesTrashbin) {
|
if ($this->stateFilesTrashbin) {
|
||||||
OC_App::enable('files_trashbin');
|
OC_App::enable('files_trashbin');
|
||||||
} else {
|
} else {
|
||||||
OC_App::disable('files_trashbin');
|
OC_App::disable('files_trashbin');
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean group
|
// clean group
|
||||||
\OC_Group::deleteGroup('group1');
|
\OC_Group::deleteGroup('group1');
|
||||||
|
|
||||||
// cleanup users
|
// cleanup users
|
||||||
\OC_User::deleteUser('user1');
|
\OC_User::deleteUser('user1');
|
||||||
\OC_User::deleteUser('user2');
|
\OC_User::deleteUser('user2');
|
||||||
\OC_User::deleteUser('user3');
|
\OC_User::deleteUser('user3');
|
||||||
|
|
||||||
\OC_FileProxy::clearProxies();
|
\OC_FileProxy::clearProxies();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $withTeardown
|
* @param bool $withTeardown
|
||||||
*/
|
*/
|
||||||
function testShareFile($withTeardown = true)
|
function testShareFile($withTeardown = true)
|
||||||
{
|
{
|
||||||
// login as admin
|
// login as admin
|
||||||
$this->loginHelper('admin');
|
$this->loginHelper('admin');
|
||||||
|
|
||||||
// save file with content
|
// save file with content
|
||||||
$cryptedFile = file_put_contents('crypt://' . $this->filename, $this->dataShort);
|
$cryptedFile = file_put_contents('crypt://' . $this->filename, $this->dataShort);
|
||||||
|
|
||||||
// test that data was successfully written
|
// test that data was successfully written
|
||||||
$this->assertTrue(is_int($cryptedFile));
|
$this->assertTrue(is_int($cryptedFile));
|
||||||
|
|
||||||
// disable encryption proxy to prevent recursive calls
|
// disable encryption proxy to prevent recursive calls
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
// get the file info from previous created file
|
// get the file info from previous created file
|
||||||
$fileInfo = $this->view->getFileInfo('/admin/files/' . $this->filename);
|
$fileInfo = $this->view->getFileInfo('/admin/files/' . $this->filename);
|
||||||
|
|
||||||
// check if we have a valid file info
|
// check if we have a valid file info
|
||||||
$this->assertTrue(is_array($fileInfo));
|
$this->assertTrue(is_array($fileInfo));
|
||||||
|
|
||||||
// check if the unencrypted file size is stored
|
// check if the unencrypted file size is stored
|
||||||
$this->assertGreaterThan(0, $fileInfo['unencrypted_size']);
|
$this->assertGreaterThan(0, $fileInfo['unencrypted_size']);
|
||||||
|
|
||||||
// re-enable the file proxy
|
// re-enable the file proxy
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
// share the file
|
// share the file
|
||||||
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1', OCP\PERMISSION_ALL);
|
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1', OCP\PERMISSION_ALL);
|
||||||
|
|
||||||
// login as admin
|
// login as admin
|
||||||
$this->loginHelper('admin');
|
$this->loginHelper('admin');
|
||||||
|
|
||||||
// check if share key for user1 exists
|
// check if share key for user1 exists
|
||||||
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey'));
|
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey'));
|
||||||
|
|
||||||
// login as user1
|
// login as user1
|
||||||
$this->loginHelper('user1');
|
$this->loginHelper('user1');
|
||||||
|
|
||||||
// get file contents
|
// get file contents
|
||||||
$retrievedCryptedFile = $this->view->file_get_contents('/user1/files/Shared/' . $this->filename);
|
$retrievedCryptedFile = $this->view->file_get_contents('/user1/files/Shared/' . $this->filename);
|
||||||
|
|
||||||
// check if data is the same as we previously written
|
// check if data is the same as we previously written
|
||||||
$this->assertEquals($this->dataShort, $retrievedCryptedFile);
|
$this->assertEquals($this->dataShort, $retrievedCryptedFile);
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
if ($withTeardown) {
|
if ($withTeardown) {
|
||||||
|
|
||||||
// login as admin
|
// login as admin
|
||||||
$this->loginHelper('admin');
|
$this->loginHelper('admin');
|
||||||
|
|
||||||
// unshare the file
|
// unshare the file
|
||||||
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1');
|
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1');
|
||||||
|
|
||||||
// check if share key not exists
|
// check if share key not exists
|
||||||
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey'));
|
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey'));
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
$this->view->unlink('/admin/files/' . $this->filename);
|
$this->view->unlink('/admin/files/' . $this->filename);
|
||||||
|
|
||||||
// check if share key not exists
|
// check if share key not exists
|
||||||
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey'));
|
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $withTeardown
|
* @param bool $withTeardown
|
||||||
*/
|
*/
|
||||||
function testReShareFile($withTeardown = true)
|
function testReShareFile($withTeardown = true)
|
||||||
{
|
{
|
||||||
$this->testShareFile(false);
|
$this->testShareFile(false);
|
||||||
|
|
||||||
// login as user1
|
// login as user1
|
||||||
$this->loginHelper('user1');
|
$this->loginHelper('user1');
|
||||||
|
|
||||||
// get the file info
|
// get the file info
|
||||||
$fileInfo = $this->view->getFileInfo('/user1/files/Shared/' . $this->filename);
|
$fileInfo = $this->view->getFileInfo('/user1/files/Shared/' . $this->filename);
|
||||||
|
|
||||||
// share the file with user2
|
// share the file with user2
|
||||||
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2', OCP\PERMISSION_ALL);
|
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2', OCP\PERMISSION_ALL);
|
||||||
|
|
||||||
// login as admin
|
// login as admin
|
||||||
$this->loginHelper('admin');
|
$this->loginHelper('admin');
|
||||||
|
|
||||||
// check if share key for user2 exists
|
// check if share key for user2 exists
|
||||||
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user2.shareKey'));
|
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user2.shareKey'));
|
||||||
|
|
||||||
// login as user2
|
// login as user2
|
||||||
$this->loginHelper('user2');
|
$this->loginHelper('user2');
|
||||||
|
|
||||||
// get file contents
|
// get file contents
|
||||||
$retrievedCryptedFile = $this->view->file_get_contents('/user2/files/Shared/' . $this->filename);
|
$retrievedCryptedFile = $this->view->file_get_contents('/user2/files/Shared/' . $this->filename);
|
||||||
|
|
||||||
// check if data is the same as previously written
|
// check if data is the same as previously written
|
||||||
$this->assertEquals($this->dataShort, $retrievedCryptedFile);
|
$this->assertEquals($this->dataShort, $retrievedCryptedFile);
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
if ($withTeardown) {
|
if ($withTeardown) {
|
||||||
|
|
||||||
// login as user1
|
// login as user1
|
||||||
$this->loginHelper('user1');
|
$this->loginHelper('user1');
|
||||||
|
|
||||||
// unshare the file with user2
|
// unshare the file with user2
|
||||||
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2');
|
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2');
|
||||||
|
|
||||||
// login as admin
|
// login as admin
|
||||||
$this->loginHelper('admin');
|
$this->loginHelper('admin');
|
||||||
|
|
||||||
// check if share key not exists
|
// check if share key not exists
|
||||||
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user2.shareKey'));
|
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user2.shareKey'));
|
||||||
|
|
||||||
// unshare the file with user1
|
// unshare the file with user1
|
||||||
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1');
|
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1');
|
||||||
|
|
||||||
// check if share key not exists
|
// check if share key not exists
|
||||||
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey'));
|
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey'));
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
$this->view->unlink('/admin/files/' . $this->filename);
|
$this->view->unlink('/admin/files/' . $this->filename);
|
||||||
|
|
||||||
// check if share key not exists
|
// check if share key not exists
|
||||||
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey'));
|
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $withTeardown
|
* @param bool $withTeardown
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
function testShareFolder($withTeardown = true)
|
function testShareFolder($withTeardown = true)
|
||||||
{
|
{
|
||||||
// login as admin
|
// login as admin
|
||||||
$this->loginHelper('admin');
|
$this->loginHelper('admin');
|
||||||
|
|
||||||
// create folder structure
|
// create folder structure
|
||||||
$this->view->mkdir('/admin/files' . $this->folder1);
|
$this->view->mkdir('/admin/files' . $this->folder1);
|
||||||
$this->view->mkdir('/admin/files' . $this->folder1 . $this->subfolder);
|
$this->view->mkdir('/admin/files' . $this->folder1 . $this->subfolder);
|
||||||
$this->view->mkdir('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder);
|
$this->view->mkdir('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder);
|
||||||
|
|
||||||
// save file with content
|
// save file with content
|
||||||
$cryptedFile = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename, $this->dataShort);
|
$cryptedFile = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename, $this->dataShort);
|
||||||
|
|
||||||
// test that data was successfully written
|
// test that data was successfully written
|
||||||
$this->assertTrue(is_int($cryptedFile));
|
$this->assertTrue(is_int($cryptedFile));
|
||||||
|
|
||||||
// disable encryption proxy to prevent recursive calls
|
// disable encryption proxy to prevent recursive calls
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
// get the file info from previous created folder
|
// get the file info from previous created folder
|
||||||
$fileInfo = $this->view->getFileInfo('/admin/files' . $this->folder1);
|
$fileInfo = $this->view->getFileInfo('/admin/files' . $this->folder1);
|
||||||
|
|
||||||
// check if we have a valid file info
|
// check if we have a valid file info
|
||||||
$this->assertTrue(is_array($fileInfo));
|
$this->assertTrue(is_array($fileInfo));
|
||||||
|
|
||||||
// re-enable the file proxy
|
// re-enable the file proxy
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
// share the folder with user1
|
// share the folder with user1
|
||||||
\OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1', OCP\PERMISSION_ALL);
|
\OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1', OCP\PERMISSION_ALL);
|
||||||
|
|
||||||
// login as admin
|
// login as admin
|
||||||
$this->loginHelper('admin');
|
$this->loginHelper('admin');
|
||||||
|
|
||||||
// check if share key for user1 exists
|
// check if share key for user1 exists
|
||||||
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey'));
|
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey'));
|
||||||
|
|
||||||
// login as user1
|
// login as user1
|
||||||
$this->loginHelper('user1');
|
$this->loginHelper('user1');
|
||||||
|
|
||||||
// get file contents
|
// get file contents
|
||||||
$retrievedCryptedFile = $this->view->file_get_contents('/user1/files/Shared' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
|
$retrievedCryptedFile = $this->view->file_get_contents('/user1/files/Shared' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
|
||||||
|
|
||||||
// check if data is the same
|
// check if data is the same
|
||||||
$this->assertEquals($this->dataShort, $retrievedCryptedFile);
|
$this->assertEquals($this->dataShort, $retrievedCryptedFile);
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
if ($withTeardown) {
|
if ($withTeardown) {
|
||||||
|
|
||||||
// login as admin
|
// login as admin
|
||||||
$this->loginHelper('admin');
|
$this->loginHelper('admin');
|
||||||
|
|
||||||
// unshare the folder with user1
|
// unshare the folder with user1
|
||||||
\OCP\Share::unshare('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1');
|
\OCP\Share::unshare('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1');
|
||||||
|
|
||||||
// check if share key not exists
|
// check if share key not exists
|
||||||
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey'));
|
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey'));
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
$this->view->unlink('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
|
$this->view->unlink('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
|
||||||
|
|
||||||
// check if share key not exists
|
// check if share key not exists
|
||||||
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey'));
|
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $fileInfo;
|
return $fileInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $withTeardown
|
* @param bool $withTeardown
|
||||||
*/
|
*/
|
||||||
function testReShareFolder($withTeardown = true)
|
function testReShareFolder($withTeardown = true)
|
||||||
{
|
{
|
||||||
$fileInfoFolder1 = $this->testShareFolder(false);
|
$fileInfoFolder1 = $this->testShareFolder(false);
|
||||||
|
|
||||||
// login as user1
|
// login as user1
|
||||||
$this->loginHelper('user1');
|
$this->loginHelper('user1');
|
||||||
|
|
||||||
// disable encryption proxy to prevent recursive calls
|
// disable encryption proxy to prevent recursive calls
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
// get the file info from previous created folder
|
// get the file info from previous created folder
|
||||||
$fileInfoSubFolder = $this->view->getFileInfo('/user1/files/Shared' . $this->folder1 . $this->subfolder);
|
$fileInfoSubFolder = $this->view->getFileInfo('/user1/files/Shared' . $this->folder1 . $this->subfolder);
|
||||||
|
|
||||||
// check if we have a valid file info
|
// check if we have a valid file info
|
||||||
$this->assertTrue(is_array($fileInfoSubFolder));
|
$this->assertTrue(is_array($fileInfoSubFolder));
|
||||||
|
|
||||||
// re-enable the file proxy
|
// re-enable the file proxy
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
// share the file with user2
|
// share the file with user2
|
||||||
\OCP\Share::shareItem('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2', OCP\PERMISSION_ALL);
|
\OCP\Share::shareItem('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2', OCP\PERMISSION_ALL);
|
||||||
|
|
||||||
// login as admin
|
// login as admin
|
||||||
$this->loginHelper('admin');
|
$this->loginHelper('admin');
|
||||||
|
|
||||||
// check if share key for user2 exists
|
// check if share key for user2 exists
|
||||||
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user2.shareKey'));
|
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user2.shareKey'));
|
||||||
|
|
||||||
// login as user2
|
// login as user2
|
||||||
$this->loginHelper('user2');
|
$this->loginHelper('user2');
|
||||||
|
|
||||||
// get file contents
|
// get file contents
|
||||||
$retrievedCryptedFile = $this->view->file_get_contents('/user2/files/Shared' . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
|
$retrievedCryptedFile = $this->view->file_get_contents('/user2/files/Shared' . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
|
||||||
|
|
||||||
// check if data is the same
|
// check if data is the same
|
||||||
$this->assertEquals($this->dataShort, $retrievedCryptedFile);
|
$this->assertEquals($this->dataShort, $retrievedCryptedFile);
|
||||||
|
|
||||||
// get the file info
|
// get the file info
|
||||||
$fileInfo = $this->view->getFileInfo('/user2/files/Shared' . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
|
$fileInfo = $this->view->getFileInfo('/user2/files/Shared' . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
|
||||||
|
|
||||||
// check if we have fileInfos
|
// check if we have fileInfos
|
||||||
$this->assertTrue(is_array($fileInfo));
|
$this->assertTrue(is_array($fileInfo));
|
||||||
|
|
||||||
// share the file with user3
|
// share the file with user3
|
||||||
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user3', OCP\PERMISSION_ALL);
|
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user3', OCP\PERMISSION_ALL);
|
||||||
|
|
||||||
// login as admin
|
// login as admin
|
||||||
$this->loginHelper('admin');
|
$this->loginHelper('admin');
|
||||||
|
|
||||||
// check if share key for user3 exists
|
// check if share key for user3 exists
|
||||||
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user3.shareKey'));
|
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user3.shareKey'));
|
||||||
|
|
||||||
// login as user3
|
// login as user3
|
||||||
$this->loginHelper('user3');
|
$this->loginHelper('user3');
|
||||||
|
|
||||||
// get file contents
|
// get file contents
|
||||||
$retrievedCryptedFile = $this->view->file_get_contents('/user3/files/Shared/' . $this->filename);
|
$retrievedCryptedFile = $this->view->file_get_contents('/user3/files/Shared/' . $this->filename);
|
||||||
|
|
||||||
// check if data is the same
|
// check if data is the same
|
||||||
$this->assertEquals($this->dataShort, $retrievedCryptedFile);
|
$this->assertEquals($this->dataShort, $retrievedCryptedFile);
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
if ($withTeardown) {
|
if ($withTeardown) {
|
||||||
|
|
||||||
// login as user2
|
// login as user2
|
||||||
$this->loginHelper('user2');
|
$this->loginHelper('user2');
|
||||||
|
|
||||||
// unshare the file with user3
|
// unshare the file with user3
|
||||||
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user3');
|
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user3');
|
||||||
|
|
||||||
// check if share key not exists
|
// check if share key not exists
|
||||||
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user3.shareKey'));
|
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user3.shareKey'));
|
||||||
|
|
||||||
// login as user1
|
// login as user1
|
||||||
$this->loginHelper('user1');
|
$this->loginHelper('user1');
|
||||||
|
|
||||||
// unshare the folder with user2
|
// unshare the folder with user2
|
||||||
\OCP\Share::unshare('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2');
|
\OCP\Share::unshare('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2');
|
||||||
|
|
||||||
// check if share key not exists
|
// check if share key not exists
|
||||||
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user2.shareKey'));
|
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user2.shareKey'));
|
||||||
|
|
||||||
// login as admin
|
// login as admin
|
||||||
$this->loginHelper('admin');
|
$this->loginHelper('admin');
|
||||||
|
|
||||||
// unshare the folder1 with user1
|
// unshare the folder1 with user1
|
||||||
\OCP\Share::unshare('folder', $fileInfoFolder1['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1');
|
\OCP\Share::unshare('folder', $fileInfoFolder1['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1');
|
||||||
|
|
||||||
// check if share key not exists
|
// check if share key not exists
|
||||||
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey'));
|
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey'));
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
$this->view->unlink('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
|
$this->view->unlink('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
|
||||||
|
|
||||||
// check if share key not exists
|
// check if share key not exists
|
||||||
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey'));
|
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function testPublicShareFile()
|
function testPublicShareFile()
|
||||||
{
|
{
|
||||||
// login as admin
|
// login as admin
|
||||||
$this->loginHelper('admin');
|
$this->loginHelper('admin');
|
||||||
|
|
||||||
// save file with content
|
// save file with content
|
||||||
$cryptedFile = file_put_contents('crypt://' . $this->filename, $this->dataShort);
|
$cryptedFile = file_put_contents('crypt://' . $this->filename, $this->dataShort);
|
||||||
|
|
||||||
// test that data was successfully written
|
// test that data was successfully written
|
||||||
$this->assertTrue(is_int($cryptedFile));
|
$this->assertTrue(is_int($cryptedFile));
|
||||||
|
|
||||||
// disable encryption proxy to prevent recursive calls
|
// disable encryption proxy to prevent recursive calls
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
\OC_FileProxy::$enabled = false;
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
// get the file info from previous created file
|
// get the file info from previous created file
|
||||||
$fileInfo = $this->view->getFileInfo('/admin/files/' . $this->filename);
|
$fileInfo = $this->view->getFileInfo('/admin/files/' . $this->filename);
|
||||||
|
|
||||||
// check if we have a valid file info
|
// check if we have a valid file info
|
||||||
$this->assertTrue(is_array($fileInfo));
|
$this->assertTrue(is_array($fileInfo));
|
||||||
|
|
||||||
// check if the unencrypted file size is stored
|
// check if the unencrypted file size is stored
|
||||||
$this->assertGreaterThan(0, $fileInfo['unencrypted_size']);
|
$this->assertGreaterThan(0, $fileInfo['unencrypted_size']);
|
||||||
|
|
||||||
// re-enable the file proxy
|
// re-enable the file proxy
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
// share the file
|
// share the file
|
||||||
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, false, OCP\PERMISSION_ALL);
|
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, false, OCP\PERMISSION_ALL);
|
||||||
|
|
||||||
// login as admin
|
// login as admin
|
||||||
$this->loginHelper('admin');
|
$this->loginHelper('admin');
|
||||||
|
|
||||||
$publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId');
|
$publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId');
|
||||||
|
|
||||||
// check if share key for public exists
|
// check if share key for public exists
|
||||||
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $publicShareKeyId . '.shareKey'));
|
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $publicShareKeyId . '.shareKey'));
|
||||||
|
|
||||||
// some hacking to simulate public link
|
// some hacking to simulate public link
|
||||||
$GLOBALS['app'] = 'files_sharing';
|
$GLOBALS['app'] = 'files_sharing';
|
||||||
$GLOBALS['fileOwner'] = 'admin';
|
$GLOBALS['fileOwner'] = 'admin';
|
||||||
\OC_User::setUserId('');
|
\OC_User::setUserId('');
|
||||||
|
|
||||||
// get file contents
|
// get file contents
|
||||||
$retrievedCryptedFile = file_get_contents('crypt://' . $this->filename);
|
$retrievedCryptedFile = file_get_contents('crypt://' . $this->filename);
|
||||||
|
|
||||||
// check if data is the same as we previously written
|
// check if data is the same as we previously written
|
||||||
$this->assertEquals($this->dataShort, $retrievedCryptedFile);
|
$this->assertEquals($this->dataShort, $retrievedCryptedFile);
|
||||||
|
|
||||||
// tear down
|
// tear down
|
||||||
|
|
||||||
// login as admin
|
// login as admin
|
||||||
$this->loginHelper('admin');
|
$this->loginHelper('admin');
|
||||||
|
|
||||||
// unshare the file
|
// unshare the file
|
||||||
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
|
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
|
||||||
|
|
||||||
// check if share key not exists
|
// check if share key not exists
|
||||||
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $publicShareKeyId . '.shareKey'));
|
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $publicShareKeyId . '.shareKey'));
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
$this->view->unlink('/admin/files/' . $this->filename);
|
$this->view->unlink('/admin/files/' . $this->filename);
|
||||||
|
|
||||||
// check if share key not exists
|
// check if share key not exists
|
||||||
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey'));
|
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function testShareFileWithGroup()
|
function testShareFileWithGroup()
|
||||||
{
|
{
|
||||||
|
@ -581,7 +581,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
// save file with content
|
// save file with content
|
||||||
$cryptedFile1 = file_put_contents('crypt://' . $this->filename, $this->dataShort);
|
$cryptedFile1 = file_put_contents('crypt://' . $this->filename, $this->dataShort);
|
||||||
$cryptedFile2 = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename, $this->dataShort);
|
$cryptedFile2 = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename, $this->dataShort);
|
||||||
|
|
||||||
// test that data was successfully written
|
// test that data was successfully written
|
||||||
$this->assertTrue(is_int($cryptedFile1));
|
$this->assertTrue(is_int($cryptedFile1));
|
||||||
|
@ -589,9 +589,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
// check if share key for admin and recovery exists
|
// check if share key for admin and recovery exists
|
||||||
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey'));
|
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey'));
|
||||||
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey'));
|
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
|
||||||
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.admin.shareKey'));
|
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey'));
|
||||||
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey'));
|
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
|
||||||
|
|
||||||
// disable recovery for admin
|
// disable recovery for admin
|
||||||
$this->assertTrue($util->setRecoveryForUser(0));
|
$this->assertTrue($util->setRecoveryForUser(0));
|
||||||
|
@ -600,8 +600,8 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase
|
||||||
$util->removeRecoveryKeys('/');
|
$util->removeRecoveryKeys('/');
|
||||||
|
|
||||||
// check if share key for recovery not exists
|
// check if share key for recovery not exists
|
||||||
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey'));
|
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
|
||||||
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey'));
|
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
|
||||||
|
|
||||||
// enable recovery for admin
|
// enable recovery for admin
|
||||||
$this->assertTrue($util->setRecoveryForUser(1));
|
$this->assertTrue($util->setRecoveryForUser(1));
|
||||||
|
@ -610,16 +610,16 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase
|
||||||
$util->addRecoveryKeys('/');
|
$util->addRecoveryKeys('/');
|
||||||
|
|
||||||
// check if share key for admin and recovery exists
|
// check if share key for admin and recovery exists
|
||||||
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey'));
|
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
|
||||||
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey'));
|
$this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
$this->view->unlink('/admin/files/' . $this->filename);
|
$this->view->unlink('/admin/files/' . $this->filename);
|
||||||
$this->view->unlink('/admin/files/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename);
|
$this->view->unlink('/admin/files/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
|
||||||
|
|
||||||
// check if share key for recovery not exists
|
// check if share key for recovery not exists
|
||||||
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey'));
|
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
|
||||||
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey'));
|
$this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function testRecoveryForUser()
|
function testRecoveryForUser()
|
||||||
|
@ -648,7 +648,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
// save file with content
|
// save file with content
|
||||||
$cryptedFile1 = file_put_contents('crypt://' . $this->filename, $this->dataShort);
|
$cryptedFile1 = file_put_contents('crypt://' . $this->filename, $this->dataShort);
|
||||||
$cryptedFile2 = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename, $this->dataShort);
|
$cryptedFile2 = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename, $this->dataShort);
|
||||||
|
|
||||||
// test that data was successfully written
|
// test that data was successfully written
|
||||||
$this->assertTrue(is_int($cryptedFile1));
|
$this->assertTrue(is_int($cryptedFile1));
|
||||||
|
@ -656,9 +656,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
// check if share key for user and recovery exists
|
// check if share key for user and recovery exists
|
||||||
$this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.user1.shareKey'));
|
$this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.user1.shareKey'));
|
||||||
$this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey'));
|
$this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
|
||||||
$this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.user1.shareKey'));
|
$this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey'));
|
||||||
$this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey'));
|
$this->assertTrue($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
|
||||||
|
|
||||||
// login as admin
|
// login as admin
|
||||||
$this->loginHelper('admin');
|
$this->loginHelper('admin');
|
||||||
|
@ -671,7 +671,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
// get file contents
|
// get file contents
|
||||||
$retrievedCryptedFile1 = file_get_contents('crypt://' . $this->filename);
|
$retrievedCryptedFile1 = file_get_contents('crypt://' . $this->filename);
|
||||||
$retrievedCryptedFile2 = file_get_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename);
|
$retrievedCryptedFile2 = file_get_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
|
||||||
|
|
||||||
// check if data is the same as we previously written
|
// check if data is the same as we previously written
|
||||||
$this->assertEquals($this->dataShort, $retrievedCryptedFile1);
|
$this->assertEquals($this->dataShort, $retrievedCryptedFile1);
|
||||||
|
@ -683,9 +683,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
// check if share key for user and recovery exists
|
// check if share key for user and recovery exists
|
||||||
$this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.user1.shareKey'));
|
$this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.user1.shareKey'));
|
||||||
$this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.'.$recoveryKeyId.'.shareKey'));
|
$this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
|
||||||
$this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.user1.shareKey'));
|
$this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey'));
|
||||||
$this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder .'/'. $this->filename . '.'.$recoveryKeyId.'.shareKey'));
|
$this->assertFalse($this->view->file_exists('/user1/files_encryption/share-keys/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
|
||||||
|
|
||||||
// enable recovery for admin
|
// enable recovery for admin
|
||||||
$this->assertTrue($util->setRecoveryForUser(0));
|
$this->assertTrue($util->setRecoveryForUser(0));
|
||||||
|
@ -697,23 +697,23 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase
|
||||||
* @param bool $password
|
* @param bool $password
|
||||||
*/
|
*/
|
||||||
function loginHelper($user, $create = false, $password = false)
|
function loginHelper($user, $create = false, $password = false)
|
||||||
{
|
{
|
||||||
if ($create) {
|
if ($create) {
|
||||||
\OC_User::createUser($user, $user);
|
\OC_User::createUser($user, $user);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($password === false) {
|
if ($password === false) {
|
||||||
$password = $user;
|
$password = $user;
|
||||||
}
|
}
|
||||||
|
|
||||||
\OC_Util::tearDownFS();
|
\OC_Util::tearDownFS();
|
||||||
\OC_User::setUserId('');
|
\OC_User::setUserId('');
|
||||||
\OC\Files\Filesystem::tearDown();
|
\OC\Files\Filesystem::tearDown();
|
||||||
\OC_Util::setupFS($user);
|
\OC_Util::setupFS($user);
|
||||||
\OC_User::setUserId($user);
|
\OC_User::setUserId($user);
|
||||||
|
|
||||||
$params['uid'] = $user;
|
$params['uid'] = $user;
|
||||||
$params['password'] = $password;
|
$params['password'] = $password;
|
||||||
OCA\Encryption\Hooks::login($params);
|
OCA\Encryption\Hooks::login($params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,20 +6,21 @@
|
||||||
* See the COPYING-README file.
|
* See the COPYING-README file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once realpath( dirname(__FILE__).'/../../../lib/base.php' );
|
require_once realpath(dirname(__FILE__) . '/../../../lib/base.php');
|
||||||
require_once realpath( dirname(__FILE__).'/../lib/crypt.php' );
|
require_once realpath(dirname(__FILE__) . '/../lib/crypt.php');
|
||||||
require_once realpath( dirname(__FILE__).'/../lib/keymanager.php' );
|
require_once realpath(dirname(__FILE__) . '/../lib/keymanager.php');
|
||||||
require_once realpath( dirname(__FILE__).'/../lib/proxy.php' );
|
require_once realpath(dirname(__FILE__) . '/../lib/proxy.php');
|
||||||
require_once realpath( dirname(__FILE__).'/../lib/stream.php' );
|
require_once realpath(dirname(__FILE__) . '/../lib/stream.php');
|
||||||
require_once realpath( dirname(__FILE__).'/../lib/util.php' );
|
require_once realpath(dirname(__FILE__) . '/../lib/util.php');
|
||||||
require_once realpath( dirname(__FILE__).'/../appinfo/app.php' );
|
require_once realpath(dirname(__FILE__) . '/../appinfo/app.php');
|
||||||
|
|
||||||
use OCA\Encryption;
|
use OCA\Encryption;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Test_Encryption_Util
|
* Class Test_Encryption_Util
|
||||||
*/
|
*/
|
||||||
class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
class Test_Encryption_Util extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
|
||||||
public $userId;
|
public $userId;
|
||||||
public $encryptionDir;
|
public $encryptionDir;
|
||||||
|
@ -38,132 +39,139 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||||
public $util;
|
public $util;
|
||||||
public $dataShort;
|
public $dataShort;
|
||||||
|
|
||||||
function setUp() {
|
function setUp()
|
||||||
// reset backend
|
{
|
||||||
\OC_User::useBackend('database');
|
// reset backend
|
||||||
|
\OC_User::useBackend('database');
|
||||||
|
|
||||||
\OC_User::setUserId( 'admin' );
|
\OC_User::setUserId('admin');
|
||||||
$this->userId = 'admin';
|
$this->userId = 'admin';
|
||||||
$this->pass = 'admin';
|
$this->pass = 'admin';
|
||||||
|
|
||||||
// set content for encrypting / decrypting in tests
|
// set content for encrypting / decrypting in tests
|
||||||
$this->dataUrl = realpath( dirname(__FILE__).'/../lib/crypt.php' );
|
$this->dataUrl = realpath(dirname(__FILE__) . '/../lib/crypt.php');
|
||||||
$this->dataShort = 'hats';
|
$this->dataShort = 'hats';
|
||||||
$this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) );
|
$this->dataLong = file_get_contents(realpath(dirname(__FILE__) . '/../lib/crypt.php'));
|
||||||
$this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' );
|
$this->legacyData = realpath(dirname(__FILE__) . '/legacy-text.txt');
|
||||||
$this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' );
|
$this->legacyEncryptedData = realpath(dirname(__FILE__) . '/legacy-encrypted-text.txt');
|
||||||
|
|
||||||
$keypair = Encryption\Crypt::createKeypair();
|
$keypair = Encryption\Crypt::createKeypair();
|
||||||
|
|
||||||
$this->genPublicKey = $keypair['publicKey'];
|
$this->genPublicKey = $keypair['publicKey'];
|
||||||
$this->genPrivateKey = $keypair['privateKey'];
|
$this->genPrivateKey = $keypair['privateKey'];
|
||||||
|
|
||||||
$this->publicKeyDir = '/' . 'public-keys';
|
$this->publicKeyDir = '/' . 'public-keys';
|
||||||
$this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption';
|
$this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption';
|
||||||
$this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles';
|
$this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles';
|
||||||
$this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key
|
$this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key
|
||||||
$this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key
|
$this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key
|
||||||
|
|
||||||
$this->view = new \OC_FilesystemView( '/' );
|
$this->view = new \OC_FilesystemView('/');
|
||||||
|
|
||||||
$userHome = \OC_User::getHome($this->userId);
|
$userHome = \OC_User::getHome($this->userId);
|
||||||
$this->dataDir = str_replace('/'.$this->userId, '', $userHome);
|
$this->dataDir = str_replace('/' . $this->userId, '', $userHome);
|
||||||
|
|
||||||
// Filesystem related hooks
|
// Filesystem related hooks
|
||||||
\OCA\Encryption\Helper::registerFilesystemHooks();
|
\OCA\Encryption\Helper::registerFilesystemHooks();
|
||||||
|
|
||||||
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
||||||
|
|
||||||
\OC_Util::tearDownFS();
|
\OC_Util::tearDownFS();
|
||||||
\OC_User::setUserId('');
|
\OC_User::setUserId('');
|
||||||
\OC\Files\Filesystem::tearDown();
|
\OC\Files\Filesystem::tearDown();
|
||||||
\OC_Util::setupFS($this->userId);
|
\OC_Util::setupFS($this->userId);
|
||||||
\OC_User::setUserId($this->userId);
|
\OC_User::setUserId($this->userId);
|
||||||
|
|
||||||
$params['uid'] = $this->userId;
|
$params['uid'] = $this->userId;
|
||||||
$params['password'] = $this->pass;
|
$params['password'] = $this->pass;
|
||||||
OCA\Encryption\Hooks::login($params);
|
OCA\Encryption\Hooks::login($params);
|
||||||
|
|
||||||
$this->util = new Encryption\Util( $this->view, $this->userId );
|
$this->util = new Encryption\Util($this->view, $this->userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function tearDown(){
|
function tearDown()
|
||||||
|
{
|
||||||
|
|
||||||
\OC_FileProxy::clearProxies();
|
\OC_FileProxy::clearProxies();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief test that paths set during User construction are correct
|
* @brief test that paths set during User construction are correct
|
||||||
*/
|
*/
|
||||||
function testKeyPaths() {
|
function testKeyPaths()
|
||||||
|
{
|
||||||
$util = new Encryption\Util( $this->view, $this->userId );
|
|
||||||
|
$util = new Encryption\Util($this->view, $this->userId);
|
||||||
$this->assertEquals( $this->publicKeyDir, $util->getPath( 'publicKeyDir' ) );
|
|
||||||
$this->assertEquals( $this->encryptionDir, $util->getPath( 'encryptionDir' ) );
|
$this->assertEquals($this->publicKeyDir, $util->getPath('publicKeyDir'));
|
||||||
$this->assertEquals( $this->keyfilesPath, $util->getPath( 'keyfilesPath' ) );
|
$this->assertEquals($this->encryptionDir, $util->getPath('encryptionDir'));
|
||||||
$this->assertEquals( $this->publicKeyPath, $util->getPath( 'publicKeyPath' ) );
|
$this->assertEquals($this->keyfilesPath, $util->getPath('keyfilesPath'));
|
||||||
$this->assertEquals( $this->privateKeyPath, $util->getPath( 'privateKeyPath' ) );
|
$this->assertEquals($this->publicKeyPath, $util->getPath('publicKeyPath'));
|
||||||
|
$this->assertEquals($this->privateKeyPath, $util->getPath('privateKeyPath'));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief test setup of encryption directories
|
* @brief test setup of encryption directories
|
||||||
*/
|
*/
|
||||||
function testSetupServerSide() {
|
function testSetupServerSide()
|
||||||
|
{
|
||||||
$this->assertEquals( true, $this->util->setupServerSide( $this->pass ) );
|
|
||||||
|
$this->assertEquals(true, $this->util->setupServerSide($this->pass));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief test checking whether account is ready for encryption,
|
* @brief test checking whether account is ready for encryption,
|
||||||
*/
|
*/
|
||||||
function testUserIsReady() {
|
function testUserIsReady()
|
||||||
|
{
|
||||||
$this->assertEquals( true, $this->util->ready() );
|
|
||||||
|
$this->assertEquals(true, $this->util->ready());
|
||||||
}
|
}
|
||||||
|
|
||||||
function testRecoveryEnabledForUser() {
|
function testRecoveryEnabledForUser()
|
||||||
|
{
|
||||||
$util = new Encryption\Util( $this->view, $this->userId );
|
|
||||||
|
$util = new Encryption\Util($this->view, $this->userId);
|
||||||
|
|
||||||
// Record the value so we can return it to it's original state later
|
// Record the value so we can return it to it's original state later
|
||||||
$enabled = $util->recoveryEnabledForUser();
|
$enabled = $util->recoveryEnabledForUser();
|
||||||
|
|
||||||
$this->assertTrue( $util->setRecoveryForUser( 1 ) );
|
$this->assertTrue($util->setRecoveryForUser(1));
|
||||||
|
|
||||||
$this->assertEquals( 1, $util->recoveryEnabledForUser() );
|
$this->assertEquals(1, $util->recoveryEnabledForUser());
|
||||||
|
|
||||||
$this->assertTrue( $util->setRecoveryForUser( 0 ) );
|
$this->assertTrue($util->setRecoveryForUser(0));
|
||||||
|
|
||||||
$this->assertEquals( 0, $util->recoveryEnabledForUser() );
|
$this->assertEquals(0, $util->recoveryEnabledForUser());
|
||||||
|
|
||||||
// Return the setting to it's previous state
|
// Return the setting to it's previous state
|
||||||
$this->assertTrue( $util->setRecoveryForUser( $enabled ) );
|
$this->assertTrue($util->setRecoveryForUser($enabled));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testGetUidAndFilename() {
|
|
||||||
|
|
||||||
\OC_User::setUserId( 'admin' );
|
|
||||||
|
|
||||||
$filename = 'tmp-'.time().'.test';
|
function testGetUidAndFilename()
|
||||||
|
{
|
||||||
|
|
||||||
// Disable encryption proxy to prevent recursive calls
|
\OC_User::setUserId('admin');
|
||||||
$proxyStatus = \OC_FileProxy::$enabled;
|
|
||||||
\OC_FileProxy::$enabled = false;
|
|
||||||
|
|
||||||
$this->view->file_put_contents($this->userId . '/files/' . $filename, $this->dataShort);
|
$filename = 'tmp-' . time() . '.test';
|
||||||
|
|
||||||
// Re-enable proxy - our work is done
|
// Disable encryption proxy to prevent recursive calls
|
||||||
\OC_FileProxy::$enabled = $proxyStatus;
|
$proxyStatus = \OC_FileProxy::$enabled;
|
||||||
|
\OC_FileProxy::$enabled = false;
|
||||||
|
|
||||||
$util = new Encryption\Util( $this->view, $this->userId );
|
$this->view->file_put_contents($this->userId . '/files/' . $filename, $this->dataShort);
|
||||||
|
|
||||||
list($fileOwnerUid, $file) = $util->getUidAndFilename( $filename );
|
// Re-enable proxy - our work is done
|
||||||
|
\OC_FileProxy::$enabled = $proxyStatus;
|
||||||
|
|
||||||
$this->assertEquals('admin', $fileOwnerUid);
|
$util = new Encryption\Util($this->view, $this->userId);
|
||||||
|
|
||||||
$this->assertEquals($file, $filename);
|
list($fileOwnerUid, $file) = $util->getUidAndFilename($filename);
|
||||||
|
|
||||||
|
$this->assertEquals('admin', $fileOwnerUid);
|
||||||
|
|
||||||
|
$this->assertEquals($file, $filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue