diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index 1b14082272..c1f273d86e 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -734,7 +734,7 @@ class Util { } if ($successful) { - $this->backupAllKeys('decryptAll'); + $this->backupAllKeys('decryptAll', false, false); $this->view->deleteAll($this->keysPath); } @@ -1495,16 +1495,61 @@ class Util { /** * create a backup of all keys from the user * - * @param string $purpose (optional) define the purpose of the backup, will be part of the backup folder + * @param string $purpose define the purpose of the backup, will be part of the backup folder name + * @param boolean $timestamp (optional) should a timestamp be added, default true + * @param boolean $includeUserKeys (optional) include users private-/public-key, default true */ - public function backupAllKeys($purpose = '') { + public function backupAllKeys($purpose, $timestamp = true, $includeUserKeys = true) { $this->userId; - $backupDir = $this->encryptionDir . '/backup.'; - $backupDir .= ($purpose === '') ? date("Y-m-d_H-i-s") . '/' : $purpose . '.' . date("Y-m-d_H-i-s") . '/'; + $backupDir = $this->encryptionDir . '/backup.' . $purpose; + $backupDir .= ($timestamp) ? '.' . date("Y-m-d_H-i-s") . '/' : '/'; $this->view->mkdir($backupDir); $this->view->copy($this->keysPath, $backupDir . 'keys/'); - $this->view->copy($this->privateKeyPath, $backupDir . $this->userId . '.privateKey'); - $this->view->copy($this->publicKeyPath, $backupDir . $this->userId . '.publicKey'); + if ($includeUserKeys) { + $this->view->copy($this->privateKeyPath, $backupDir . $this->userId . '.privateKey'); + $this->view->copy($this->publicKeyPath, $backupDir . $this->userId . '.publicKey'); + } + } + + /** + * restore backup + * + * @param string $backup complete name of the backup + * @return boolean + */ + public function restoreBackup($backup) { + $backupDir = $this->encryptionDir . '/backup.' . $backup . '/'; + + $fileKeysRestored = $this->view->rename($backupDir . 'keys', $this->encryptionDir . '/keys'); + + $pubKeyRestored = $privKeyRestored = true; + if ( + $this->view->file_exists($backupDir . $this->userId . '.privateKey') && + $this->view->file_exists($backupDir . $this->userId . '.privateKey') + ) { + + $pubKeyRestored = $this->view->rename($backupDir . $this->userId . '.publicKey', $this->publicKeyPath); + $privKeyRestored = $this->view->rename($backupDir . $this->userId . '.privateKey', $this->privateKeyPath); + } + + if ($fileKeysRestored && $pubKeyRestored && $privKeyRestored) { + $this->view->deleteAll($backupDir); + + return true; + } + + return false; + } + + /** + * delete backup + * + * @param string $backup complete name of the backup + * @return boolean + */ + public function deleteBackup($backup) { + $backupDir = $this->encryptionDir . '/backup.' . $backup . '/'; + return $this->view->deleteAll($backupDir); } /** diff --git a/apps/files_encryption/tests/util.php b/apps/files_encryption/tests/util.php index 4e0b4f2d0d..f9ee005e95 100755 --- a/apps/files_encryption/tests/util.php +++ b/apps/files_encryption/tests/util.php @@ -27,7 +27,7 @@ class Util extends TestCase { * @var \OC\Files\View */ public $view; - public $keyfilesPath; + public $keysPath; public $publicKeyPath; public $privateKeyPath; /** @@ -379,8 +379,6 @@ class Util extends TestCase { $this->assertTrue($this->view->is_dir($backupPath . '/keys')); $this->assertTrue($this->view->file_exists($backupPath . '/keys/' . $filename . '/fileKey')); $this->assertTrue($this->view->file_exists($backupPath . '/keys/' . $filename . '/' . $user . '.shareKey')); - $this->assertTrue($this->view->file_exists($backupPath . '/' . $user . '.privateKey')); - $this->assertTrue($this->view->file_exists($backupPath . '/' . $user . '.publicKey')); // cleanup $this->view->unlink($this->userId . '/files/' . $filename); @@ -389,21 +387,27 @@ class Util extends TestCase { } - /** - * test if all keys get moved to the backup folder correctly - */ - function testBackupAllKeys() { - self::loginHelper(self::TEST_ENCRYPTION_UTIL_USER1); - + private function createDummyKeysForBackupTest() { // create some dummy key files $encPath = '/' . self::TEST_ENCRYPTION_UTIL_USER1 . '/files_encryption'; $this->view->mkdir($encPath . '/keys/foo'); $this->view->file_put_contents($encPath . '/keys/foo/fileKey', 'key'); $this->view->file_put_contents($encPath . '/keys/foo/user1.shareKey', 'share key'); + } + + /** + * test if all keys get moved to the backup folder correctly + * + * @dataProvider dataBackupAllKeys + */ + function testBackupAllKeys($addTimestamp, $includeUserKeys) { + self::loginHelper(self::TEST_ENCRYPTION_UTIL_USER1); + + $this->createDummyKeysForBackupTest(); $util = new \OCA\Files_Encryption\Util($this->view, self::TEST_ENCRYPTION_UTIL_USER1); - $util->backupAllKeys('testBackupAllKeys'); + $util->backupAllKeys('testBackupAllKeys', $addTimestamp, $includeUserKeys); $backupPath = $this->getBackupPath('testBackupAllKeys'); @@ -412,15 +416,80 @@ class Util extends TestCase { $this->assertTrue($this->view->is_dir($backupPath . '/keys/foo')); $this->assertTrue($this->view->file_exists($backupPath . '/keys/foo/fileKey')); $this->assertTrue($this->view->file_exists($backupPath . '/keys/foo/user1.shareKey')); - $this->assertTrue($this->view->file_exists($backupPath . '/' . self::TEST_ENCRYPTION_UTIL_USER1 . '.privateKey')); - $this->assertTrue($this->view->file_exists($backupPath . '/' . self::TEST_ENCRYPTION_UTIL_USER1 . '.publicKey')); + + if ($includeUserKeys) { + $this->assertTrue($this->view->file_exists($backupPath . '/' . self::TEST_ENCRYPTION_UTIL_USER1 . '.privateKey')); + $this->assertTrue($this->view->file_exists($backupPath . '/' . self::TEST_ENCRYPTION_UTIL_USER1 . '.publicKey')); + } else { + $this->assertFalse($this->view->file_exists($backupPath . '/' . self::TEST_ENCRYPTION_UTIL_USER1 . '.privateKey')); + $this->assertFalse($this->view->file_exists($backupPath . '/' . self::TEST_ENCRYPTION_UTIL_USER1 . '.publicKey')); + } //cleanup $this->view->deleteAll($backupPath); - $this->view->unlink($encPath . '/keys/foo/fileKey'); - $this->view->unlink($encPath . '/keys/foo/user1.shareKey'); + $this->view->unlink($this->encryptionDir . '/keys/foo/fileKey'); + $this->view->unlink($this->encryptionDir . '/keys/foo/user1.shareKey'); } + function dataBackupAllKeys() { + return array( + array(true, true), + array(false, true), + array(true, false), + array(false, false), + ); + } + + + /** + * @dataProvider dataBackupAllKeys + */ + function testRestoreBackup($addTimestamp, $includeUserKeys) { + + $util = new \OCA\Files_Encryption\Util($this->view, self::TEST_ENCRYPTION_UTIL_USER1); + $this->createDummyKeysForBackupTest(); + + $util->backupAllKeys('restoreKeysBackupTest', $addTimestamp, $includeUserKeys); + $this->view->deleteAll($this->keysPath); + if ($includeUserKeys) { + $this->view->unlink($this->privateKeyPath); + $this->view->unlink($this->publicKeyPath); + } + + // key should be removed after backup was created + $this->assertFalse($this->view->is_dir($this->keysPath)); + if ($includeUserKeys) { + $this->assertFalse($this->view->file_exists($this->privateKeyPath)); + $this->assertFalse($this->view->file_exists($this->publicKeyPath)); + } + + $backupPath = $this->getBackupPath('restoreKeysBackupTest'); + $backupName = substr(basename($backupPath), strlen('backup.')); + + $this->assertTrue($util->restoreBackup($backupName)); + + // check if all keys are restored + $this->assertFalse($this->view->is_dir($backupPath)); + $this->assertTrue($this->view->is_dir($this->keysPath)); + $this->assertTrue($this->view->is_dir($this->keysPath . '/foo')); + $this->assertTrue($this->view->file_exists($this->keysPath . '/foo/fileKey')); + $this->assertTrue($this->view->file_exists($this->keysPath . '/foo/user1.shareKey')); + $this->assertTrue($this->view->file_exists($this->privateKeyPath)); + $this->assertTrue($this->view->file_exists($this->publicKeyPath)); + } + + function testDeleteBackup() { + $util = new \OCA\Files_Encryption\Util($this->view, self::TEST_ENCRYPTION_UTIL_USER1); + $this->createDummyKeysForBackupTest(); + + $util->backupAllKeys('testDeleteBackup', false, false); + + $this->assertTrue($this->view->is_dir($this->encryptionDir . '/backup.testDeleteBackup')); + + $util->deleteBackup('testDeleteBackup'); + + $this->assertFalse($this->view->is_dir($this->encryptionDir . '/backup.testDeleteBackup')); + } function testDescryptAllWithBrokenFiles() { diff --git a/lib/private/util.php b/lib/private/util.php index ec3640503e..d2d286fc11 100644 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -692,9 +692,9 @@ class OC_Util { $encryptedFiles = false; if (OC_App::isEnabled('files_encryption') === false) { $view = new OC\Files\View('/' . OCP\User::getUser()); - $keyfilePath = '/files_encryption/keyfiles'; - if ($view->is_dir($keyfilePath)) { - $dircontent = $view->getDirectoryContent($keyfilePath); + $keysPath = '/files_encryption/keys'; + if ($view->is_dir($keysPath)) { + $dircontent = $view->getDirectoryContent($keysPath); if (!empty($dircontent)) { $encryptedFiles = true; } @@ -714,7 +714,7 @@ class OC_Util { $backupExists = false; if (OC_App::isEnabled('files_encryption') === false) { $view = new OC\Files\View('/' . OCP\User::getUser()); - $backupPath = '/files_encryption/keyfiles.backup'; + $backupPath = '/files_encryption/backup.decryptAll'; if ($view->is_dir($backupPath)) { $dircontent = $view->getDirectoryContent($backupPath); if (!empty($dircontent)) { diff --git a/settings/ajax/deletekeys.php b/settings/ajax/deletekeys.php index 86a45820af..7d6c9a27aa 100644 --- a/settings/ajax/deletekeys.php +++ b/settings/ajax/deletekeys.php @@ -4,13 +4,11 @@ OCP\JSON::checkLoggedIn(); OCP\JSON::callCheck(); $l = \OC::$server->getL10N('settings'); -$user = \OC_User::getUser(); -$view = new \OC\Files\View('/' . $user . '/files_encryption'); -$keyfilesDeleted = $view->deleteAll('keyfiles.backup'); -$sharekeysDeleted = $view->deleteAll('share-keys.backup'); +$util = new \OCA\Files_Encryption\Util(new \OC\Files\View(), \OC_User::getUser()); +$result = $util->deleteBackup('decryptAll'); -if ($keyfilesDeleted && $sharekeysDeleted) { +if ($result) { \OCP\JSON::success(array('data' => array('message' => $l->t('Encryption keys deleted permanently')))); } else { \OCP\JSON::error(array('data' => array('message' => $l->t('Couldn\'t permanently delete your encryption keys, please check your owncloud.log or ask your administrator')))); diff --git a/settings/ajax/restorekeys.php b/settings/ajax/restorekeys.php index 5c263fadab..b89a8286db 100644 --- a/settings/ajax/restorekeys.php +++ b/settings/ajax/restorekeys.php @@ -4,21 +4,12 @@ OCP\JSON::checkLoggedIn(); OCP\JSON::callCheck(); $l = \OC::$server->getL10N('settings'); -$user = \OC_User::getUser(); -$view = new \OC\Files\View('/' . $user . '/files_encryption'); -$keyfilesRestored = $view->rename('keyfiles.backup', 'keyfiles'); -$sharekeysRestored = $view->rename('share-keys.backup' , 'share-keys'); +$util = new \OCA\Files_Encryption\Util(new \OC\Files\View(), \OC_User::getUser()); +$result = $util->restoreBackup('decryptAll'); -if ($keyfilesRestored && $sharekeysRestored) { +if ($result) { \OCP\JSON::success(array('data' => array('message' => $l->t('Backups restored successfully')))); } else { - // if one of the move operation was succesful we remove the files back to have a consistent state - if($keyfilesRestored) { - $view->rename('keyfiles', 'keyfiles.backup'); - } - if($sharekeysRestored) { - $view->rename('share-keys' , 'share-keys.backup'); - } \OCP\JSON::error(array('data' => array('message' => $l->t('Couldn\'t restore your encryption keys, please check your owncloud.log or ask your administrator')))); }