@@ -80,7 +80,12 @@ class Encryption extends \OCP\AppFramework\App { | |||
$hookManager = new HookManager(); | |||
$hookManager->registerHook([ | |||
new UserHooks($container->query('KeyManager'), $server->getLogger(), $container->query('UserSetup'), $server->getUserSession(), new \OCP\Util(), $container->query('Util')), | |||
new UserHooks($container->query('KeyManager'), | |||
$server->getLogger(), | |||
$container->query('UserSetup'), | |||
$server->getUserSession(), | |||
new \OCP\Util(), | |||
$container->query('Util'),), | |||
]); | |||
$hookManager->fireHooks(); | |||
@@ -126,7 +131,6 @@ class Encryption extends \OCP\AppFramework\App { | |||
$server->getConfig(), | |||
$server->getUserSession(), | |||
$server->getSession(), | |||
$server->getMemCacheFactory(), | |||
$server->getLogger() | |||
); | |||
}); |
@@ -0,0 +1,10 @@ | |||
/* Copyright (c) 2013, Sam Tuke, <samtuke@owncloud.com> | |||
This file is licensed under the Affero General Public License version 3 or later. | |||
See the COPYING-README file. */ | |||
#encryptAllError | |||
, #encryptAllSuccess | |||
, #recoveryEnabledError | |||
, #recoveryEnabledSuccess { | |||
display: none; | |||
} |
@@ -1,37 +0,0 @@ | |||
<?php | |||
/** | |||
* @author Clark Tomlinson <clark@owncloud.com> | |||
* @since 2/19/15, 10:02 AM | |||
* @copyright Copyright (c) 2015, ownCloud, Inc. | |||
* @license AGPL-3.0 | |||
* | |||
* This code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License, version 3, | |||
* as published by the Free Software Foundation. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public License, version 3, | |||
* along with this program. If not, see <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
namespace OCA\Encryption\Hooks; | |||
use OCA\Encryption\Hooks\Contracts\IHook; | |||
use OCP\Util; | |||
class AppHooks implements IHook { | |||
/** | |||
* Connects Hooks | |||
* | |||
* @return null | |||
*/ | |||
public function addHooks() { | |||
Util::connectHook('OC_App', 'pre_disable', 'OCA\Encryption\Hooks', 'preDisable'); | |||
Util::connectHook('OC_App', 'post_disable', 'OCA\Encryption\Hooks', 'postEnable'); | |||
} | |||
} |
@@ -1,46 +0,0 @@ | |||
<?php | |||
/** | |||
* @author Clark Tomlinson <clark@owncloud.com> | |||
* @since 2/19/15, 10:02 AM | |||
* @copyright Copyright (c) 2015, ownCloud, Inc. | |||
* @license AGPL-3.0 | |||
* | |||
* This code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License, version 3, | |||
* as published by the Free Software Foundation. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public License, version 3, | |||
* along with this program. If not, see <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
namespace OCA\Encryption\Hooks; | |||
use OCA\Encryption\Hooks\Contracts\IHook; | |||
use OCP\Util; | |||
class FileSystemHooks implements IHook { | |||
/** | |||
* Connects Hooks | |||
* | |||
* @return null | |||
*/ | |||
public function addHooks() { | |||
Util::connectHook('OC_Filesystem', 'rename', 'OCA\Encryption\Hooks', 'preRename'); | |||
Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRenameOrCopy'); | |||
Util::connectHook('OC_Filesystem', 'copy', 'OCA\Encryption\Hooks', 'preCopy'); | |||
Util::connectHook('OC_Filesystem', 'post_copy', 'OCA\Encryption\Hooks', 'postRenameOrCopy'); | |||
Util::connectHook('OC_Filesystem', 'post_delete', 'OCA\Encryption\Hooks', 'postDelete'); | |||
Util::connectHook('OC_Filesystem', 'delete', 'OCA\Encryption\Hooks', 'preDelete'); | |||
Util::connectHook('\OC\Core\LostPassword\Controller\LostController', 'post_passwordReset', 'OCA\Encryption\Hooks', 'postPasswordReset'); | |||
Util::connectHook('OC_Filesystem', 'post_umount', 'OCA\Encryption\Hooks', 'postUnmount'); | |||
Util::connectHook('OC_Filesystem', 'umount', 'OCA\Encryption\Hooks', 'preUnmount'); | |||
} | |||
} |
@@ -1,40 +0,0 @@ | |||
<?php | |||
/** | |||
* @author Clark Tomlinson <clark@owncloud.com> | |||
* @since 2/19/15, 10:02 AM | |||
* @copyright Copyright (c) 2015, ownCloud, Inc. | |||
* @license AGPL-3.0 | |||
* | |||
* This code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License, version 3, | |||
* as published by the Free Software Foundation. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public License, version 3, | |||
* along with this program. If not, see <http://www.gnu.org/licenses/> | |||
* | |||
*/ | |||
namespace OCA\Encryption\Hooks; | |||
use OCA\Encryption\Hooks\Contracts\IHook; | |||
use OCP\Util; | |||
class ShareHooks implements IHook { | |||
/** | |||
* Connects Hooks | |||
* | |||
* @return null | |||
*/ | |||
public function addHooks() { | |||
Util::connectHook('OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared'); | |||
Util::connectHook('OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared'); | |||
Util::connectHook('OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare'); | |||
} | |||
} |
@@ -22,6 +22,7 @@ | |||
namespace OCA\Encryption\Hooks; | |||
use OCP\ISession; | |||
use OCP\Util as OCUtil; | |||
use OCA\Encryption\Hooks\Contracts\IHook; | |||
use OCA\Encryption\KeyManager; | |||
@@ -53,6 +54,10 @@ class UserHooks implements IHook { | |||
* @var Util | |||
*/ | |||
private $util; | |||
/** | |||
* @var ISession | |||
*/ | |||
private $session; | |||
/** | |||
* UserHooks constructor. | |||
@@ -63,15 +68,22 @@ class UserHooks implements IHook { | |||
* @param IUserSession $user | |||
* @param OCUtil $ocUtil | |||
* @param Util $util | |||
* @param ISession $session | |||
*/ | |||
public function __construct( | |||
KeyManager $keyManager, ILogger $logger, Setup $userSetup, IUserSession $user, OCUtil $ocUtil, Util $util) { | |||
public function __construct(KeyManager $keyManager, | |||
ILogger $logger, | |||
Setup $userSetup, | |||
IUserSession $user, | |||
OCUtil $ocUtil, | |||
Util $util, | |||
ISession $session) { | |||
$this->keyManager = $keyManager; | |||
$this->logger = $logger; | |||
$this->userSetup = $userSetup; | |||
$this->user = $user; | |||
$this->util = $util; | |||
$this->session = $session; | |||
} | |||
/** | |||
@@ -132,7 +144,7 @@ class UserHooks implements IHook { | |||
* remove keys from session during logout | |||
*/ | |||
public function logout() { | |||
KeyManager::$cacheFactory->clear(); | |||
KeyManager::$session->clear(); | |||
} | |||
/** |
@@ -0,0 +1,33 @@ | |||
/** | |||
* Copyright (c) 2013 | |||
* Bjoern Schiessle <schiessle@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or later. | |||
* See the COPYING-README file. | |||
*/ | |||
$(document).ready(function(){ | |||
$('form[name="login"]').on('submit', function() { | |||
var user = $('#user').val(); | |||
var password = $('#password').val(); | |||
$.ajax({ | |||
type: 'POST', | |||
url: OC.linkTo('files_encryption', 'ajax/getMigrationStatus.php'), | |||
dataType: 'json', | |||
data: {user: user, password: password}, | |||
async: false, | |||
success: function(response) { | |||
if (response.data.migrationStatus === OC.Encryption.MIGRATION_OPEN) { | |||
var message = t('files_encryption', 'Initial encryption started... This can take some time. Please wait.'); | |||
$('#messageText').text(message); | |||
$('#message').removeClass('hidden').addClass('update'); | |||
} else if (response.data.migrationStatus === OC.Encryption.MIGRATION_IN_PROGRESS) { | |||
var message = t('files_encryption', 'Initial encryption running... Please try again later.'); | |||
$('#messageText').text(message); | |||
$('#message').removeClass('hidden').addClass('update'); | |||
} | |||
} | |||
}); | |||
}); | |||
}); |
@@ -0,0 +1,16 @@ | |||
/** | |||
* Copyright (c) 2014 | |||
* Bjoern Schiessle <schiessle@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or later. | |||
* See the COPYING-README file. | |||
*/ | |||
/** | |||
* @namespace | |||
* @memberOf OC | |||
*/ | |||
OC.Encryption={ | |||
MIGRATION_OPEN:0, | |||
MIGRATION_COMPLETED:1, | |||
MIGRATION_IN_PROGRESS:-1, | |||
}; |
@@ -0,0 +1,55 @@ | |||
/** | |||
* Copyright (c) 2013 | |||
* Sam Tuke <samtuke@owncloud.com> | |||
* Robin Appelman <icewind1991@gmail.com> | |||
* Bjoern Schiessle <schiessle@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or later. | |||
* See the COPYING-README file. | |||
*/ | |||
$(document).ready(function(){ | |||
$( 'input:radio[name="adminEnableRecovery"]' ).change( | |||
function() { | |||
var recoveryStatus = $( this ).val(); | |||
var oldStatus = (1+parseInt(recoveryStatus)) % 2; | |||
var recoveryPassword = $( '#encryptionRecoveryPassword' ).val(); | |||
var confirmPassword = $( '#repeatEncryptionRecoveryPassword' ).val(); | |||
OC.msg.startSaving('#encryptionSetRecoveryKey .msg'); | |||
$.post( | |||
OC.filePath( 'files_encryption', 'ajax', 'adminrecovery.php' ) | |||
, { adminEnableRecovery: recoveryStatus, recoveryPassword: recoveryPassword, confirmPassword: confirmPassword } | |||
, function( result ) { | |||
OC.msg.finishedSaving('#encryptionSetRecoveryKey .msg', result); | |||
if (result.status === "error") { | |||
$('input:radio[name="adminEnableRecovery"][value="'+oldStatus.toString()+'"]').attr("checked", "true"); | |||
} else { | |||
if (recoveryStatus === "0") { | |||
$('p[name="changeRecoveryPasswordBlock"]').addClass("hidden"); | |||
} else { | |||
$('input:password[name="changeRecoveryPassword"]').val(""); | |||
$('p[name="changeRecoveryPasswordBlock"]').removeClass("hidden"); | |||
} | |||
} | |||
} | |||
); | |||
} | |||
); | |||
// change recovery password | |||
$('button:button[name="submitChangeRecoveryKey"]').click(function() { | |||
var oldRecoveryPassword = $('#oldEncryptionRecoveryPassword').val(); | |||
var newRecoveryPassword = $('#newEncryptionRecoveryPassword').val(); | |||
var confirmNewPassword = $('#repeatedNewEncryptionRecoveryPassword').val(); | |||
OC.msg.startSaving('#encryptionChangeRecoveryKey .msg'); | |||
$.post( | |||
OC.filePath( 'files_encryption', 'ajax', 'changeRecoveryPassword.php' ) | |||
, { oldPassword: oldRecoveryPassword, newPassword: newRecoveryPassword, confirmPassword: confirmNewPassword } | |||
, function( data ) { | |||
OC.msg.finishedSaving('#encryptionChangeRecoveryKey .msg', data); | |||
} | |||
); | |||
}); | |||
}); |
@@ -0,0 +1,89 @@ | |||
/** | |||
* Copyright (c) 2013, Sam Tuke <samtuke@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or later. | |||
* See the COPYING-README file. | |||
*/ | |||
function updatePrivateKeyPasswd() { | |||
var oldPrivateKeyPassword = $('input:password[id="oldPrivateKeyPassword"]').val(); | |||
var newPrivateKeyPassword = $('input:password[id="newPrivateKeyPassword"]').val(); | |||
OC.msg.startSaving('#encryption .msg'); | |||
$.post( | |||
OC.filePath( 'files_encryption', 'ajax', 'updatePrivateKeyPassword.php' ) | |||
, { oldPassword: oldPrivateKeyPassword, newPassword: newPrivateKeyPassword } | |||
, function( data ) { | |||
if (data.status === "error") { | |||
OC.msg.finishedSaving('#encryption .msg', data); | |||
} else { | |||
OC.msg.finishedSaving('#encryption .msg', data); | |||
} | |||
} | |||
); | |||
} | |||
$(document).ready(function(){ | |||
// Trigger ajax on recoveryAdmin status change | |||
$( 'input:radio[name="userEnableRecovery"]' ).change( | |||
function() { | |||
var recoveryStatus = $( this ).val(); | |||
OC.msg.startAction('#userEnableRecovery .msg', 'Updating recovery keys. This can take some time...'); | |||
$.post( | |||
OC.filePath( 'files_encryption', 'ajax', 'userrecovery.php' ) | |||
, { userEnableRecovery: recoveryStatus } | |||
, function( data ) { | |||
OC.msg.finishedAction('#userEnableRecovery .msg', data); | |||
} | |||
); | |||
// Ensure page is not reloaded on form submit | |||
return false; | |||
} | |||
); | |||
$("#encryptAll").click( | |||
function(){ | |||
// Hide feedback messages in case they're already visible | |||
$('#encryptAllSuccess').hide(); | |||
$('#encryptAllError').hide(); | |||
var userPassword = $( '#userPassword' ).val(); | |||
var encryptAll = $( '#encryptAll' ).val(); | |||
$.post( | |||
OC.filePath( 'files_encryption', 'ajax', 'encryptall.php' ) | |||
, { encryptAll: encryptAll, userPassword: userPassword } | |||
, function( data ) { | |||
if ( data.status == "success" ) { | |||
$('#encryptAllSuccess').show(); | |||
} else { | |||
$('#encryptAllError').show(); | |||
} | |||
} | |||
); | |||
// Ensure page is not reloaded on form submit | |||
return false; | |||
} | |||
); | |||
// update private key password | |||
$('input:password[name="changePrivateKeyPassword"]').keyup(function(event) { | |||
var oldPrivateKeyPassword = $('input:password[id="oldPrivateKeyPassword"]').val(); | |||
var newPrivateKeyPassword = $('input:password[id="newPrivateKeyPassword"]').val(); | |||
if (newPrivateKeyPassword !== '' && oldPrivateKeyPassword !== '' ) { | |||
$('button:button[name="submitChangePrivateKeyPassword"]').removeAttr("disabled"); | |||
if(event.which === 13) { | |||
updatePrivateKeyPasswd(); | |||
} | |||
} else { | |||
$('button:button[name="submitChangePrivateKeyPassword"]').attr("disabled", "true"); | |||
} | |||
}); | |||
$('button:button[name="submitChangePrivateKeyPassword"]').click(function() { | |||
updatePrivateKeyPasswd(); | |||
}); | |||
}); |
@@ -77,7 +77,7 @@ class Encryption implements IEncryptionModule { | |||
* @param array $header contains the header data read from the file | |||
* @param array $accessList who has access to the file contains the key 'users' and 'public' | |||
* | |||
* $return array $header contain data as key-value pairs which should be | |||
* @return array $header contain data as key-value pairs which should be | |||
* written to the header, in case of a write operation | |||
* or if no additional data is needed return a empty array | |||
*/ |
@@ -37,9 +37,9 @@ use \OCP\ISession; | |||
class KeyManager { | |||
/** | |||
* @var ICache | |||
* @var ISession | |||
*/ | |||
public static $cacheFactory; | |||
public static $session; | |||
/** | |||
* @var IStorage | |||
*/ | |||
@@ -87,24 +87,17 @@ class KeyManager { | |||
*/ | |||
private $log; | |||
/** | |||
* @var \OCP\ISession | |||
*/ | |||
private $session; | |||
/** | |||
* @param IStorage $keyStorage | |||
* @param Crypt $crypt | |||
* @param IConfig $config | |||
* @param Session $userSession | |||
* @param IUserSession $userSession | |||
* @param \OCP\ISession $session | |||
* @param ICacheFactory $cacheFactory | |||
* @param ILogger $log | |||
*/ | |||
public function __construct(IStorage $keyStorage, Crypt $crypt, IConfig $config, | |||
IUserSession $userSession, ISession $session ,ICacheFactory $cacheFactory, ILogger $log) { | |||
public function __construct(IStorage $keyStorage, Crypt $crypt, IConfig $config, IUserSession $userSession, ISession $session, ILogger $log) { | |||
$this->session = $session; | |||
self::$session = $session; | |||
$this->keyStorage = $keyStorage; | |||
$this->crypt = $crypt; | |||
$this->config = $config; | |||
@@ -113,9 +106,6 @@ class KeyManager { | |||
$this->publicShareKeyId = $this->config->getAppValue('encryption', | |||
'publicShareKeyId'); | |||
$this->keyId = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : false; | |||
self::$cacheFactory = $cacheFactory; | |||
self::$cacheFactory = self::$cacheFactory->create('encryption'); | |||
$this->log = $log; | |||
} | |||
@@ -211,7 +201,7 @@ class KeyManager { | |||
* | |||
* @param string $uid userid | |||
* @param string $passPhrase users password | |||
* @return ICache | |||
* @return ISession | |||
*/ | |||
public function init($uid, $passPhrase) { | |||
try { | |||
@@ -225,13 +215,10 @@ class KeyManager { | |||
} | |||
$this->session->set('privateKey', $privateKey); | |||
$this->session->set('initStatus', true); | |||
self::$cacheFactory->set('privateKey', $privateKey); | |||
self::$cacheFactory->set('initStatus', true); | |||
self::$session->set('privateKey', $privateKey); | |||
self::$session->set('initStatus', true); | |||
return self::$cacheFactory; | |||
return self::$session; | |||
} | |||
/** | |||
@@ -256,12 +243,15 @@ class KeyManager { | |||
*/ | |||
public function getFileKey($path, $uid) { | |||
$key = ''; | |||
$encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId); | |||
$encryptedFileKey = $this->keyStorage->getFileKey($path, | |||
$this->fileKeyId); | |||
$shareKey = $this->getShareKey($path, $uid); | |||
$privateKey = $this->session->get('privateKey'); | |||
if ($encryptedFileKey && $shareKey && $privateKey) { | |||
$key = $this->crypt->multiKeyDecrypt($encryptedFileKey, $shareKey, $privateKey); | |||
$key = $this->crypt->multiKeyDecrypt($encryptedFileKey, | |||
$shareKey, | |||
$privateKey); | |||
} | |||
return $key; | |||
@@ -293,11 +283,13 @@ class KeyManager { | |||
if ($params['uid'] === $user->getUser()->getUID() && $privateKey) { | |||
// Encrypt private key with new user pwd as passphrase | |||
$encryptedPrivateKey = $this->crypt->symmetricEncryptFileContent($privateKey, $params['password']); | |||
$encryptedPrivateKey = $this->crypt->symmetricEncryptFileContent($privateKey, | |||
$params['password']); | |||
// Save private key | |||
if ($encryptedPrivateKey) { | |||
$this->setPrivateKey($user->getUser()->getUID(), $encryptedPrivateKey); | |||
$this->setPrivateKey($user->getUser()->getUID(), | |||
$encryptedPrivateKey); | |||
} else { | |||
$this->log->error('Encryption could not update users encryption password'); | |||
} | |||
@@ -331,7 +323,8 @@ class KeyManager { | |||
$this->setPublicKey($user, $keypair['publicKey']); | |||
// Encrypt private key with new password | |||
$encryptedKey = $this->crypt->symmetricEncryptFileContent($keypair['privateKey'], $newUserPassword); | |||
$encryptedKey = $this->crypt->symmetricEncryptFileContent($keypair['privateKey'], | |||
$newUserPassword); | |||
if ($encryptedKey) { | |||
$this->setPrivateKey($user, $encryptedKey); | |||
@@ -431,4 +424,11 @@ class KeyManager { | |||
return $keys; | |||
} | |||
/** | |||
* @return string returns openssl key | |||
*/ | |||
public function getSystemPrivateKey() { | |||
return $this->keyStorage->getSystemUserKey($this->privateKeyId); | |||
} | |||
} |
@@ -94,120 +94,6 @@ class Util { | |||
$this->config = $config; | |||
} | |||
/** | |||
* @param $dirPath | |||
* @param bool $found | |||
* @return array|bool | |||
*/ | |||
private function findEncryptedFiles($dirPath, &$found = false) { | |||
if ($found === false) { | |||
$found = [ | |||
'plain' => [], | |||
'encrypted' => [], | |||
'broken' => [], | |||
]; | |||
} | |||
if ($this->files->is_dir($dirPath) && $handle = $this->files->opendir($dirPath)) { | |||
if (is_resource($handle)) { | |||
while (($file = readdir($handle) !== false)) { | |||
if ($file !== '.' && $file !== '..') { | |||
// Skip stray part files | |||
if ($this->isPartialFilePath($file)) { | |||
continue; | |||
} | |||
$filePath = $dirPath . '/' . $this->files->getRelativePath('/' . $file); | |||
$relPath = $this->stripUserFilesPath($filePath); | |||
// If the path is a directory, search its contents | |||
if ($this->files->is_dir($filePath)) { | |||
// Recurse back | |||
$this->findEncryptedFiles($filePath); | |||
/* | |||
* If the path is a file, | |||
* determine where they got re-enabled :/ | |||
*/ | |||
} elseif ($this->files->is_file($filePath)) { | |||
$isEncryptedPath = $this->isEncryptedPath($filePath); | |||
/** | |||
* If the file is encrypted | |||
* | |||
* @note: if the userId is | |||
* empty or not set, file will | |||
* be detected as plain | |||
* @note: this is inefficient; | |||
* scanning every file like this | |||
* will eat server resources :( | |||
* fixMe: xxx find better way | |||
*/ | |||
if ($isEncryptedPath) { | |||
$fileKey = $this->keyManager->getFileKey($relPath); | |||
$shareKey = $this->keyManager->getShareKey($relPath); | |||
// If file is encrypted but now file key is available, throw exception | |||
if (!$fileKey || !$shareKey) { | |||
$this->logger->error('Encryption library, no keys avilable to decrypt the file: ' . $file); | |||
$found['broken'][] = [ | |||
'name' => $file, | |||
'path' => $filePath, | |||
]; | |||
} else { | |||
$found['encrypted'][] = [ | |||
'name' => $file, | |||
'path' => $filePath | |||
]; | |||
} | |||
} else { | |||
$found['plain'][] = [ | |||
'name' => $file, | |||
'path' => $filePath | |||
]; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
return $found; | |||
} | |||
/** | |||
* @param $path | |||
* @return bool | |||
*/ | |||
private function isPartialFilePath($path) { | |||
$extension = pathinfo($path, PATHINFO_EXTENSION); | |||
if ($extension === 'part') { | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* @param $filePath | |||
* @return bool|string | |||
*/ | |||
private function stripUserFilesPath($filePath) { | |||
$split = $this->splitPath($filePath); | |||
// It is not a file relative to data/user/files | |||
if (count($split) < 4 || $split[2] !== 'files') { | |||
return false; | |||
} | |||
$sliced = array_slice($split, 3); | |||
return implode('/', $sliced); | |||
} | |||
/** | |||
* @param $filePath | |||
* @return array | |||
@@ -218,41 +104,6 @@ class Util { | |||
return explode('/', $normalized); | |||
} | |||
/** | |||
* @param $filePath | |||
* @return bool | |||
*/ | |||
private function isEncryptedPath($filePath) { | |||
$data = ''; | |||
// We only need 24 bytes from the last chunck | |||
if ($this->files->file_exists($filePath)) { | |||
$handle = $this->files->fopen($filePath, 'r'); | |||
if (is_resource($handle)) { | |||
// Suppress fseek warning, we handle the case that fseek | |||
// doesn't work in the else branch | |||
if (@fseek($handle, -24, SEEK_END) === 0) { | |||
$data = fgets($handle); | |||
} else { | |||
// if fseek failed on the storage we create a local copy | |||
// from the file and read this one | |||
fclose($handle); | |||
$localFile = $this->files->getLocalFile($filePath); | |||
$handle = fopen($localFile, 'r'); | |||
if (is_resource($handle) && fseek($handle, | |||
-24, | |||
SEEK_END) === 0 | |||
) { | |||
$data = fgets($handle); | |||
} | |||
} | |||
fclose($handle); | |||
return $this->crypt->isCatfileContent($data); | |||
} | |||
} | |||
} | |||
/** | |||
* @return bool | |||
*/ | |||
@@ -287,8 +138,8 @@ class Util { | |||
* @param $recoveryPassword | |||
*/ | |||
public function recoverUsersFiles($recoveryPassword) { | |||
// todo: get system private key here | |||
// $this->keyManager->get | |||
$encryptedKey = $this->keyManager->getSystemPrivateKey(); | |||
$privateKey = $this->crypt->decryptPrivateKey($encryptedKey, | |||
$recoveryPassword); | |||
@@ -329,25 +180,30 @@ class Util { | |||
*/ | |||
private function recoverFile($filePath, $privateKey) { | |||
$sharingEnabled = Share::isEnabled(); | |||
$uid = $this->user->getUID(); | |||
// Find out who, if anyone, is sharing the file | |||
if ($sharingEnabled) { | |||
$result = Share::getUsersSharingFile($filePath, | |||
$this->user->getUID(), | |||
$uid, | |||
true); | |||
$userIds = $result['users']; | |||
$userIds[] = 'public'; | |||
} else { | |||
$userIds = [ | |||
$this->user->getUID(), | |||
$uid, | |||
$this->recoveryKeyId | |||
]; | |||
} | |||
$filteredUids = $this->filterShareReadyUsers($userIds); | |||
// Decrypt file key | |||
$encKeyFile = $this->keyManager->getFileKey($filePath); | |||
$shareKey = $this->keyManager->getShareKey($filePath); | |||
$encKeyFile = $this->keyManager->getFileKey($filePath, | |||
$uid); | |||
$shareKey = $this->keyManager->getShareKey($filePath, | |||
$uid); | |||
$plainKeyFile = $this->crypt->multiKeyDecrypt($encKeyFile, | |||
$shareKey, | |||
$privateKey); | |||
@@ -357,38 +213,12 @@ class Util { | |||
$multiEncryptionKey = $this->crypt->multiKeyEncrypt($plainKeyFile, | |||
$userPublicKeys); | |||
$this->keyManager->setFileKeys($multiEncryptionKey['data']); | |||
$this->keyManager->setShareKeys($multiEncryptionKey['keys']); | |||
} | |||
/** | |||
* @param $userIds | |||
* @return array | |||
*/ | |||
private function filterShareReadyUsers($userIds) { | |||
// This array will collect the filtered IDs | |||
$readyIds = $unreadyIds = []; | |||
$this->keyManager->setFileKey($multiEncryptionKey['data'], | |||
$uid); | |||
// Loop though users and create array of UIDs that need new keyfiles | |||
foreach ($userIds as $user) { | |||
// Check that the user is encryption capable, or is the | |||
// public system user (for public shares) | |||
if ($this->isUserReady($user)) { | |||
// construct array of ready UIDs for keymanager | |||
$readyIds[] = $user; | |||
} else { | |||
// Construct array of unready UIDs for keymanager | |||
$unreadyIds[] = $user; | |||
// Log warning; we cant do necessary setup here | |||
// because we don't have the user passphrase | |||
$this->logger->warning('Encryption Library ' . $this->user->getUID() . ' is not setup for encryption'); | |||
} | |||
} | |||
return [ | |||
'ready' => $readyIds, | |||
'unready' => $unreadyIds | |||
]; | |||
$this->keyManager->setShareKey($filePath, | |||
$uid, | |||
$multiEncryptionKey['keys']); | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
<?php | |||
/** | |||
* Copyright (c) 2011 Robin Appelman <icewind@owncloud.com> | |||
* Copyright (c) 2015 Clark Tomlinson <clark@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or | |||
* later. | |||
* See the COPYING-README file. | |||
@@ -16,7 +16,7 @@ $tmpl = new OCP\Template('files_encryption', 'settings-admin'); | |||
$recoveryAdminEnabled = \OC::$server->getConfig()->getAppValue('encryption', 'recoveryAdminEnabled', '0'); | |||
$tmpl->assign('recoveryEnabled', $recoveryAdminEnabled); | |||
$tmpl->assign('initStatus', KeyManager::$cacheFactory->get('initStatus')); | |||
$tmpl->assign('initStatus', KeyManager::$session->get('initStatus')); | |||
\OCP\Util::addscript('files_encryption', 'settings-admin'); | |||
\OCP\Util::addscript('core', 'multiselect'); |
@@ -1,17 +1,17 @@ | |||
<?php | |||
/** | |||
* Copyright (c) 2013 Sam Tuke <samtuke@owncloud.com> | |||
* Copyright (c) 2015 Clark Tomlinson <clark@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or | |||
* later. | |||
* See the COPYING-README file. | |||
*/ | |||
// Add CSS stylesheet | |||
\OC_Util::addStyle('files_encryption', 'settings-personal'); | |||
\OC_Util::addStyle('encryption', 'settings-personal'); | |||
$tmpl = new OCP\Template('files_encryption', 'settings-personal'); | |||
$tmpl = new OCP\Template('encryption', 'settings-personal'); | |||
$user = \OCP\USER::getUser(); | |||
$user = \OCP\User::getUser(); | |||
$view = new \OC\Files\View('/'); | |||
$util = new \OCA\Files_Encryption\Util($view, $user); | |||
$session = new \OCA\Files_Encryption\Session($view); | |||
@@ -20,14 +20,14 @@ $privateKeySet = $session->getPrivateKey() !== false; | |||
// did we tried to initialize the keys for this session? | |||
$initialized = $session->getInitialized(); | |||
$recoveryAdminEnabled = \OC::$server->getAppConfig()->getValue('files_encryption', 'recoveryAdminEnabled'); | |||
$recoveryAdminEnabled = \OC::$server->getConfig()->getAppValue('encryption', 'recoveryAdminEnabled'); | |||
$recoveryEnabledForUser = $util->recoveryEnabledForUser(); | |||
$result = false; | |||
if ($recoveryAdminEnabled || !$privateKeySet) { | |||
\OCP\Util::addscript('files_encryption', 'settings-personal'); | |||
\OCP\Util::addscript('encryption', 'settings-personal'); | |||
$tmpl->assign('recoveryEnabled', $recoveryAdminEnabled); | |||
$tmpl->assign('recoveryEnabledForUser', $recoveryEnabledForUser); |
@@ -45,10 +45,15 @@ class KeyManagerTest extends TestCase { | |||
$userMock | |||
->method('getUID') | |||
->will($this->returnValue('admin')); | |||
$cacheMock = $this->getMock('OCP\ICacheFactory'); | |||
$sessionMock = $this->getMock('OCP\ISession'); | |||
$logMock = $this->getMock('OCP\ILogger'); | |||
$this->userId = 'admin'; | |||
$this->instance = new KeyManager($keyStorageMock, $cryptMock, $configMock, $userMock, $cacheMock, $logMock); | |||
$this->instance = new KeyManager($keyStorageMock, | |||
$cryptMock, | |||
$configMock, | |||
$userMock, | |||
$sessionMock, | |||
$logMock); | |||
$this->dummyKeys = ['public' => 'randomweakpublickeyhere', | |||
'private' => 'randomweakprivatekeyhere']; | |||
@@ -87,14 +92,16 @@ class KeyManagerTest extends TestCase { | |||
*/ | |||
public function testSetPublicKey() { | |||
$this->assertTrue($this->instance->setPublicKey($this->userId, $this->dummyKeys['public'])); | |||
$this->assertTrue($this->instance->setPublicKey($this->userId, | |||
$this->dummyKeys['public'])); | |||
} | |||
/** | |||
* | |||
*/ | |||
public function testSetPrivateKey() { | |||
$this->assertTrue($this->instance->setPrivateKey($this->userId, $this->dummyKeys['private'])); | |||
$this->assertTrue($this->instance->setPrivateKey($this->userId, | |||
$this->dummyKeys['private'])); | |||
} | |||
/** |