diff options
44 files changed, 1697 insertions, 234 deletions
diff --git a/apps/encryption/l10n/id.js b/apps/encryption/l10n/id.js index f1aebdbe1ac..4feb1de4186 100644 --- a/apps/encryption/l10n/id.js +++ b/apps/encryption/l10n/id.js @@ -8,20 +8,32 @@ OC.L10N.register( "Could not enable recovery key. Please check your recovery key password!" : "Tidak dapat mengaktifkan kunci pemulihan. Silakan periksa sandi kunci pemulihan Anda!", "Recovery key successfully disabled" : "Kunci pemulihan berhasil dinonaktifkan", "Could not disable recovery key. Please check your recovery key password!" : "Tidak dapat menonaktifkan kunci pemulihan. Silakan periksa sandi kunci pemulihan Anda!", + "Missing parameters" : "Parameter salah", "Please provide the old recovery password" : "Mohon berikan sandi pemulihan lama", "Please provide a new recovery password" : "Mohon berikan sandi pemulihan baru", "Please repeat the new recovery password" : "Silakan ulangi sandi pemulihan baru", "Password successfully changed." : "Sandi berhasil diubah", "Could not change the password. Maybe the old password was not correct." : "Tidak dapat mengubah sandi. Kemungkinan sandi lama yang dimasukkan salah.", + "Recovery Key disabled" : "Kunci Pemulihan dinonaktifkan", + "Recovery Key enabled" : "Kunci Pemulihan diaktifkan", + "Could not enable the recovery key, please try again or contact your administrator" : "Tidak dapat mengaktifkan kunci pemulihan, silakan coba lagi atau hubungi administrator Anda", "Could not update the private key password." : "Tidak dapat memperbarui sandi kunci private.", "The old password was not correct, please try again." : "Sandi lama salah, mohon coba lagi.", "The current log-in password was not correct, please try again." : "Sandi masuk saat ini salah, mohon coba lagi.", "Private key password successfully updated." : "Sandi kunci privat berhasil diperbarui.", "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." : "Kunci privat tidak sah untuk Aplikasi Enskripsi. Silakan perbarui sandi kunci privat anda pada pengaturan pribadi untuk memulihkan akses ke berkas anda yang dienskripsi.", "Encryption App is enabled but your keys are not initialized, please log-out and log-in again" : "Aplikasi Enskripsi telah diaktifkan tetapi kunci tidak diinisialisasi, silakan log-out dan log-in lagi", + "Enable recovery key" : "Aktifkan kunci pemulihan", + "Disable recovery key" : "Nonaktifkan kunci pemulihan", + "The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "Kunci pemulihan adalah kunci enkripsi tambahan yang digunakan untuk mengenkripsi berkas. Kunci pemulihan memungkinkan untuk memulihkan berkas-berkas pengguna ketika pengguna tersebut melupakan sandi mereka.", "Recovery key password" : "Sandi kunci pemulihan", + "Repeat recovery key password" : "Ulangi sandi kunci pemulihan", "Change recovery key password:" : "Ubah sandi kunci pemulihan:", + "Old recovery key password" : "Sandi kunci pemulihan lama", + "New recovery key password" : "Sandi kunci pemulihan baru", + "Repeat new recovery key password" : "Ulangi sandi kunci pemulihan baru", "Change Password" : "Ubah Sandi", + "ownCloud basic encryption module" : "Modul enkripsi dasar ownCloud", "Your private key password no longer matches your log-in password." : "Sandi kunci private Anda tidak lagi cocok dengan sandi masuk Anda.", "Set your old private key password to your current log-in password:" : "Setel sandi kunci private Anda untuk sandi masuk Anda saat ini:", " If you don't remember your old password you can ask your administrator to recover your files." : "Jika Anda tidak ingat sandi lama, Anda dapat meminta administrator Anda untuk memulihkan berkas.", diff --git a/apps/encryption/l10n/id.json b/apps/encryption/l10n/id.json index 25433f810ac..da2bf575939 100644 --- a/apps/encryption/l10n/id.json +++ b/apps/encryption/l10n/id.json @@ -6,20 +6,32 @@ "Could not enable recovery key. Please check your recovery key password!" : "Tidak dapat mengaktifkan kunci pemulihan. Silakan periksa sandi kunci pemulihan Anda!", "Recovery key successfully disabled" : "Kunci pemulihan berhasil dinonaktifkan", "Could not disable recovery key. Please check your recovery key password!" : "Tidak dapat menonaktifkan kunci pemulihan. Silakan periksa sandi kunci pemulihan Anda!", + "Missing parameters" : "Parameter salah", "Please provide the old recovery password" : "Mohon berikan sandi pemulihan lama", "Please provide a new recovery password" : "Mohon berikan sandi pemulihan baru", "Please repeat the new recovery password" : "Silakan ulangi sandi pemulihan baru", "Password successfully changed." : "Sandi berhasil diubah", "Could not change the password. Maybe the old password was not correct." : "Tidak dapat mengubah sandi. Kemungkinan sandi lama yang dimasukkan salah.", + "Recovery Key disabled" : "Kunci Pemulihan dinonaktifkan", + "Recovery Key enabled" : "Kunci Pemulihan diaktifkan", + "Could not enable the recovery key, please try again or contact your administrator" : "Tidak dapat mengaktifkan kunci pemulihan, silakan coba lagi atau hubungi administrator Anda", "Could not update the private key password." : "Tidak dapat memperbarui sandi kunci private.", "The old password was not correct, please try again." : "Sandi lama salah, mohon coba lagi.", "The current log-in password was not correct, please try again." : "Sandi masuk saat ini salah, mohon coba lagi.", "Private key password successfully updated." : "Sandi kunci privat berhasil diperbarui.", "Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." : "Kunci privat tidak sah untuk Aplikasi Enskripsi. Silakan perbarui sandi kunci privat anda pada pengaturan pribadi untuk memulihkan akses ke berkas anda yang dienskripsi.", "Encryption App is enabled but your keys are not initialized, please log-out and log-in again" : "Aplikasi Enskripsi telah diaktifkan tetapi kunci tidak diinisialisasi, silakan log-out dan log-in lagi", + "Enable recovery key" : "Aktifkan kunci pemulihan", + "Disable recovery key" : "Nonaktifkan kunci pemulihan", + "The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "Kunci pemulihan adalah kunci enkripsi tambahan yang digunakan untuk mengenkripsi berkas. Kunci pemulihan memungkinkan untuk memulihkan berkas-berkas pengguna ketika pengguna tersebut melupakan sandi mereka.", "Recovery key password" : "Sandi kunci pemulihan", + "Repeat recovery key password" : "Ulangi sandi kunci pemulihan", "Change recovery key password:" : "Ubah sandi kunci pemulihan:", + "Old recovery key password" : "Sandi kunci pemulihan lama", + "New recovery key password" : "Sandi kunci pemulihan baru", + "Repeat new recovery key password" : "Ulangi sandi kunci pemulihan baru", "Change Password" : "Ubah Sandi", + "ownCloud basic encryption module" : "Modul enkripsi dasar ownCloud", "Your private key password no longer matches your log-in password." : "Sandi kunci private Anda tidak lagi cocok dengan sandi masuk Anda.", "Set your old private key password to your current log-in password:" : "Setel sandi kunci private Anda untuk sandi masuk Anda saat ini:", " If you don't remember your old password you can ask your administrator to recover your files." : "Jika Anda tidak ingat sandi lama, Anda dapat meminta administrator Anda untuk memulihkan berkas.", diff --git a/apps/encryption/l10n/pt_BR.js b/apps/encryption/l10n/pt_BR.js index f68cd3ae667..4d25a18c137 100644 --- a/apps/encryption/l10n/pt_BR.js +++ b/apps/encryption/l10n/pt_BR.js @@ -25,6 +25,7 @@ OC.L10N.register( "Encryption App is enabled but your keys are not initialized, please log-out and log-in again" : "App de criptografia está ativado, mas as chaves não estão inicializadas, por favor log-out e faça login novamente", "Enable recovery key" : "Habilitar recuperação de chave", "Disable recovery key" : "Dasabilitar chave de recuperação", + "The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "A chave de recuperação é uma chave de encriptação extra que é utilizada para encriptar arquivos. Ela permite a recuperação de arquivos de um usuário esquecer sua senha.", "Recovery key password" : "Senha da chave de recuperação", "Repeat recovery key password" : "Repita senha da chave de recuperação", "Change recovery key password:" : "Mudar a senha da chave de recuperação:", diff --git a/apps/encryption/l10n/pt_BR.json b/apps/encryption/l10n/pt_BR.json index aecf8ee11c1..1c7b13e2e7d 100644 --- a/apps/encryption/l10n/pt_BR.json +++ b/apps/encryption/l10n/pt_BR.json @@ -23,6 +23,7 @@ "Encryption App is enabled but your keys are not initialized, please log-out and log-in again" : "App de criptografia está ativado, mas as chaves não estão inicializadas, por favor log-out e faça login novamente", "Enable recovery key" : "Habilitar recuperação de chave", "Disable recovery key" : "Dasabilitar chave de recuperação", + "The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "A chave de recuperação é uma chave de encriptação extra que é utilizada para encriptar arquivos. Ela permite a recuperação de arquivos de um usuário esquecer sua senha.", "Recovery key password" : "Senha da chave de recuperação", "Repeat recovery key password" : "Repita senha da chave de recuperação", "Change recovery key password:" : "Mudar a senha da chave de recuperação:", diff --git a/apps/encryption/lib/keymanager.php b/apps/encryption/lib/keymanager.php index aa9614812bc..05d23873482 100644 --- a/apps/encryption/lib/keymanager.php +++ b/apps/encryption/lib/keymanager.php @@ -483,7 +483,7 @@ class KeyManager { } public function deleteAllFileKeys($path) { - return $this->keyStorage->deleteAllFileKeys($path, Encryption::ID); + return $this->keyStorage->deleteAllFileKeys($path); } /** diff --git a/apps/files/l10n/pt_PT.js b/apps/files/l10n/pt_PT.js index 072141105c8..09974a0321d 100644 --- a/apps/files/l10n/pt_PT.js +++ b/apps/files/l10n/pt_PT.js @@ -42,6 +42,7 @@ OC.L10N.register( "Delete" : "Apagar", "Disconnect storage" : "Desconete o armazenamento", "Unshare" : "Deixar de partilhar", + "No permission to delete" : "Não tem permissão para apagar", "Download" : "Transferir", "Select" : "Selecionar", "Pending" : "Pendente", diff --git a/apps/files/l10n/pt_PT.json b/apps/files/l10n/pt_PT.json index 66230a0e6c9..4172185936a 100644 --- a/apps/files/l10n/pt_PT.json +++ b/apps/files/l10n/pt_PT.json @@ -40,6 +40,7 @@ "Delete" : "Apagar", "Disconnect storage" : "Desconete o armazenamento", "Unshare" : "Deixar de partilhar", + "No permission to delete" : "Não tem permissão para apagar", "Download" : "Transferir", "Select" : "Selecionar", "Pending" : "Pendente", diff --git a/apps/files_trashbin/lib/storage.php b/apps/files_trashbin/lib/storage.php index 418d7d2f1fd..006971fb242 100644 --- a/apps/files_trashbin/lib/storage.php +++ b/apps/files_trashbin/lib/storage.php @@ -81,14 +81,39 @@ class Storage extends Wrapper { /** * Deletes the given file by moving it into the trashbin. * - * @param string $path + * @param string $path path of file or folder to delete + * + * @return bool true if the operation succeeded, false otherwise */ public function unlink($path) { + return $this->doDelete($path, 'unlink'); + } + + /** + * Deletes the given folder by moving it into the trashbin. + * + * @param string $path path of folder to delete + * + * @return bool true if the operation succeeded, false otherwise + */ + public function rmdir($path) { + return $this->doDelete($path, 'rmdir'); + } + + /** + * Run the delete operation with the given method + * + * @param string $path path of file or folder to delete + * @param string $method either "unlink" or "rmdir" + * + * @return bool true if the operation succeeded, false otherwise + */ + private function doDelete($path, $method) { if (self::$disableTrash || !\OC_App::isEnabled('files_trashbin') || (pathinfo($path, PATHINFO_EXTENSION) === 'part') ) { - return $this->storage->unlink($path); + return call_user_func_array([$this->storage, $method], [$path]); } $normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path); $result = true; @@ -101,14 +126,14 @@ class Storage extends Wrapper { // in cross-storage cases the file will be copied // but not deleted, so we delete it here if ($result) { - $this->storage->unlink($path); + call_user_func_array([$this->storage, $method], [$path]); } } else { - $result = $this->storage->unlink($path); + $result = call_user_func_array([$this->storage, $method], [$path]); } unset($this->deletedFiles[$normalized]); } else if ($this->storage->file_exists($path)) { - $result = $this->storage->unlink($path); + $result = call_user_func_array([$this->storage, $method], [$path]); } return $result; diff --git a/apps/files_trashbin/lib/trashbin.php b/apps/files_trashbin/lib/trashbin.php index 1c880735b5a..31d77c01c91 100644 --- a/apps/files_trashbin/lib/trashbin.php +++ b/apps/files_trashbin/lib/trashbin.php @@ -277,16 +277,16 @@ class Trashbin { } /** - * restore files from trash bin + * Restore a file or folder from trash bin * - * @param string $file path to the deleted file - * @param string $filename name of the file - * @param int $timestamp time when the file was deleted + * @param string $file path to the deleted file/folder relative to "files_trashbin/files/", + * including the timestamp suffix ".d12345678" + * @param string $filename name of the file/folder + * @param int $timestamp time when the file/folder was deleted * - * @return bool + * @return bool true on success, false otherwise */ public static function restore($file, $filename, $timestamp) { - $user = \OCP\User::getUser(); $view = new \OC\Files\View('/' . $user); @@ -311,6 +311,9 @@ class Trashbin { $source = \OC\Files\Filesystem::normalizePath('files_trashbin/files/' . $file); $target = \OC\Files\Filesystem::normalizePath('files/' . $location . '/' . $uniqueFilename); + if (!$view->file_exists($source)) { + return false; + } $mtime = $view->filemtime($source); // restore file @@ -762,6 +765,8 @@ class Trashbin { $name = pathinfo($filename, PATHINFO_FILENAME); $l = \OC::$server->getL10N('files_trashbin'); + $location = '/' . trim($location, '/'); + // if extension is not empty we set a dot in front of it if ($ext !== '') { $ext = '.' . $ext; diff --git a/apps/files_trashbin/tests/storage.php b/apps/files_trashbin/tests/storage.php index d1468522dc2..7415aba09e9 100644 --- a/apps/files_trashbin/tests/storage.php +++ b/apps/files_trashbin/tests/storage.php @@ -62,6 +62,8 @@ class Storage extends \Test\TestCase { $this->userView = new \OC\Files\View('/' . $this->user . '/files/'); $this->userView->file_put_contents('test.txt', 'foo'); + $this->userView->mkdir('folder'); + $this->userView->file_put_contents('folder/inside.txt', 'bar'); } protected function tearDown() { @@ -75,7 +77,7 @@ class Storage extends \Test\TestCase { /** * Test that deleting a file puts it into the trashbin. */ - public function testSingleStorageDelete() { + public function testSingleStorageDeleteFile() { $this->assertTrue($this->userView->file_exists('test.txt')); $this->userView->unlink('test.txt'); list($storage,) = $this->userView->resolvePath('test.txt'); @@ -90,12 +92,34 @@ class Storage extends \Test\TestCase { } /** + * Test that deleting a folder puts it into the trashbin. + */ + public function testSingleStorageDeleteFolder() { + $this->assertTrue($this->userView->file_exists('folder/inside.txt')); + $this->userView->rmdir('folder'); + list($storage,) = $this->userView->resolvePath('folder/inside.txt'); + $storage->getScanner()->scan(''); // make sure we check the storage + $this->assertFalse($this->userView->getFileInfo('folder')); + + // check if folder is in trashbin + $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/'); + $this->assertEquals(1, count($results)); + $name = $results[0]->getName(); + $this->assertEquals('folder', substr($name, 0, strrpos($name, '.'))); + + $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/' . $name . '/'); + $this->assertEquals(1, count($results)); + $name = $results[0]->getName(); + $this->assertEquals('inside.txt', $name); + } + + /** * Test that deleting a file from another mounted storage properly * lands in the trashbin. This is a cross-storage situation because * the trashbin folder is in the root storage while the mounted one * isn't. */ - public function testCrossStorageDelete() { + public function testCrossStorageDeleteFile() { $storage2 = new Temporary(array()); \OC\Files\Filesystem::mount($storage2, array(), $this->user . '/files/substorage'); @@ -116,9 +140,41 @@ class Storage extends \Test\TestCase { } /** + * Test that deleting a folder from another mounted storage properly + * lands in the trashbin. This is a cross-storage situation because + * the trashbin folder is in the root storage while the mounted one + * isn't. + */ + public function testCrossStorageDeleteFolder() { + $storage2 = new Temporary(array()); + \OC\Files\Filesystem::mount($storage2, array(), $this->user . '/files/substorage'); + + $this->userView->mkdir('substorage/folder'); + $this->userView->file_put_contents('substorage/folder/subfile.txt', 'bar'); + $storage2->getScanner()->scan(''); + $this->assertTrue($storage2->file_exists('folder/subfile.txt')); + $this->userView->rmdir('substorage/folder'); + + $storage2->getScanner()->scan(''); + $this->assertFalse($this->userView->getFileInfo('substorage/folder')); + $this->assertFalse($storage2->file_exists('folder/subfile.txt')); + + // check if folder is in trashbin + $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files'); + $this->assertEquals(1, count($results)); + $name = $results[0]->getName(); + $this->assertEquals('folder', substr($name, 0, strrpos($name, '.'))); + + $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/' . $name . '/'); + $this->assertEquals(1, count($results)); + $name = $results[0]->getName(); + $this->assertEquals('subfile.txt', $name); + } + + /** * Test that deleted versions properly land in the trashbin. */ - public function testDeleteVersions() { + public function testDeleteVersionsOfFile() { \OCA\Files_Versions\Hooks::connectHooks(); // trigger a version (multiple would not work because of the expire logic) @@ -137,7 +193,38 @@ class Storage extends \Test\TestCase { $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/versions'); $this->assertEquals(1, count($results)); $name = $results[0]->getName(); - $this->assertEquals('test.txt', substr($name, 0, strlen('test.txt'))); + $this->assertEquals('test.txt.v', substr($name, 0, strlen('test.txt.v'))); + } + + /** + * Test that deleted versions properly land in the trashbin. + */ + public function testDeleteVersionsOfFolder() { + \OCA\Files_Versions\Hooks::connectHooks(); + + // trigger a version (multiple would not work because of the expire logic) + $this->userView->file_put_contents('folder/inside.txt', 'v1'); + + $results = $this->rootView->getDirectoryContent($this->user . '/files_versions/folder/'); + $this->assertEquals(1, count($results)); + + $this->userView->rmdir('folder'); + + // rescan trash storage + list($rootStorage,) = $this->rootView->resolvePath($this->user . '/files_trashbin'); + $rootStorage->getScanner()->scan(''); + + // check if versions are in trashbin + $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/versions'); + $this->assertEquals(1, count($results)); + $name = $results[0]->getName(); + $this->assertEquals('folder.d', substr($name, 0, strlen('folder.d'))); + + // check if versions are in trashbin + $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/versions/' . $name . '/'); + $this->assertEquals(1, count($results)); + $name = $results[0]->getName(); + $this->assertEquals('inside.txt.v', substr($name, 0, strlen('inside.txt.v'))); } /** @@ -145,7 +232,7 @@ class Storage extends \Test\TestCase { * storages. This is because rename() between storages would call * unlink() which should NOT trigger the version deletion logic. */ - public function testKeepFileAndVersionsWhenMovingBetweenStorages() { + public function testKeepFileAndVersionsWhenMovingFileBetweenStorages() { \OCA\Files_Versions\Hooks::connectHooks(); $storage2 = new Temporary(array()); @@ -162,7 +249,7 @@ class Storage extends \Test\TestCase { // move to another storage $this->userView->rename('test.txt', 'substorage/test.txt'); - $this->userView->file_exists('substorage/test.txt'); + $this->assertTrue($this->userView->file_exists('substorage/test.txt')); // rescan trash storage list($rootStorage,) = $this->rootView->resolvePath($this->user . '/files_trashbin'); @@ -182,9 +269,50 @@ class Storage extends \Test\TestCase { } /** + * Test that versions are not auto-trashed when moving a file between + * storages. This is because rename() between storages would call + * unlink() which should NOT trigger the version deletion logic. + */ + public function testKeepFileAndVersionsWhenMovingFolderBetweenStorages() { + \OCA\Files_Versions\Hooks::connectHooks(); + + $storage2 = new Temporary(array()); + \OC\Files\Filesystem::mount($storage2, array(), $this->user . '/files/substorage'); + + // trigger a version (multiple would not work because of the expire logic) + $this->userView->file_put_contents('folder/inside.txt', 'v1'); + + $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files'); + $this->assertEquals(0, count($results)); + + $results = $this->rootView->getDirectoryContent($this->user . '/files_versions/folder/'); + $this->assertEquals(1, count($results)); + + // move to another storage + $this->userView->rename('folder', 'substorage/folder'); + $this->assertTrue($this->userView->file_exists('substorage/folder/inside.txt')); + + // rescan trash storage + list($rootStorage,) = $this->rootView->resolvePath($this->user . '/files_trashbin'); + $rootStorage->getScanner()->scan(''); + + // versions were moved too + $results = $this->rootView->getDirectoryContent($this->user . '/files_versions/substorage/folder/'); + $this->assertEquals(1, count($results)); + + // check that nothing got trashed by the rename's unlink() call + $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files'); + $this->assertEquals(0, count($results)); + + // check that versions were moved and not trashed + $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/versions/'); + $this->assertEquals(0, count($results)); + } + + /** * Delete should fail is the source file cant be deleted */ - public function testSingleStorageDeleteFail() { + public function testSingleStorageDeleteFileFail() { /** * @var \OC\Files\Storage\Temporary | \PHPUnit_Framework_MockObject_MockObject $storage */ @@ -194,9 +322,6 @@ class Storage extends \Test\TestCase { ->getMock(); $storage->expects($this->any()) - ->method('rename') - ->will($this->returnValue(false)); - $storage->expects($this->any()) ->method('unlink') ->will($this->returnValue(false)); @@ -214,4 +339,38 @@ class Storage extends \Test\TestCase { $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/'); $this->assertEquals(0, count($results)); } + + /** + * Delete should fail is the source folder cant be deleted + */ + public function testSingleStorageDeleteFolderFail() { + /** + * @var \OC\Files\Storage\Temporary | \PHPUnit_Framework_MockObject_MockObject $storage + */ + $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary') + ->setConstructorArgs([[]]) + ->setMethods(['rename', 'unlink', 'rmdir']) + ->getMock(); + + $storage->expects($this->any()) + ->method('rmdir') + ->will($this->returnValue(false)); + + $cache = $storage->getCache(); + + Filesystem::mount($storage, [], '/' . $this->user); + $storage->mkdir('files'); + $this->userView->mkdir('folder'); + $this->userView->file_put_contents('folder/test.txt', 'foo'); + $this->assertTrue($storage->file_exists('files/folder/test.txt')); + $this->assertFalse($this->userView->rmdir('files/folder')); + $this->assertTrue($storage->file_exists('files/folder')); + $this->assertTrue($storage->file_exists('files/folder/test.txt')); + $this->assertTrue($cache->inCache('files/folder')); + $this->assertTrue($cache->inCache('files/folder/test.txt')); + + // file should not be in the trashbin + $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/'); + $this->assertEquals(0, count($results)); + } } diff --git a/apps/files_trashbin/tests/trashbin.php b/apps/files_trashbin/tests/trashbin.php index a2e1a9addf6..85c47b527b7 100644 --- a/apps/files_trashbin/tests/trashbin.php +++ b/apps/files_trashbin/tests/trashbin.php @@ -40,6 +40,11 @@ class Test_Trashbin extends \Test\TestCase { private static $rememberAutoExpire; /** + * @var bool + */ + private static $trashBinStatus; + + /** * @var \OC\Files\View */ private $rootView; @@ -47,6 +52,9 @@ class Test_Trashbin extends \Test\TestCase { public static function setUpBeforeClass() { parent::setUpBeforeClass(); + $appManager = \OC::$server->getAppManager(); + self::$trashBinStatus = $appManager->isEnabledForUser('files_trashbin'); + // reset backend \OC_User::clearBackends(); \OC_User::useBackend('database'); @@ -89,12 +97,18 @@ class Test_Trashbin extends \Test\TestCase { \OC\Files\Filesystem::getLoader()->removeStorageWrapper('oc_trashbin'); + if (self::$trashBinStatus) { + \OC::$server->getAppManager()->enableApp('files_trashbin'); + } + parent::tearDownAfterClass(); } protected function setUp() { parent::setUp(); + \OC::$server->getAppManager()->enableApp('files_trashbin'); + $this->trashRoot1 = '/' . self::TEST_TRASHBIN_USER1 . '/files_trashbin'; $this->trashRoot2 = '/' . self::TEST_TRASHBIN_USER2 . '/files_trashbin'; $this->rootView = new \OC\Files\View(); @@ -102,9 +116,18 @@ class Test_Trashbin extends \Test\TestCase { } protected function tearDown() { + // disable trashbin to be able to properly clean up + \OC::$server->getAppManager()->disableApp('files_trashbin'); + + $this->rootView->deleteAll('/' . self::TEST_TRASHBIN_USER1 . '/files'); + $this->rootView->deleteAll('/' . self::TEST_TRASHBIN_USER2 . '/files'); $this->rootView->deleteAll($this->trashRoot1); $this->rootView->deleteAll($this->trashRoot2); + // clear trash table + $connection = \OC::$server->getDatabaseConnection(); + $connection->executeUpdate('DELETE FROM `*PREFIX*files_trash`'); + parent::tearDown(); } @@ -295,6 +318,310 @@ class Test_Trashbin extends \Test\TestCase { } /** + * Test restoring a file + */ + public function testRestoreFileInRoot() { + $userFolder = \OC::$server->getUserFolder(); + $file = $userFolder->newFile('file1.txt'); + $file->putContent('foo'); + + $this->assertTrue($userFolder->nodeExists('file1.txt')); + + $file->delete(); + + $this->assertFalse($userFolder->nodeExists('file1.txt')); + + $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'mtime'); + $this->assertCount(1, $filesInTrash); + + /** @var \OCP\Files\FileInfo */ + $trashedFile = $filesInTrash[0]; + + $this->assertTrue( + OCA\Files_Trashbin\Trashbin::restore( + 'file1.txt.d' . $trashedFile->getMtime(), + $trashedFile->getName(), + $trashedFile->getMtime() + ) + ); + + $file = $userFolder->get('file1.txt'); + $this->assertEquals('foo', $file->getContent()); + } + + /** + * Test restoring a file in subfolder + */ + public function testRestoreFileInSubfolder() { + $userFolder = \OC::$server->getUserFolder(); + $folder = $userFolder->newFolder('folder'); + $file = $folder->newFile('file1.txt'); + $file->putContent('foo'); + + $this->assertTrue($userFolder->nodeExists('folder/file1.txt')); + + $file->delete(); + + $this->assertFalse($userFolder->nodeExists('folder/file1.txt')); + + $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'mtime'); + $this->assertCount(1, $filesInTrash); + + /** @var \OCP\Files\FileInfo */ + $trashedFile = $filesInTrash[0]; + + $this->assertTrue( + OCA\Files_Trashbin\Trashbin::restore( + 'file1.txt.d' . $trashedFile->getMtime(), + $trashedFile->getName(), + $trashedFile->getMtime() + ) + ); + + $file = $userFolder->get('folder/file1.txt'); + $this->assertEquals('foo', $file->getContent()); + } + + /** + * Test restoring a folder + */ + public function testRestoreFolder() { + $userFolder = \OC::$server->getUserFolder(); + $folder = $userFolder->newFolder('folder'); + $file = $folder->newFile('file1.txt'); + $file->putContent('foo'); + + $this->assertTrue($userFolder->nodeExists('folder')); + + $folder->delete(); + + $this->assertFalse($userFolder->nodeExists('folder')); + + $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'mtime'); + $this->assertCount(1, $filesInTrash); + + /** @var \OCP\Files\FileInfo */ + $trashedFolder = $filesInTrash[0]; + + $this->assertTrue( + OCA\Files_Trashbin\Trashbin::restore( + 'folder.d' . $trashedFolder->getMtime(), + $trashedFolder->getName(), + $trashedFolder->getMtime() + ) + ); + + $file = $userFolder->get('folder/file1.txt'); + $this->assertEquals('foo', $file->getContent()); + } + + /** + * Test restoring a file from inside a trashed folder + */ + public function testRestoreFileFromTrashedSubfolder() { + $userFolder = \OC::$server->getUserFolder(); + $folder = $userFolder->newFolder('folder'); + $file = $folder->newFile('file1.txt'); + $file->putContent('foo'); + + $this->assertTrue($userFolder->nodeExists('folder')); + + $folder->delete(); + + $this->assertFalse($userFolder->nodeExists('folder')); + + $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'mtime'); + $this->assertCount(1, $filesInTrash); + + /** @var \OCP\Files\FileInfo */ + $trashedFile = $filesInTrash[0]; + + $this->assertTrue( + OCA\Files_Trashbin\Trashbin::restore( + 'folder.d' . $trashedFile->getMtime() . '/file1.txt', + 'file1.txt', + $trashedFile->getMtime() + ) + ); + + $file = $userFolder->get('file1.txt'); + $this->assertEquals('foo', $file->getContent()); + } + + /** + * Test restoring a file whenever the source folder was removed. + * The file should then land in the root. + */ + public function testRestoreFileWithMissingSourceFolder() { + $userFolder = \OC::$server->getUserFolder(); + $folder = $userFolder->newFolder('folder'); + $file = $folder->newFile('file1.txt'); + $file->putContent('foo'); + + $this->assertTrue($userFolder->nodeExists('folder/file1.txt')); + + $file->delete(); + + $this->assertFalse($userFolder->nodeExists('folder/file1.txt')); + + $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'mtime'); + $this->assertCount(1, $filesInTrash); + + /** @var \OCP\Files\FileInfo */ + $trashedFile = $filesInTrash[0]; + + // delete source folder + $folder->delete(); + + $this->assertTrue( + OCA\Files_Trashbin\Trashbin::restore( + 'file1.txt.d' . $trashedFile->getMtime(), + $trashedFile->getName(), + $trashedFile->getMtime() + ) + ); + + $file = $userFolder->get('file1.txt'); + $this->assertEquals('foo', $file->getContent()); + } + + /** + * Test restoring a file in the root folder whenever there is another file + * with the same name in the root folder + */ + public function testRestoreFileDoesNotOverwriteExistingInRoot() { + $userFolder = \OC::$server->getUserFolder(); + $file = $userFolder->newFile('file1.txt'); + $file->putContent('foo'); + + $this->assertTrue($userFolder->nodeExists('file1.txt')); + + $file->delete(); + + $this->assertFalse($userFolder->nodeExists('file1.txt')); + + $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'mtime'); + $this->assertCount(1, $filesInTrash); + + /** @var \OCP\Files\FileInfo */ + $trashedFile = $filesInTrash[0]; + + // create another file + $file = $userFolder->newFile('file1.txt'); + $file->putContent('bar'); + + $this->assertTrue( + OCA\Files_Trashbin\Trashbin::restore( + 'file1.txt.d' . $trashedFile->getMtime(), + $trashedFile->getName(), + $trashedFile->getMtime() + ) + ); + + $anotherFile = $userFolder->get('file1.txt'); + $this->assertEquals('bar', $anotherFile->getContent()); + + $restoredFile = $userFolder->get('file1 (restored).txt'); + $this->assertEquals('foo', $restoredFile->getContent()); + } + + /** + * Test restoring a file whenever there is another file + * with the same name in the source folder + */ + public function testRestoreFileDoesNotOverwriteExistingInSubfolder() { + $userFolder = \OC::$server->getUserFolder(); + $folder = $userFolder->newFolder('folder'); + $file = $folder->newFile('file1.txt'); + $file->putContent('foo'); + + $this->assertTrue($userFolder->nodeExists('folder/file1.txt')); + + $file->delete(); + + $this->assertFalse($userFolder->nodeExists('folder/file1.txt')); + + $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'mtime'); + $this->assertCount(1, $filesInTrash); + + /** @var \OCP\Files\FileInfo */ + $trashedFile = $filesInTrash[0]; + + // create another file + $file = $folder->newFile('file1.txt'); + $file->putContent('bar'); + + $this->assertTrue( + OCA\Files_Trashbin\Trashbin::restore( + 'file1.txt.d' . $trashedFile->getMtime(), + $trashedFile->getName(), + $trashedFile->getMtime() + ) + ); + + $anotherFile = $userFolder->get('folder/file1.txt'); + $this->assertEquals('bar', $anotherFile->getContent()); + + $restoredFile = $userFolder->get('folder/file1 (restored).txt'); + $this->assertEquals('foo', $restoredFile->getContent()); + } + + /** + * Test restoring a non-existing file from trashbin, returns false + */ + public function testRestoreUnexistingFile() { + $this->assertFalse( + OCA\Files_Trashbin\Trashbin::restore( + 'unexist.txt.d123456', + 'unexist.txt', + '123456' + ) + ); + } + + /** + * Test restoring a file into a read-only folder, will restore + * the file to root instead + */ + public function testRestoreFileIntoReadOnlySourceFolder() { + $userFolder = \OC::$server->getUserFolder(); + $folder = $userFolder->newFolder('folder'); + $file = $folder->newFile('file1.txt'); + $file->putContent('foo'); + + $this->assertTrue($userFolder->nodeExists('folder/file1.txt')); + + $file->delete(); + + $this->assertFalse($userFolder->nodeExists('folder/file1.txt')); + + $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'mtime'); + $this->assertCount(1, $filesInTrash); + + /** @var \OCP\Files\FileInfo */ + $trashedFile = $filesInTrash[0]; + + // delete source folder + list($storage, $internalPath) = $this->rootView->resolvePath('/' . self::TEST_TRASHBIN_USER1 . '/files/folder'); + $folderAbsPath = $storage->getSourcePath($internalPath); + // make folder read-only + chmod($folderAbsPath, 0555); + + $this->assertTrue( + OCA\Files_Trashbin\Trashbin::restore( + 'file1.txt.d' . $trashedFile->getMtime(), + $trashedFile->getName(), + $trashedFile->getMtime() + ) + ); + + $file = $userFolder->get('file1.txt'); + $this->assertEquals('foo', $file->getContent()); + + chmod($folderAbsPath, 0755); + } + + /** * @param string $user * @param bool $create * @param bool $password diff --git a/apps/files_versions/lib/storage.php b/apps/files_versions/lib/storage.php index 45f96ee776b..98e486690b6 100644 --- a/apps/files_versions/lib/storage.php +++ b/apps/files_versions/lib/storage.php @@ -158,7 +158,7 @@ class Storage { // 1.5 times as large as the current version -> 2.5 $neededSpace = $files_view->filesize($filename) * 2.5; - self::scheduleExpire($filename, $versionsSize, $neededSpace); + self::scheduleExpire($uid, $filename, $versionsSize, $neededSpace); // store a new version of a file $mtime = $users_view->filemtime('files/' . $filename); @@ -276,7 +276,7 @@ class Storage { // if we moved versions directly for a file, schedule expiration check for that file if (!$rootView->is_dir('/' . $targetOwner . '/files/' . $targetPath)) { - self::scheduleExpire($targetPath); + self::scheduleExpire($targetOwner, $targetPath); } } @@ -309,7 +309,7 @@ class Storage { // rollback if (self::copyFileContents($users_view, 'files_versions' . $filename . '.v' . $revision, 'files' . $filename)) { $files_view->touch($file, $revision); - Storage::scheduleExpire($file); + Storage::scheduleExpire($uid, $file); return true; } else if ($versionCreated) { self::deleteVersion($users_view, $version); @@ -532,12 +532,15 @@ class Storage { } /** - * @param string $fileName - * @param int|null $versionsSize - * @param int $neededSpace + * Schedule versions expiration for the given file + * + * @param string $uid owner of the file + * @param string $fileName file/folder for which to schedule expiration + * @param int|null $versionsSize current versions size + * @param int $neededSpace requested versions size */ - private static function scheduleExpire($fileName, $versionsSize = null, $neededSpace = 0) { - $command = new Expire(\OC::$server->getUserSession()->getUser()->getUID(), $fileName, $versionsSize, $neededSpace); + private static function scheduleExpire($uid, $fileName, $versionsSize = null, $neededSpace = 0) { + $command = new Expire($uid, $fileName, $versionsSize, $neededSpace); \OC::$server->getCommandBus()->push($command); } diff --git a/apps/files_versions/tests/versions.php b/apps/files_versions/tests/versions.php index 2d3e2b66e06..97afcf715cb 100644 --- a/apps/files_versions/tests/versions.php +++ b/apps/files_versions/tests/versions.php @@ -45,10 +45,6 @@ class Test_Files_Versioning extends \Test\TestCase { public static function setUpBeforeClass() { parent::setUpBeforeClass(); - // clear share hooks - \OC_Hook::clear('OCP\\Share'); - \OC::registerShareHooks(); - \OCA\Files_Versions\Hooks::connectHooks(); $application = new \OCA\Files_Sharing\AppInfo\Application(); $application->registerMountProviders(); $application->setupPropagation(); @@ -69,6 +65,11 @@ class Test_Files_Versioning extends \Test\TestCase { protected function setUp() { parent::setUp(); + // clear hooks + \OC_Hook::clear(); + \OC::registerShareHooks(); + \OCA\Files_Versions\Hooks::connectHooks(); + self::loginHelper(self::TEST_VERSIONS_USER); $this->rootView = new \OC\Files\View(); if (!$this->rootView->file_exists(self::USERS_VERSIONS_ROOT)) { @@ -82,6 +83,8 @@ class Test_Files_Versioning extends \Test\TestCase { $this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files_versions/'); $this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files_versions/'); + \OC_Hook::clear(); + parent::tearDown(); } @@ -648,6 +651,85 @@ class Test_Files_Versioning extends \Test\TestCase { } /** + * Test whether versions are created when overwriting as owner + */ + public function testStoreVersionAsOwner() { + $this->loginAsUser(self::TEST_VERSIONS_USER); + + $this->createAndCheckVersions( + \OC\Files\Filesystem::getView(), + 'test.txt' + ); + } + + /** + * Test whether versions are created when overwriting as share recipient + */ + public function testStoreVersionAsRecipient() { + $this->loginAsUser(self::TEST_VERSIONS_USER); + + \OC\Files\Filesystem::mkdir('folder'); + \OC\Files\Filesystem::file_put_contents('folder/test.txt', 'test file'); + $fileInfo = \OC\Files\Filesystem::getFileInfo('folder'); + + \OCP\Share::shareItem( + 'folder', + $fileInfo['fileid'], + \OCP\Share::SHARE_TYPE_USER, + self::TEST_VERSIONS_USER2, + \OCP\Constants::PERMISSION_ALL + ); + + $this->loginAsUser(self::TEST_VERSIONS_USER2); + + $this->createAndCheckVersions( + \OC\Files\Filesystem::getView(), + 'folder/test.txt' + ); + } + + /** + * Test whether versions are created when overwriting anonymously. + * + * When uploading through a public link or publicwebdav, no user + * is logged in. File modification must still be able to find + * the owner and create versions. + */ + public function testStoreVersionAsAnonymous() { + $this->logout(); + + // note: public link upload does this, + // needed to make the hooks fire + \OC_Util::setupFS(self::TEST_VERSIONS_USER); + + $userView = new \OC\Files\View('/' . self::TEST_VERSIONS_USER . '/files'); + $this->createAndCheckVersions( + $userView, + 'test.txt' + ); + } + + private function createAndCheckVersions($view, $path) { + $view->file_put_contents($path, 'test file'); + $view->file_put_contents($path, 'version 1'); + $view->file_put_contents($path, 'version 2'); + + $this->loginAsUser(self::TEST_VERSIONS_USER); + + // need to scan for the versions + list($rootStorage,) = $this->rootView->resolvePath(self::TEST_VERSIONS_USER . '/files_versions'); + $rootStorage->getScanner()->scan('files_versions'); + + $versions = \OCA\Files_Versions\Storage::getVersions( + self::TEST_VERSIONS_USER, '/' . $path + ); + + // note: we cannot predict how many versions are created due to + // test run timing + $this->assertGreaterThan(0, count($versions)); + } + + /** * @param string $user * @param bool $create * @param bool $password diff --git a/apps/provisioning_api/lib/users.php b/apps/provisioning_api/lib/users.php index 505a141c032..43cf22b071b 100644 --- a/apps/provisioning_api/lib/users.php +++ b/apps/provisioning_api/lib/users.php @@ -155,7 +155,14 @@ class Users { case 'quota': $quota = $parameters['_put']['value']; if($quota !== 'none' and $quota !== 'default') { - $quota = OC_Helper::computerFileSize($quota); + if (is_numeric($quota)) { + $quota = floatval($quota); + } else { + $quota = OC_Helper::computerFileSize($quota); + } + if ($quota === false) { + return new OC_OCS_Result(null, 103, "Invalid quota value {$parameters['_put']['value']}"); + } if($quota == 0) { $quota = 'default'; }else if($quota == -1){ diff --git a/apps/provisioning_api/tests/userstest.php b/apps/provisioning_api/tests/userstest.php index b7e83a3c4fe..c6a6133b7d2 100644 --- a/apps/provisioning_api/tests/userstest.php +++ b/apps/provisioning_api/tests/userstest.php @@ -187,20 +187,36 @@ class UsersTest extends TestCase { } - public function testEditOwnQuota() { + /** + * @dataProvider providesQuotas + * @param $expected + * @param $quota + */ + public function testEditOwnQuota($expected, $quota) { $user = $this->generateUsers(); + \OC_Group::addToGroup($user, 'admin'); \OC_User::setUserId($user); $result = \OCA\provisioning_API\Users::editUser( - array( + [ 'userid' => $user, - '_put' => array( + '_put' => [ 'key' => 'quota', - 'value' => '20G', - ), - ) + 'value' => $quota, + ], + ] ); $this->assertInstanceOf('OC_OCS_Result', $result); - $this->assertFalse($result->succeeded()); + $this->assertEquals($expected, $result->succeeded()); + } + + public function providesQuotas() { + return [ + [true, '20G'], + [true, '1234567'], + [true, 'none'], + [true, 'default'], + [false, 'qwertzu'], + ]; } public function testAdminEditOwnQuota() { diff --git a/apps/user_ldap/l10n/da.js b/apps/user_ldap/l10n/da.js index f19e3ffa837..1b070f48a90 100644 --- a/apps/user_ldap/l10n/da.js +++ b/apps/user_ldap/l10n/da.js @@ -22,6 +22,7 @@ OC.L10N.register( "Could not detect Base DN, please enter it manually." : "Kunne ikke registrere Base DN - angiv den venligst manuelt.", "{nthServer}. Server" : "{nthServer}. server", "No object found in the given Base DN. Please revise." : "Intet objekt fundet i den givne Base DN. Gennemse venligst.", + "More than 1.000 directory entries available." : "Mere end 1.000 opslag tilgængelige", " entries available within the provided Base DN" : "poster tilgængelige inden for det angivne Base DN.", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Der opstod en fejl. Tjek venligst Base DN, såvel som forbindelsesindstillingerne og brugeroplysningerne.", "Do you really want to delete the current Server Configuration?" : "Ønsker du virkelig at slette den nuværende Server Konfiguration?", diff --git a/apps/user_ldap/l10n/da.json b/apps/user_ldap/l10n/da.json index 0e3702e3e80..acd0eaae13e 100644 --- a/apps/user_ldap/l10n/da.json +++ b/apps/user_ldap/l10n/da.json @@ -20,6 +20,7 @@ "Could not detect Base DN, please enter it manually." : "Kunne ikke registrere Base DN - angiv den venligst manuelt.", "{nthServer}. Server" : "{nthServer}. server", "No object found in the given Base DN. Please revise." : "Intet objekt fundet i den givne Base DN. Gennemse venligst.", + "More than 1.000 directory entries available." : "Mere end 1.000 opslag tilgængelige", " entries available within the provided Base DN" : "poster tilgængelige inden for det angivne Base DN.", "An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Der opstod en fejl. Tjek venligst Base DN, såvel som forbindelsesindstillingerne og brugeroplysningerne.", "Do you really want to delete the current Server Configuration?" : "Ønsker du virkelig at slette den nuværende Server Konfiguration?", diff --git a/apps/user_ldap/l10n/id.js b/apps/user_ldap/l10n/id.js index d8ff8b4e24c..23170f99864 100644 --- a/apps/user_ldap/l10n/id.js +++ b/apps/user_ldap/l10n/id.js @@ -35,6 +35,8 @@ OC.L10N.register( "Select attributes" : "Pilih atribut", "User not found. Please check your login attributes and username. Effective filter (to copy-and-paste for command line validation): <br/>" : "Pengguna tidak ditemukan. Mohon periksa atribut login dan nama pengguna Anda. Penyaring efektif (salin dan tempel berikut untuk validasi baris perintah):\n<br/>", "User found and settings verified." : "Pengguna ditemukan dan pengaturan terverifikasi.", + "An unspecified error occurred. Please check the settings and the log." : "Terjadi kesalahan yang tidak disebutkan. Mohon periksa pengaturan dan log.", + "The search filter is invalid, probably due to syntax issues like uneven number of opened and closed brackets. Please revise." : "Penyaring pencarian tidak sah, kemungkinan karena masalah sintaks seperti jumlah kurung buka dan tutup tidak sama. Mohon diperiksa.", "A connection error to LDAP / AD occurred, please check host, port and credentials." : "Terjadi kesalahan sambungan ke LDAP / AD, mohon periksa host, port dan kredensial.", "The group box was disabled, because the LDAP / AD server does not support memberOf." : "Kotak grup telah diaktifkan, karena server LDAP / AD tidak mendukung keanggotaan.", "_%s group found_::_%s groups found_" : ["%s grup ditemukan"], diff --git a/apps/user_ldap/l10n/id.json b/apps/user_ldap/l10n/id.json index 811351a2549..fa0a0a7be20 100644 --- a/apps/user_ldap/l10n/id.json +++ b/apps/user_ldap/l10n/id.json @@ -33,6 +33,8 @@ "Select attributes" : "Pilih atribut", "User not found. Please check your login attributes and username. Effective filter (to copy-and-paste for command line validation): <br/>" : "Pengguna tidak ditemukan. Mohon periksa atribut login dan nama pengguna Anda. Penyaring efektif (salin dan tempel berikut untuk validasi baris perintah):\n<br/>", "User found and settings verified." : "Pengguna ditemukan dan pengaturan terverifikasi.", + "An unspecified error occurred. Please check the settings and the log." : "Terjadi kesalahan yang tidak disebutkan. Mohon periksa pengaturan dan log.", + "The search filter is invalid, probably due to syntax issues like uneven number of opened and closed brackets. Please revise." : "Penyaring pencarian tidak sah, kemungkinan karena masalah sintaks seperti jumlah kurung buka dan tutup tidak sama. Mohon diperiksa.", "A connection error to LDAP / AD occurred, please check host, port and credentials." : "Terjadi kesalahan sambungan ke LDAP / AD, mohon periksa host, port dan kredensial.", "The group box was disabled, because the LDAP / AD server does not support memberOf." : "Kotak grup telah diaktifkan, karena server LDAP / AD tidak mendukung keanggotaan.", "_%s group found_::_%s groups found_" : ["%s grup ditemukan"], diff --git a/apps/user_ldap/l10n/pt_PT.js b/apps/user_ldap/l10n/pt_PT.js index e29158df8d4..55cccb28022 100644 --- a/apps/user_ldap/l10n/pt_PT.js +++ b/apps/user_ldap/l10n/pt_PT.js @@ -10,6 +10,7 @@ OC.L10N.register( "No configuration specified" : "Nenhuma configuração especificada", "No data specified" : "Nenhuma data especificada", " Could not set configuration %s" : "Não foi possível definir a configuração %s", + "Action does not exist" : "Não existe esta acção", "Configuration incorrect" : "Configuração incorreta", "Configuration incomplete" : "Configuração incompleta", "Configuration OK" : "Configuração OK", diff --git a/apps/user_ldap/l10n/pt_PT.json b/apps/user_ldap/l10n/pt_PT.json index 94e5cb6c3af..2b0c81a96f4 100644 --- a/apps/user_ldap/l10n/pt_PT.json +++ b/apps/user_ldap/l10n/pt_PT.json @@ -8,6 +8,7 @@ "No configuration specified" : "Nenhuma configuração especificada", "No data specified" : "Nenhuma data especificada", " Could not set configuration %s" : "Não foi possível definir a configuração %s", + "Action does not exist" : "Não existe esta acção", "Configuration incorrect" : "Configuração incorreta", "Configuration incomplete" : "Configuração incompleta", "Configuration OK" : "Configuração OK", diff --git a/apps/user_ldap/lib/ldap.php b/apps/user_ldap/lib/ldap.php index b4ca3499f49..74df3dd8ae7 100644 --- a/apps/user_ldap/lib/ldap.php +++ b/apps/user_ldap/lib/ldap.php @@ -26,6 +26,8 @@ namespace OCA\user_ldap\lib; +use OC\ServerNotAvailableException; + class LDAP implements ILDAPWrapper { protected $curFunc = ''; protected $curArgs = array(); @@ -283,6 +285,8 @@ class LDAP implements ILDAPWrapper { //for now } else if ($errorCode === 10) { //referrals, we switch them off, but then there is AD :) + } else if ($errorCode === -1) { + throw new ServerNotAvailableException('Lost connection to LDAP server.'); } else { \OCP\Util::writeLog('user_ldap', 'LDAP error '.$errorMsg.' (' . diff --git a/apps/user_ldap/tests/integration/exceptionOnLostConnection.php b/apps/user_ldap/tests/integration/exceptionOnLostConnection.php new file mode 100644 index 00000000000..a55d4822689 --- /dev/null +++ b/apps/user_ldap/tests/integration/exceptionOnLostConnection.php @@ -0,0 +1,192 @@ +<?php +/** + * @author Arthur Schiwon <blizzz@owncloud.com> + * + * @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/> + * + */ + +use OC\ServerNotAvailableException; +use OCA\user_ldap\lib\LDAP; + +/** + * Class ExceptionOnLostConnection + * + * integration test, ensures that an exception is thrown, when the connection is lost. + * + * LDAP must be available via toxiproxy. + * + * This test must be run manually. + * + */ +class ExceptionOnLostConnection { + /** @var string */ + private $toxiProxyHost; + + /** @var string */ + private $toxiProxyName; + + /** @var string */ + private $ldapBase; + + /** @var string|null */ + private $ldapBindDN; + + /** @var string|null */ + private $ldapBindPwd; + + /** @var string */ + private $ldapHost; + + /** @var OCA\user_ldap\lib\LDAP */ + private $ldap; + + /** @var bool */ + private $originalProxyState; + + /** + * @param string $proxyHost host of toxiproxy as url, like http://localhost:8474 + * @param string $proxyName name of the LDAP proxy service as configured in toxiProxy + * @param string $ldapBase any valid LDAP base DN + * @param null $bindDN optional, bind DN if anonymous bind is not possible + * @param null $bindPwd optional + */ + public function __construct($proxyHost, $proxyName, $ldapBase, $bindDN = null, $bindPwd = null) { + $this->toxiProxyHost = $proxyHost; + $this->toxiProxyName = $proxyName; + $this->ldapBase = $ldapBase; + $this->ldapBindDN = $bindDN; + $this->ldapBindPwd = $bindPwd; + + $this->setUp(); + } + + /** + * destructor + */ + public function __destruct() { + $this->cleanUp(); + } + + /** + * prepares everything for the test run. Includes loading ownCloud and + * the LDAP backend, as well as getting information about toxiproxy. + * Also creates an instance of the LDAP class, the testee + * + * @throws Exception + */ + public function setUp() { + require_once __DIR__ . '/../../../../lib/base.php'; + \OC_App::loadApps('user_ldap'); + + $ch = $this->getCurl(); + $proxyInfoJson = curl_exec($ch); + $this->checkCurlResult($ch, $proxyInfoJson); + $proxyInfo = json_decode($proxyInfoJson, true); + $this->originalProxyState = $proxyInfo['enabled']; + $this->ldapHost = 'ldap://' . $proxyInfo['listen']; // contains port as well + + $this->ldap = new LDAP(); + } + + /** + * restores original state of the LDAP proxy, if necessary + */ + public function cleanUp() { + if($this->originalProxyState === true) { + $this->setProxyState(true); + } + } + + /** + * runs the test and prints the result. Exit code is 0 if successful, 1 on + * fail + */ + public function run() { + if($this->originalProxyState === false) { + $this->setProxyState(true); + } + //host contains port, 2nd parameter will be ignored + $cr = $this->ldap->connect($this->ldapHost, 0); + $this->ldap->bind($cr, $this->ldapBindDN, $this->ldapBindPwd); + $this->ldap->search($cr, $this->ldapBase, 'objectClass=*', array('dn'), true, 5); + + // disable LDAP, will cause lost connection + $this->setProxyState(false); + try { + $this->ldap->search($cr, $this->ldapBase, 'objectClass=*', array('dn'), true, 5); + } catch (ServerNotAvailableException $e) { + print("Test PASSED" . PHP_EOL); + exit(0); + } + print("Test FAILED" . PHP_EOL); + exit(1); + } + + /** + * tests whether a curl operation ran successfully. If not, an exception + * is thrown + * + * @param resource $ch + * @param mixed $result + * @throws Exception + */ + private function checkCurlResult($ch, $result) { + if($result === false) { + $error = curl_error($ch); + curl_close($ch); + throw new \Exception($error); + } + } + + /** + * enables or disabled the LDAP proxy service in toxiproxy + * + * @param bool $isEnabled whether is should be enabled or disables + * @throws Exception + */ + private function setProxyState($isEnabled) { + if(!is_bool($isEnabled)) { + throw new \InvalidArgumentException('Bool expected'); + } + $postData = json_encode(['enabled' => $isEnabled]); + $ch = $this->getCurl(); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); + curl_setopt($ch, CURLOPT_HTTPHEADER, array( + 'Content-Type: application/json', + 'Content-Length: ' . strlen($postData)) + ); + $recvd = curl_exec($ch); + $this->checkCurlResult($ch, $recvd); + } + + /** + * initializes a curl handler towards the toxiproxy LDAP proxy service + * @return resource + */ + private function getCurl() { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $this->toxiProxyHost . '/proxies/' . $this->toxiProxyName); + curl_setopt($ch, CURLOPT_HEADER, false); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + return $ch; + } +} + +$test = new ExceptionOnLostConnection('http://localhost:8474', 'ldap', 'dc=owncloud,dc=bzoc'); +$test->run(); + diff --git a/autotest.sh b/autotest.sh index 8b8017eba80..3ce88c64974 100755 --- a/autotest.sh +++ b/autotest.sh @@ -53,11 +53,18 @@ if ! [ -x "$PHPUNIT" ]; then exit 3 fi -PHPUNIT_VERSION=$("$PHP" "$PHPUNIT" --version | cut -d" " -f2) -PHPUNIT_MAJOR_VERSION=$(echo $PHPUNIT_VERSION | cut -d"." -f1) -PHPUNIT_MINOR_VERSION=$(echo $PHPUNIT_VERSION | cut -d"." -f2) +# PHPUnit might also be installed via a facade binary script +if [[ "$PHPUNIT" =~ \.phar$ ]]; then + PHPUNIT=( "$PHP" "$PHPUNIT" ) +else + PHPUNIT=( "$PHPUNIT" ) +fi + +PHPUNIT_VERSION=$($PHPUNIT --version | cut -d" " -f2) +PHPUNIT_MAJOR_VERSION=$(echo "$PHPUNIT_VERSION" | cut -d"." -f1) +PHPUNIT_MINOR_VERSION=$(echo "$PHPUNIT_VERSION" | cut -d"." -f2) -if ! [ $PHPUNIT_MAJOR_VERSION -gt 3 -o \( $PHPUNIT_MAJOR_VERSION -eq 3 -a $PHPUNIT_MINOR_VERSION -ge 7 \) ]; then +if ! [ "$PHPUNIT_MAJOR_VERSION" -gt 3 -o \( "$PHPUNIT_MAJOR_VERSION" -eq 3 -a "$PHPUNIT_MINOR_VERSION" -ge 7 \) ]; then echo "phpunit version >= 3.7 required. Version found: $PHPUNIT_VERSION" >&2 exit 4 fi @@ -70,7 +77,7 @@ fi if [ "$1" ]; then FOUND=0 for DBCONFIG in $DBCONFIGS; do - if [ "$1" = $DBCONFIG ]; then + if [ "$1" = "$DBCONFIG" ]; then FOUND=1 break fi @@ -90,7 +97,7 @@ fi function cleanup_config { if [ ! -z "$DOCKER_CONTAINER_ID" ]; then echo "Kill the docker $DOCKER_CONTAINER_ID" - docker rm -f $DOCKER_CONTAINER_ID + docker rm -f "$DOCKER_CONTAINER_ID" fi cd "$BASEDIR" @@ -132,15 +139,15 @@ function execute_tests { # drop database if [ "$1" == "mysql" ] ; then - mysql -u $DATABASEUSER -powncloud -e "DROP DATABASE IF EXISTS $DATABASENAME" -h $DATABASEHOST || true + mysql -u "$DATABASEUSER" -powncloud -e "DROP DATABASE IF EXISTS $DATABASENAME" -h $DATABASEHOST || true fi if [ "$1" == "pgsql" ] ; then - dropdb -U $DATABASEUSER $DATABASENAME || true + dropdb -U "$DATABASEUSER" "$DATABASENAME" || true fi if [ "$1" == "oci" ] ; then echo "Fire up the oracle docker" - DOCKER_CONTAINER_ID=`docker run -d deepdiver/docker-oracle-xe-11g` - DATABASEHOST=`docker inspect $DOCKER_CONTAINER_ID | grep IPAddress | cut -d '"' -f 4` + DOCKER_CONTAINER_ID=$(docker run -d deepdiver/docker-oracle-xe-11g) + DATABASEHOST=$(docker inspect "$DOCKER_CONTAINER_ID" | grep IPAddress | cut -d '"' -f 4) echo "Waiting 60 seconds for Oracle initialization ... " sleep 60 @@ -151,7 +158,7 @@ function execute_tests { # trigger installation echo "Installing ...." - "$PHP" ./occ maintenance:install --database=$1 --database-name=$DATABASENAME --database-host=$DATABASEHOST --database-user=$DATABASEUSER --database-pass=owncloud --database-table-prefix=oc_ --admin-user=$ADMINLOGIN --admin-pass=admin --data-dir=$DATADIR + "$PHP" ./occ maintenance:install --database="$1" --database-name="$DATABASENAME" --database-host="$DATABASEHOST" --database-user="$DATABASEUSER" --database-pass=owncloud --database-table-prefix=oc_ --admin-user="$ADMINLOGIN" --admin-pass=admin --data-dir="$DATADIR" #test execution echo "Testing with $1 ..." @@ -160,11 +167,11 @@ function execute_tests { mkdir "coverage-html-$1" "$PHP" -f enable_all.php | grep -i -C9999 error && echo "Error during setup" && exit 101 if [ -z "$NOCOVERAGE" ]; then - "$PHP" "$PHPUNIT" --configuration phpunit-autotest.xml --log-junit "autotest-results-$1.xml" --coverage-clover "autotest-clover-$1.xml" --coverage-html "coverage-html-$1" "$2" "$3" + "${PHPUNIT[@]}" --configuration phpunit-autotest.xml --log-junit "autotest-results-$1.xml" --coverage-clover "autotest-clover-$1.xml" --coverage-html "coverage-html-$1" "$2" "$3" RESULT=$? else echo "No coverage" - "$PHP" "$PHPUNIT" --configuration phpunit-autotest.xml --log-junit "autotest-results-$1.xml" "$2" "$3" + "${PHPUNIT[@]}" --configuration phpunit-autotest.xml --log-junit "autotest-results-$1.xml" "$2" "$3" RESULT=$? fi } @@ -176,7 +183,7 @@ if [ -z "$1" ] then # run all known database configs for DBCONFIG in $DBCONFIGS; do - execute_tests $DBCONFIG + execute_tests "$DBCONFIG" done else FILENAME="$2" diff --git a/config/ca-bundle.crt b/config/ca-bundle.crt index 7366a6dfaf7..c93d3c4d4a7 100644 --- a/config/ca-bundle.crt +++ b/config/ca-bundle.crt @@ -1,7 +1,7 @@ ## ## Bundle of CA Root Certificates ## -## Certificate data from Mozilla as of: Wed Feb 25 16:40:11 2015 +## Certificate data from Mozilla as of: Mon Apr 27 08:58:04 2015 ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates @@ -14,7 +14,7 @@ ## Just configure this file as the SSLCACertificateFile. ## ## Conversion done with mk-ca-bundle.pl version 1.25. -## SHA1: f9bc9fa76145720d94124527f82a7185d921975e +## SHA1: ed3c0bbfb7912bcc00cd2033b0cb85c98d10559c ## @@ -174,23 +174,6 @@ Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp -----END CERTIFICATE----- -Equifax Secure Global eBusiness CA -================================== ------BEGIN CERTIFICATE----- -MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT -RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp -bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx -HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds -b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV -PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN -qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn -hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j -BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs -MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN -I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY -NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV ------END CERTIFICATE----- - AddTrust Low-Value Services Root ================================ -----BEGIN CERTIFICATE----- @@ -1633,33 +1616,6 @@ JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk vQ== -----END CERTIFICATE----- -TC TrustCenter Class 3 CA II -============================ ------BEGIN CERTIFICATE----- -MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC -REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy -IENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYw -MTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 -c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UE -AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJWHt4bNwcwIi9v8Qbxq63W -yKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+QVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo -6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZ -uV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk -2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB -7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 -Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU -cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i -SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u -TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzE -O2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8 -yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9 -IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal -092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc -5A== ------END CERTIFICATE----- - TC TrustCenter Universal CA I ============================= -----BEGIN CERTIFICATE----- @@ -2277,28 +2233,6 @@ yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi LXpUq3DDfSJlgnCW -----END CERTIFICATE----- -E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi -=================================================== ------BEGIN CERTIFICATE----- -MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG -EwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoGA1UEAxMz -ZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3 -MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0 -cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9u -aWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdUMZTe1RK6UxYC6lhj71vY -8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlTL/jDj/6z/P2douNffb7tC+Bg62nsM+3Y -jfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAI -JjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk -9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQD -AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqG -SIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5d -F4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwq -D2fK/A+JYZ1lpTzlvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4 -Vwpm+Vganf2XKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq -fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX ------END CERTIFICATE----- - GlobalSign Root CA - R3 ======================= -----BEGIN CERTIFICATE----- @@ -3857,4 +3791,198 @@ h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7 yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA - G3 +================================== +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE +CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g +Um9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloXDTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMC +TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l +ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4y +olQPcPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WWIkYFsO2t +x1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqXxz8ecAgwoNzFs21v0IJy +EavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFyKJLZWyNtZrVtB0LrpjPOktvA9mxjeM3K +Tj215VKb8b475lRgsGYeCasH/lSJEULR9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUur +mkVLoR9BvUhTFXFkC4az5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU5 +1nus6+N86U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7Ngzp +07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHPbMk7ccHViLVlvMDo +FxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXtBznaqB16nzaeErAMZRKQFWDZJkBE +41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTtXUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleu +yjWcLhL75LpdINyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD +U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwpLiniyMMB8jPq +KqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8Ipf3YF3qKS9Ysr1YvY2WTxB1 +v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixpgZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA +8KCWAg8zxXHzniN9lLf9OtMJgwYh/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b +8KKaa8MFSu1BYBQw0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0r +mj1AfsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq4BZ+Extq +1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR1VmiiXTTn74eS9fGbbeI +JG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/QFH1T/U67cjF68IeHRaVesd+QnGTbksV +tzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM94B7IWcnMFk= +-----END CERTIFICATE----- + +Staat der Nederlanden EV Root CA +================================ +-----BEGIN CERTIFICATE----- +MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJOTDEeMBwGA1UE +CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFhdCBkZXIgTmVkZXJsYW5kZW4g +RVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0yMjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5M +MR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRl +cmxhbmRlbiBFViBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkk +SzrSM4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nCUiY4iKTW +O0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3dZ//BYY1jTw+bbRcwJu+r +0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46prfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8 +Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13lpJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gV +XJrm0w912fxBmJc+qiXbj5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr +08C+eKxCKFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS/ZbV +0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0XcgOPvZuM5l5Tnrmd +74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH1vI4gnPah1vlPNOePqc7nvQDs/nx +fRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrPpx9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwa +ivsnuL8wbqg7MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI +eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u2dfOWBfoqSmu +c0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHSv4ilf0X8rLiltTMMgsT7B/Zq +5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTCwPTxGfARKbalGAKb12NMcIxHowNDXLldRqAN +b/9Zjr7dn3LDWyvfjFvO5QxGbJKyCqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tN +f1zuacpzEPuKqf2evTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi +5Dp6Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIaGl6I6lD4 +WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeLeG9QgkRQP2YGiqtDhFZK +DyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGy +eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg== +-----END CERTIFICATE----- + +IdenTrust Commercial Root CA 1 +============================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG +EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS +b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES +MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB +IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld +hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/ +mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi +1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C +XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl +3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy +NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV +WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg +xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix +uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI +hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg +ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt +ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV +YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX +feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro +kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe +2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz +Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R +cGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- + +IdenTrust Public Sector Root CA 1 +================================= +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG +EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv +ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV +UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS +b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy +P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6 +Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI +rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf +qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS +mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn +ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh +LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v +iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL +4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B +Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw +DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A +mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt +GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt +m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx +NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4 +Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI +ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC +ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ +3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- + +Entrust Root Certification Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy +bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug +b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw +HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT +DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx +OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP +/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz +HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU +s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y +TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx +AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6 +0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z +iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi +nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+ +vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO +e4pIb4tF9g== +-----END CERTIFICATE----- + +Entrust Root Certification Authority - EC1 +========================================== +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx +FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn +YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl +ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw +FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs +LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg +dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt +IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy +AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef +9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h +vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8 +kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- + +CFCA EV ROOT +============ +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE +CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB +IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw +MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD +DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV +BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD +7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN +uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW +ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7 +xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f +py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K +gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol +hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ +tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf +BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q +ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua +4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG +E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX +BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn +aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy +PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX +kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C +ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su -----END CERTIFICATE-----
\ No newline at end of file diff --git a/core/js/maintenance-check.js b/core/js/maintenance-check.js index 061a434214b..663f7fb5f00 100644 --- a/core/js/maintenance-check.js +++ b/core/js/maintenance-check.js @@ -3,10 +3,7 @@ window.setInterval(checkStatus, 20000); function checkStatus() { var request = new XMLHttpRequest(); - var ocroot = location.pathname.substr( - 0, location.pathname.indexOf('index.php') - ); - request.open("GET", ocroot+'status.php', true); + request.open("GET", OC.webroot+'/status.php', true); request.onreadystatechange = function() { if (request.readyState === 4) { var response = request.responseText; diff --git a/core/js/share.js b/core/js/share.js index 6723b829ca5..121ee97d17f 100644 --- a/core/js/share.js +++ b/core/js/share.js @@ -839,6 +839,24 @@ OC.Share={ $('#defaultExpireMessage').slideDown(OC.menuSpeed); } $.datepicker.setDefaults(datePickerOptions); + }, + /** + * Get the default Expire date + * + * @return {String} The expire date + */ + getDefaultExpirationDate:function() { + var expireDateString = ''; + if (oc_appconfig.core.defaultExpireDateEnabled) { + var date = new Date().getTime(); + var expireAfterMs = oc_appconfig.core.defaultExpireDate * 24 * 60 * 60 * 1000; + var expireDate = new Date(date + expireAfterMs); + var month = expireDate.getMonth() + 1; + var year = expireDate.getFullYear(); + var day = expireDate.getDate(); + expireDateString = year + "-" + month + '-' + day + ' 00:00:00'; + } + return expireDateString; } }; @@ -986,18 +1004,15 @@ $(document).ready(function() { $('#linkPassText').attr('placeholder', t('core', 'Choose a password for the public link')); // Reset link $('#linkText').val(''); + $('#showPassword').prop('checked', false); + $('#linkPass').hide(); + $('#sharingDialogAllowPublicUpload').prop('checked', false); + $('#expirationCheckbox').prop('checked', false); + $('#expirationDate').hide(); var expireDateString = ''; - if (oc_appconfig.core.defaultExpireDateEnabled) { - var date = new Date().getTime(); - var expireAfterMs = oc_appconfig.core.defaultExpireDate * 24 * 60 * 60 * 1000; - var expireDate = new Date(date + expireAfterMs); - var month = expireDate.getMonth() + 1; - var year = expireDate.getFullYear(); - var day = expireDate.getDate(); - expireDateString = year + "-" + month + '-' + day + ' 00:00:00'; - } // Create a link if (oc_appconfig.core.enforcePasswordForPublicLink === false) { + expireDateString = OC.Share.getDefaultExpirationDate(); $loading.removeClass('hidden'); $button.addClass('hidden'); $button.prop('disabled', true); @@ -1135,8 +1150,10 @@ $(document).ready(function() { permissions = OC.PERMISSION_READ; } + var expireDateString = OC.Share.getDefaultExpirationDate(); + $loading.removeClass('hidden'); - OC.Share.share(itemType, itemSource, OC.Share.SHARE_TYPE_LINK, $('#linkPassText').val(), permissions, itemSourceName, function(data) { + OC.Share.share(itemType, itemSource, OC.Share.SHARE_TYPE_LINK, $('#linkPassText').val(), permissions, itemSourceName, expireDateString, function(data) { $loading.addClass('hidden'); linkPassText.val(''); linkPassText.attr('placeholder', t('core', 'Password protected')); @@ -1145,8 +1162,12 @@ $(document).ready(function() { OC.Share.showLink(data.token, "password set", itemSource); OC.Share.updateIcon(itemType, itemSource); } + $('#dropdown').trigger(new $.Event('sharesChanged', {shares: OC.Share.currentShares})); }); + if (expireDateString !== '') { + OC.Share.showExpirationDate(expireDateString); + } } }); diff --git a/core/js/tests/specs/shareSpec.js b/core/js/tests/specs/shareSpec.js index 3e9a0b247d7..c075351b9f5 100644 --- a/core/js/tests/specs/shareSpec.js +++ b/core/js/tests/specs/shareSpec.js @@ -228,6 +228,112 @@ describe('OC.Share tests', function() { oc_appconfig.core.enforcePasswordForPublicLink = old; }); + it('reset password on toggle of share', function() { + $('#allowShareWithLink').val('yes'); + OC.Share.showDropDown( + 'file', + 123, + $container, + true, + 31, + 'shared_file_name.txt' + ); + $('#dropdown [name=linkCheckbox]').click(); + fakeServer.requests[0].respond( + 200, + { 'Content-Type': 'application/json' }, + JSON.stringify({data: {token: 'xyz'}, status: 'success'}) + ); + + //Password protection should be unchecked and password field not visible + expect($('#dropdown [name=showPassword]').prop('checked')).toEqual(false); + expect($('#dropdown #linkPass').is(":visible")).toEqual(false); + + // Toggle and set password + $('#dropdown [name=showPassword]').click(); + $('#dropdown #linkPassText').val('foo'); + $('#dropdown #linkPassText').trigger(new $.Event('keyup', {keyCode: 13})); + fakeServer.requests[1].respond( + 200, + { 'Content-Type': 'application/json' }, + JSON.stringify({data: {token: 'xyz2'}, status: 'success'}) + ); + + // Unshare + $('#dropdown [name=linkCheckbox]').click(); + fakeServer.requests[2].respond( + 200, + { 'Content-Type': 'application/json' }, + JSON.stringify({status: 'success'}) + ); + + // Toggle share again + $('#dropdown [name=linkCheckbox]').click(); + fakeServer.requests[3].respond( + 200, + { 'Content-Type': 'application/json' }, + JSON.stringify({data: {token: 'xyz3'}, status: 'success'}) + ); + + + // Password checkbox should be unchecked + expect($('#dropdown [name=showPassword]').prop('checked')).toEqual(false); + expect($('#dropdown #linkPass').is(":visible")).toEqual(false); + }); + it('reset expiration on toggle of share', function() { + $('#allowShareWithLink').val('yes'); + OC.Share.showDropDown( + 'file', + 123, + $container, + true, + 31, + 'shared_file_name.txt' + ); + $('#dropdown [name=linkCheckbox]').click(); + fakeServer.requests[0].respond( + 200, + { 'Content-Type': 'application/json' }, + JSON.stringify({data: {token: 'xyz'}, status: 'success'}) + ); + + //Expiration should be unchecked and expiration field not visible + expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(false); + expect($('#dropdown #expirationDate').is(":visible")).toEqual(false); + + // Toggle and set password + $('#dropdown [name=expirationCheckbox]').click(); + d = new Date(); + d.setDate(d.getDate() + 1); + date=d.getDate() + '-' + (d.getMonth()+1) + '-' + d.getFullYear(); + $('#dropdown #expirationDate').val(date); + $('#dropdown #expirationDate').change(); + fakeServer.requests[1].respond( + 200, + { 'Content-Type': 'application/json' }, + JSON.stringify({data: {token: 'xyz2'}, status: 'success'}) + ); + + // Unshare + $('#dropdown [name=linkCheckbox]').click(); + fakeServer.requests[2].respond( + 200, + { 'Content-Type': 'application/json' }, + JSON.stringify({status: 'success'}) + ); + + // Toggle share again + $('#dropdown [name=linkCheckbox]').click(); + fakeServer.requests[3].respond( + 200, + { 'Content-Type': 'application/json' }, + JSON.stringify({data: {token: 'xyz3'}, status: 'success'}) + ); + + // Recheck expire visibility + expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(false); + expect($('#dropdown #expirationDate').is(":visible")).toEqual(false); + }); it('shows populated link share when a link share exists', function() { loadItemStub.returns({ reshare: [], @@ -419,6 +525,7 @@ describe('OC.Share tests', function() { }; loadItemStub.returns(shareData); oc_appconfig.core.defaultExpireDate = 7; + oc_appconfig.core.enforcePasswordForPublicLink = false; oc_appconfig.core.defaultExpireDateEnabled = false; oc_appconfig.core.defaultExpireDateEnforced = false; }); @@ -474,6 +581,32 @@ describe('OC.Share tests', function() { $('#dropdown [name=expirationCheckbox]').click(); expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(true); }); + it('enforces default date when enforced date setting is enabled and password is enforced', function() { + /* jshint camelcase:false */ + oc_appconfig.core.enforcePasswordForPublicLink = true; + oc_appconfig.core.defaultExpireDateEnabled = true; + oc_appconfig.core.defaultExpireDateEnforced = true; + showDropDown(); + $('#dropdown [name=linkCheckbox]').click(); + + //Enter password + $('#dropdown #linkPassText').val('foo'); + $('#dropdown #linkPassText').trigger(new $.Event('keyup', {keyCode: 13})); + fakeServer.requests[0].respond( + 200, + { 'Content-Type': 'application/json' }, + JSON.stringify({data: {token: 'xyz'}, status: 'success'}) + ); + + expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(true); + // TODO: those zeros must go... + expect($('#dropdown #expirationDate').val()).toEqual('2014-1-27 00:00:00'); + + // disabling is not allowed + expect($('#dropdown [name=expirationCheckbox]').prop('disabled')).toEqual(true); + $('#dropdown [name=expirationCheckbox]').click(); + expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(true); + }); it('displayes email form when sending emails is enabled', function() { $('input[name=mailPublicNotificationEnabled]').val('yes'); showDropDown(); diff --git a/lib/private/connector/sabre/file.php b/lib/private/connector/sabre/file.php index cfa1cacdd0b..8e4460ef3b5 100644 --- a/lib/private/connector/sabre/file.php +++ b/lib/private/connector/sabre/file.php @@ -161,13 +161,37 @@ class File extends Node implements IFile { } try { + $view = \OC\Files\Filesystem::getView(); + $run = true; + if ($view) { + $hookPath = $view->getRelativePath($this->fileView->getAbsolutePath($this->path)); + + if (!$exists) { + \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_create, array( + \OC\Files\Filesystem::signal_param_path => $hookPath, + \OC\Files\Filesystem::signal_param_run => &$run, + )); + } else { + \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_update, array( + \OC\Files\Filesystem::signal_param_path => $hookPath, + \OC\Files\Filesystem::signal_param_run => &$run, + )); + } + \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_write, array( + \OC\Files\Filesystem::signal_param_path => $hookPath, + \OC\Files\Filesystem::signal_param_run => &$run, + )); + } + if ($needsPartFile) { // rename to correct path try { - $renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath); - $fileExists = $storage->file_exists($internalPath); - if ($renameOkay === false || $fileExists === false) { - \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); + if ($run) { + $renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath); + $fileExists = $storage->file_exists($internalPath); + } + if (!$run || $renameOkay === false || $fileExists === false) { + \OC_Log::write('webdav', 'renaming part file to final file failed', \OC_Log::ERROR); $partStorage->unlink($internalPartPath); throw new Exception('Could not rename part file to final file'); } @@ -180,9 +204,7 @@ class File extends Node implements IFile { // since we skipped the view we need to scan and emit the hooks ourselves $partStorage->getScanner()->scanFile($internalPath); - $view = \OC\Files\Filesystem::getView(); if ($view) { - $hookPath = $view->getRelativePath($this->fileView->getAbsolutePath($this->path)); $this->fileView->getUpdater()->propagate($hookPath); if (!$exists) { \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_create, array( diff --git a/lib/private/encryption/keys/storage.php b/lib/private/encryption/keys/storage.php index 118c8dc920d..6aa00c5b5ee 100644 --- a/lib/private/encryption/keys/storage.php +++ b/lib/private/encryption/keys/storage.php @@ -125,10 +125,9 @@ class Storage implements IStorage { /** * @inheritdoc */ - public function deleteAllFileKeys($path, $encryptionModuleId) { - $keyDir = $this->getFileKeyDir($encryptionModuleId, $path); - $path = dirname($keyDir); - return !$this->view->file_exists($path) || $this->view->deleteAll($path); + public function deleteAllFileKeys($path) { + $keyDir = $this->getFileKeyDir('', $path); + return !$this->view->file_exists($keyDir) || $this->view->deleteAll($keyDir); } /** @@ -208,17 +207,10 @@ class Storage implements IStorage { * @param string $encryptionModuleId * @param string $path path to the file, relative to data/ * @return string - * @throws GenericEncryptionException - * @internal param string $keyId */ private function getFileKeyDir($encryptionModuleId, $path) { - if ($this->view->is_dir($path)) { - throw new GenericEncryptionException("file was expected but directory was given: $path"); - } - list($owner, $filename) = $this->util->getUidAndFilename($path); - $filename = $this->util->stripPartialFileExtension($filename); // in case of system wide mount points the keys are stored directly in the data directory if ($this->util->isSystemWideMountPoint($filename, $owner)) { diff --git a/lib/private/files/storage/wrapper/encryption.php b/lib/private/files/storage/wrapper/encryption.php index c42e6d439fd..f7759d91497 100644 --- a/lib/private/files/storage/wrapper/encryption.php +++ b/lib/private/files/storage/wrapper/encryption.php @@ -206,8 +206,7 @@ class Encryption extends Wrapper { $encryptionModule = $this->getEncryptionModule($path); if ($encryptionModule) { - $this->keyStorage->deleteAllFileKeys($this->getFullPath($path), - $encryptionModule->getId()); + $this->keyStorage->deleteAllFileKeys($this->getFullPath($path)); } return $this->storage->unlink($path); @@ -239,6 +238,21 @@ class Encryption extends Wrapper { } /** + * see http://php.net/manual/en/function.rmdir.php + * + * @param string $path + * @return bool + */ + public function rmdir($path) { + $result = $this->storage->rmdir($path); + if ($result && $this->encryptionManager->isEnabled()) { + $this->keyStorage->deleteAllFileKeys($this->getFullPath($path)); + } + + return $result; + } + + /** * see http://php.net/manual/en/function.copy.php * * @param string $path1 @@ -269,8 +283,13 @@ class Encryption extends Wrapper { } } $data = $this->getMetaData($path1); - $this->getCache()->put($path2, ['encrypted' => $data['encrypted']]); - $this->updateUnencryptedSize($fullPath2, $data['size']); + + if (isset($data['encrypted'])) { + $this->getCache()->put($path2, ['encrypted' => $data['encrypted']]); + } + if (isset($data['size'])) { + $this->updateUnencryptedSize($fullPath2, $data['size']); + } } return $result; diff --git a/lib/private/helper.php b/lib/private/helper.php index 144ccbfe228..981447c213b 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -394,6 +394,9 @@ class OC_Helper { */ public static function computerFileSize($str) { $str = strtolower($str); + if (is_numeric($str)) { + return $str; + } $bytes_array = array( 'b' => 1, @@ -413,6 +416,8 @@ class OC_Helper { if (preg_match('#([kmgtp]?b?)$#si', $str, $matches) && !empty($bytes_array[$matches[1]])) { $bytes *= $bytes_array[$matches[1]]; + } else { + return false; } $bytes = round($bytes); diff --git a/lib/public/encryption/keys/istorage.php b/lib/public/encryption/keys/istorage.php index 752c073375d..17677814107 100644 --- a/lib/public/encryption/keys/istorage.php +++ b/lib/public/encryption/keys/istorage.php @@ -129,12 +129,11 @@ interface IStorage { * delete all file keys for a given file * * @param string $path to the file - * @param string $encryptionModuleId * * @return boolean False when the keys could not be deleted * @since 8.1.0 */ - public function deleteAllFileKeys($path, $encryptionModuleId); + public function deleteAllFileKeys($path); /** * delete system-wide encryption keys not related to a specific user, diff --git a/settings/changepassword/controller.php b/settings/changepassword/controller.php index 4a68636d3f8..94323fc2fcc 100644 --- a/settings/changepassword/controller.php +++ b/settings/changepassword/controller.php @@ -113,30 +113,27 @@ class Controller { $recoveryEnabledForUser = false; if ($recoveryAdminEnabled) { $validRecoveryPassword = $keyManager->checkRecoveryPassword($recoveryPassword); - $recoveryEnabledForUser = $recovery->isRecoveryEnabledForUser(); + $recoveryEnabledForUser = $recovery->isRecoveryEnabledForUser($username); } + $l = new \OC_L10n('settings'); if ($recoveryEnabledForUser && $recoveryPassword === '') { - $l = new \OC_L10n('settings'); \OC_JSON::error(array('data' => array( 'message' => $l->t('Please provide an admin recovery password, otherwise all user data will be lost') ))); } elseif ($recoveryEnabledForUser && ! $validRecoveryPassword) { - $l = new \OC_L10n('settings'); \OC_JSON::error(array('data' => array( 'message' => $l->t('Wrong admin recovery password. Please check the password and try again.') ))); } else { // now we know that everything is fine regarding the recovery password, let's try to change the password $result = \OC_User::setPassword($username, $password, $recoveryPassword); if (!$result && $recoveryEnabledForUser) { - $l = new \OC_L10n('settings'); \OC_JSON::error(array( "data" => array( "message" => $l->t("Backend doesn't support password change, but the user's encryption key was successfully updated.") ) )); } elseif (!$result && !$recoveryEnabledForUser) { - $l = new \OC_L10n('settings'); \OC_JSON::error(array("data" => array( "message" => $l->t("Unable to change password" ) ))); } else { \OC_JSON::success(array("data" => array( "username" => $username ))); @@ -147,7 +144,6 @@ class Controller { if (!is_null($password) && \OC_User::setPassword($username, $password)) { \OC_JSON::success(array('data' => array('username' => $username))); } else { - $l = new \OC_L10n('settings'); \OC_JSON::error(array('data' => array('message' => $l->t('Unable to change password')))); } } diff --git a/settings/controller/userscontroller.php b/settings/controller/userscontroller.php index e9ffc36904e..d0b5267e3c8 100644 --- a/settings/controller/userscontroller.php +++ b/settings/controller/userscontroller.php @@ -122,10 +122,10 @@ class UsersController extends Controller { $this->subAdminFactory = $subAdminFactory; // check for encryption state - TODO see formatUserForIndex - $this->isEncryptionAppEnabled = $appManager->isEnabledForUser('files_encryption'); + $this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption'); if($this->isEncryptionAppEnabled) { // putting this directly in empty is possible in PHP 5.5+ - $result = $config->getAppValue('files_encryption', 'recoveryAdminEnabled', 0); + $result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0); $this->isRestoreEnabled = !empty($result); } } @@ -148,7 +148,7 @@ class UsersController extends Controller { if ($this->isEncryptionAppEnabled) { if ($this->isRestoreEnabled) { // check for the users recovery setting - $recoveryMode = $this->config->getUserValue($user->getUID(), 'files_encryption', 'recovery_enabled', '0'); + $recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0'); // method call inside empty is possible with PHP 5.5+ $recoveryModeEnabled = !empty($recoveryMode); if ($recoveryModeEnabled) { diff --git a/settings/l10n/id.js b/settings/l10n/id.js index c3064a071a2..177e2f70f95 100644 --- a/settings/l10n/id.js +++ b/settings/l10n/id.js @@ -56,7 +56,7 @@ OC.L10N.register( "All" : "Semua", "Official apps are developed by and within the ownCloud community. They offer functionality central to ownCloud and are ready for production use." : "Aplikasi resmi dikembangkan oleh komunitas ownCloud. Mereka menawarkan fitur pusat bagi ownCloud dan siap digunakan untuk penggunaan produksi.", "Approved apps are developed by trusted developers and have passed a cursory security check. They are actively maintained in an open code repository and their maintainers deem them to be stable for casual to normal use." : "Aplikasi tersetujui dikembangkan oleh pengembang terpercaya dan telah lulus pemeriksaan keamanan. Mereka secara aktif dipelihara direpositori kode terbuka dan pemelihara sudah memastikan mereka stabil untuk penggunaan normal.", - "This app is not checked for security issues and is new or known to be unstable. Install on your own risk." : "Aplikasi ini belum diperiksa masalah keamanan dan baru atau dikenal tidak stabil. Instal dengan resiko.", + "This app is not checked for security issues and is new or known to be unstable. Install on your own risk." : "Aplikasi ini belum diperiksa masalah keamanan dan masih baru atau dikenal tidak stabil. Instal dengan resiko.", "Please wait...." : "Mohon tunggu....", "Error while disabling app" : "Terjadi kesalahan saat menonaktifkan aplikasi", "Disable" : "Nonaktifkan", @@ -143,6 +143,12 @@ OC.L10N.register( "cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "cron.php didaftarkan pada layanan webcron untuk memanggil cron.php setiap 15 menit melalui http.", "Use system's cron service to call the cron.php file every 15 minutes." : "Gunakan layanan cron sistem untuk memanggil berkas cron.php setiap 15 menit.", "Enable server-side encryption" : "Aktifkan enkripsi sisi-server", + "Encryption is a one way process. Once encryption is enabled, all files from that point forward will be encrypted on the server and it will not be possible to disable encryption at a later date. This is the final warning: Do you really want to enable encryption?" : "Enkripsi adalah proses satu arah. Setelah enkripsi diaktifkan, semua berkas mulai saat ini akan di enkrispi pada server dan tidak mungkin untuk menonaktifkan enkrispi dikemudian hari. Ini merupakan peringatan terakhir: Apakah Anda yakin ingin mengaktifkan enkripsi?", + "Enable encryption" : "Aktifkan enkripsi", + "No encryption module loaded, please enable an encryption module in the app menu." : "Tidak ada modul enkripsi yang dimuat, mohon aktifkan modul enkripsi di menu aplikasi.", + "Select default encryption module:" : "Pilih modul enkripsi baku:", + "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please enable the \"ownCloud Default Encryption Module\" and run 'occ encryption:migrate'" : "Anda perlu untuk mengubah kunci enkripsi dari enkripsi lama (ownCloud <= 8.0) ke yang baru. Mohon aktifkan \"Modul Enkripsi Baku ownCloud\" dan jalankan 'occ encryption:migrate'", + "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one." : "Anda perlu untuk mengubah kunci enkripsi dari enkripsi lama (ownCloud <= 8.0) ke yang baru.", "Start migration" : "Mulai migrasi", "This is used for sending out notifications." : "Ini digunakan untuk mengirim notifikasi keluar.", "Send mode" : "Modus kirim", @@ -167,11 +173,12 @@ OC.L10N.register( "SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite digunakan sebagai basis data. Untuk instalasi yang lebih besar, kami menyarankan untuk beralih ke backend basis data yang berbeda.", "Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Terutama saat menggunakan klien desktop untuk sinkronisasi berkas, penggunaan SQLite tidak disarankan.", "To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Untuk migrasi ke basis data lainnya, gunakan alat baris perintah: 'occ db:convert-type', atau lihat <a target=\"_blank\" href=\"%s\">dokumentasi ↗</a>.", - "How to do backups" : "Bagaimana cara mencadangkan", + "How to do backups" : "Bagaimana cara membuat cadangan", "Advanced monitoring" : "Pemantauan tingkat lanjut", "Performance tuning" : "Pemeliharaan performa", "Improving the config.php" : "Memperbaiki config.php", "Theming" : "Tema", + "Hardening and security guidance" : "Panduan Keselamatan dan Keamanan", "Version" : "Versi", "Developer documentation" : "Dokumentasi pengembang", "Experimental applications ahead" : "Aplikasi percobaan terdepan", @@ -261,6 +268,6 @@ OC.L10N.register( "change full name" : "ubah nama lengkap", "set new password" : "setel sandi baru", "change email address" : "ubah alamat email", - "Default" : "Default" + "Default" : "Baku" }, "nplurals=1; plural=0;"); diff --git a/settings/l10n/id.json b/settings/l10n/id.json index f720eb2fc03..30acbef09c2 100644 --- a/settings/l10n/id.json +++ b/settings/l10n/id.json @@ -54,7 +54,7 @@ "All" : "Semua", "Official apps are developed by and within the ownCloud community. They offer functionality central to ownCloud and are ready for production use." : "Aplikasi resmi dikembangkan oleh komunitas ownCloud. Mereka menawarkan fitur pusat bagi ownCloud dan siap digunakan untuk penggunaan produksi.", "Approved apps are developed by trusted developers and have passed a cursory security check. They are actively maintained in an open code repository and their maintainers deem them to be stable for casual to normal use." : "Aplikasi tersetujui dikembangkan oleh pengembang terpercaya dan telah lulus pemeriksaan keamanan. Mereka secara aktif dipelihara direpositori kode terbuka dan pemelihara sudah memastikan mereka stabil untuk penggunaan normal.", - "This app is not checked for security issues and is new or known to be unstable. Install on your own risk." : "Aplikasi ini belum diperiksa masalah keamanan dan baru atau dikenal tidak stabil. Instal dengan resiko.", + "This app is not checked for security issues and is new or known to be unstable. Install on your own risk." : "Aplikasi ini belum diperiksa masalah keamanan dan masih baru atau dikenal tidak stabil. Instal dengan resiko.", "Please wait...." : "Mohon tunggu....", "Error while disabling app" : "Terjadi kesalahan saat menonaktifkan aplikasi", "Disable" : "Nonaktifkan", @@ -141,6 +141,12 @@ "cron.php is registered at a webcron service to call cron.php every 15 minutes over http." : "cron.php didaftarkan pada layanan webcron untuk memanggil cron.php setiap 15 menit melalui http.", "Use system's cron service to call the cron.php file every 15 minutes." : "Gunakan layanan cron sistem untuk memanggil berkas cron.php setiap 15 menit.", "Enable server-side encryption" : "Aktifkan enkripsi sisi-server", + "Encryption is a one way process. Once encryption is enabled, all files from that point forward will be encrypted on the server and it will not be possible to disable encryption at a later date. This is the final warning: Do you really want to enable encryption?" : "Enkripsi adalah proses satu arah. Setelah enkripsi diaktifkan, semua berkas mulai saat ini akan di enkrispi pada server dan tidak mungkin untuk menonaktifkan enkrispi dikemudian hari. Ini merupakan peringatan terakhir: Apakah Anda yakin ingin mengaktifkan enkripsi?", + "Enable encryption" : "Aktifkan enkripsi", + "No encryption module loaded, please enable an encryption module in the app menu." : "Tidak ada modul enkripsi yang dimuat, mohon aktifkan modul enkripsi di menu aplikasi.", + "Select default encryption module:" : "Pilih modul enkripsi baku:", + "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one. Please enable the \"ownCloud Default Encryption Module\" and run 'occ encryption:migrate'" : "Anda perlu untuk mengubah kunci enkripsi dari enkripsi lama (ownCloud <= 8.0) ke yang baru. Mohon aktifkan \"Modul Enkripsi Baku ownCloud\" dan jalankan 'occ encryption:migrate'", + "You need to migrate your encryption keys from the old encryption (ownCloud <= 8.0) to the new one." : "Anda perlu untuk mengubah kunci enkripsi dari enkripsi lama (ownCloud <= 8.0) ke yang baru.", "Start migration" : "Mulai migrasi", "This is used for sending out notifications." : "Ini digunakan untuk mengirim notifikasi keluar.", "Send mode" : "Modus kirim", @@ -165,11 +171,12 @@ "SQLite is used as database. For larger installations we recommend to switch to a different database backend." : "SQLite digunakan sebagai basis data. Untuk instalasi yang lebih besar, kami menyarankan untuk beralih ke backend basis data yang berbeda.", "Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "Terutama saat menggunakan klien desktop untuk sinkronisasi berkas, penggunaan SQLite tidak disarankan.", "To migrate to another database use the command line tool: 'occ db:convert-type', or see the <a target=\"_blank\" href=\"%s\">documentation ↗</a>." : "Untuk migrasi ke basis data lainnya, gunakan alat baris perintah: 'occ db:convert-type', atau lihat <a target=\"_blank\" href=\"%s\">dokumentasi ↗</a>.", - "How to do backups" : "Bagaimana cara mencadangkan", + "How to do backups" : "Bagaimana cara membuat cadangan", "Advanced monitoring" : "Pemantauan tingkat lanjut", "Performance tuning" : "Pemeliharaan performa", "Improving the config.php" : "Memperbaiki config.php", "Theming" : "Tema", + "Hardening and security guidance" : "Panduan Keselamatan dan Keamanan", "Version" : "Versi", "Developer documentation" : "Dokumentasi pengembang", "Experimental applications ahead" : "Aplikasi percobaan terdepan", @@ -259,6 +266,6 @@ "change full name" : "ubah nama lengkap", "set new password" : "setel sandi baru", "change email address" : "ubah alamat email", - "Default" : "Default" + "Default" : "Baku" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/tests/apps.php b/tests/apps.php index 3e27b81df61..f13a996772f 100644 --- a/tests/apps.php +++ b/tests/apps.php @@ -7,6 +7,9 @@ */ function loadDirectory($path) { + if (strpos($path, 'integration')) { + return; + } if ($dh = opendir($path)) { while ($name = readdir($dh)) { if ($name[0] !== '.') { diff --git a/tests/lib/connector/sabre/file.php b/tests/lib/connector/sabre/file.php index ee9c20fd9cb..6602a2df24f 100644 --- a/tests/lib/connector/sabre/file.php +++ b/tests/lib/connector/sabre/file.php @@ -8,8 +8,35 @@ namespace Test\Connector\Sabre; +use Test\HookHelper; +use OC\Files\Filesystem; + class File extends \Test\TestCase { + /** + * @var string + */ + private $user; + + public function setUp() { + parent::setUp(); + + \OC_Hook::clear(); + + $this->user = $this->getUniqueID('user_'); + $userManager = \OC::$server->getUserManager(); + $userManager->createUser($this->user, 'pass'); + + $this->loginAsUser($this->user); + } + + public function tearDown() { + $userManager = \OC::$server->getUserManager(); + $userManager->get($this->user)->delete(); + + parent::tearDown(); + } + private function getStream($string) { $stream = fopen('php://temp', 'r+'); fwrite($stream, $string); @@ -23,7 +50,7 @@ class File extends \Test\TestCase { public function testSimplePutFails() { // setup $storage = $this->getMock('\OC\Files\Storage\Local', ['fopen'], [['datadir' => \OC::$server->getTempManager()->getTemporaryFolder()]]); - $view = $this->getMock('\OC\Files\View', array('file_put_contents', 'getRelativePath', 'resolvePath'), array()); + $view = $this->getMock('\OC\Files\View', array('getRelativePath', 'resolvePath'), array()); $view->expects($this->any()) ->method('resolvePath') ->will($this->returnValue(array($storage, ''))); @@ -45,28 +72,21 @@ class File extends \Test\TestCase { $file->put('test data'); } - public function testPutSingleFileShare() { - // setup - $stream = fopen('php://temp', 'w+'); - $storage = $this->getMock('\OC\Files\Storage\Local', ['fopen'], [['datadir' => \OC::$server->getTempManager()->getTemporaryFolder()]]); - $view = $this->getMock('\OC\Files\View', array('file_put_contents', 'getRelativePath', 'resolvePath'), array()); - $view->expects($this->any()) - ->method('resolvePath') - ->will($this->returnValue(array($storage, ''))); - $view->expects($this->any()) - ->method('getRelativePath') - ->will($this->returnValue('')); - $view->expects($this->any()) - ->method('file_put_contents') - ->with('') - ->will($this->returnValue(true)); - $storage->expects($this->once()) - ->method('fopen') - ->will($this->returnValue($stream)); - - $info = new \OC\Files\FileInfo('/foo.txt', null, null, array( - 'permissions' => \OCP\Constants::PERMISSION_ALL - ), null); + private function doPut($path, $viewRoot = null) { + $view = \OC\Files\Filesystem::getView(); + if (!is_null($viewRoot)) { + $view = new \OC\Files\View($viewRoot); + } else { + $viewRoot = '/' . $this->user . '/files'; + } + + $info = new \OC\Files\FileInfo( + $viewRoot . '/' . ltrim($path, '/'), + null, + null, + ['permissions' => \OCP\Constants::PERMISSION_ALL], + null + ); $file = new \OC\Connector\Sabre\File($view, $info); @@ -74,16 +94,144 @@ class File extends \Test\TestCase { } /** + * Test putting a single file + */ + public function testPutSingleFile() { + $this->doPut('/foo.txt'); + } + + /** + * Test that putting a file triggers create hooks + */ + public function testPutSingleFileTriggersHooks() { + HookHelper::setUpHooks(); + + $this->doPut('/foo.txt'); + + $this->assertCount(4, HookHelper::$hookCalls); + $this->assertHookCall( + HookHelper::$hookCalls[0], + Filesystem::signal_create, + '/foo.txt' + ); + $this->assertHookCall( + HookHelper::$hookCalls[1], + Filesystem::signal_write, + '/foo.txt' + ); + $this->assertHookCall( + HookHelper::$hookCalls[2], + Filesystem::signal_post_create, + '/foo.txt' + ); + $this->assertHookCall( + HookHelper::$hookCalls[3], + Filesystem::signal_post_write, + '/foo.txt' + ); + } + + /** + * Test that putting a file triggers update hooks + */ + public function testPutOverwriteFileTriggersHooks() { + $view = \OC\Files\Filesystem::getView(); + $view->file_put_contents('/foo.txt', 'some content that will be replaced'); + + HookHelper::setUpHooks(); + + $this->doPut('/foo.txt'); + + $this->assertCount(4, HookHelper::$hookCalls); + $this->assertHookCall( + HookHelper::$hookCalls[0], + Filesystem::signal_update, + '/foo.txt' + ); + $this->assertHookCall( + HookHelper::$hookCalls[1], + Filesystem::signal_write, + '/foo.txt' + ); + $this->assertHookCall( + HookHelper::$hookCalls[2], + Filesystem::signal_post_update, + '/foo.txt' + ); + $this->assertHookCall( + HookHelper::$hookCalls[3], + Filesystem::signal_post_write, + '/foo.txt' + ); + } + + /** + * Test that putting a file triggers hooks with the correct path + * if the passed view was chrooted (can happen with public webdav + * where the root is the share root) + */ + public function testPutSingleFileTriggersHooksDifferentRoot() { + $view = \OC\Files\Filesystem::getView(); + $view->mkdir('noderoot'); + + HookHelper::setUpHooks(); + + // happens with public webdav where the view root is the share root + $this->doPut('/foo.txt', '/' . $this->user . '/files/noderoot'); + + $this->assertCount(4, HookHelper::$hookCalls); + $this->assertHookCall( + HookHelper::$hookCalls[0], + Filesystem::signal_create, + '/noderoot/foo.txt' + ); + $this->assertHookCall( + HookHelper::$hookCalls[1], + Filesystem::signal_write, + '/noderoot/foo.txt' + ); + $this->assertHookCall( + HookHelper::$hookCalls[2], + Filesystem::signal_post_create, + '/noderoot/foo.txt' + ); + $this->assertHookCall( + HookHelper::$hookCalls[3], + Filesystem::signal_post_write, + '/noderoot/foo.txt' + ); + } + + public static function cancellingHook($params) { + self::$hookCalls[] = array( + 'signal' => Filesystem::signal_post_create, + 'params' => $params + ); + } + + /** + * Test put file with cancelled hook + * + * @expectedException \Sabre\DAV\Exception + */ + public function testPutSingleFileCancelPreHook() { + \OCP\Util::connectHook( + Filesystem::CLASSNAME, + Filesystem::signal_create, + '\Test\HookHelper', + 'cancellingCallback' + ); + + $this->doPut('/foo.txt'); + } + + /** * @expectedException \Sabre\DAV\Exception */ public function testSimplePutFailsOnRename() { // setup $view = $this->getMock('\OC\Files\View', - array('file_put_contents', 'rename', 'getRelativePath', 'filesize')); - $view->expects($this->any()) - ->method('file_put_contents') - ->withAnyParameters() - ->will($this->returnValue(true)); + array('rename', 'getRelativePath', 'filesize')); $view->expects($this->any()) ->method('rename') ->withAnyParameters() @@ -113,11 +261,7 @@ class File extends \Test\TestCase { */ public function testSimplePutInvalidChars() { // setup - $view = $this->getMock('\OC\Files\View', array('file_put_contents', 'getRelativePath')); - $view->expects($this->any()) - ->method('file_put_contents') - ->will($this->returnValue(false)); - + $view = $this->getMock('\OC\Files\View', array('getRelativePath')); $view->expects($this->any()) ->method('getRelativePath') ->will($this->returnValue('/*')); @@ -157,11 +301,7 @@ class File extends \Test\TestCase { public function testUploadAbort() { // setup $view = $this->getMock('\OC\Files\View', - array('file_put_contents', 'rename', 'getRelativePath', 'filesize')); - $view->expects($this->any()) - ->method('file_put_contents') - ->withAnyParameters() - ->will($this->returnValue(true)); + array('rename', 'getRelativePath', 'filesize')); $view->expects($this->any()) ->method('rename') ->withAnyParameters() @@ -248,4 +388,20 @@ class File extends \Test\TestCase { // action $file->delete(); } + + /** + * Asserts hook call + * + * @param array $callData hook call data to check + * @param string $signal signal name + * @param string $hookPath hook path + */ + protected function assertHookCall($callData, $signal, $hookPath) { + $this->assertEquals($signal, $callData['signal']); + $params = $callData['params']; + $this->assertEquals( + $hookPath, + $params[Filesystem::signal_param_path] + ); + } } diff --git a/tests/lib/helper.php b/tests/lib/helper.php index ed15a677300..b7aa185f4e3 100644 --- a/tests/lib/helper.php +++ b/tests/lib/helper.php @@ -53,21 +53,22 @@ class Test_Helper extends \Test\TestCase { } /** - * @dataProvider computerFileSizeProvider + * @dataProvider providesComputerFileSize */ function testComputerFileSize($expected, $input) { $result = OC_Helper::computerFileSize($input); $this->assertEquals($expected, $result); } - function computerFileSizeProvider(){ - return array( - array(0.0, "0 B"), - array(1024.0, "1 kB"), - array(1395864371.0, '1.3 GB'), - array(9961472.0, "9.5 MB"), - array(500041567437.0, "465.7 GB"), - ); + function providesComputerFileSize(){ + return [ + [0.0, "0 B"], + [1024.0, "1 kB"], + [1395864371.0, '1.3 GB'], + [9961472.0, "9.5 MB"], + [500041567437.0, "465.7 GB"], + [false, "12 GB etfrhzui"] + ]; } function testGetMimeType() { diff --git a/tests/lib/hookhelper.php b/tests/lib/hookhelper.php new file mode 100644 index 00000000000..93411bd068b --- /dev/null +++ b/tests/lib/hookhelper.php @@ -0,0 +1,112 @@ +<?php +/** + * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test; + +use OC\Files\Filesystem; + +/** + * Helper class to register hooks on + */ +class HookHelper { + public static $hookCalls; + + public static function setUpHooks() { + self::clear(); + \OCP\Util::connectHook( + Filesystem::CLASSNAME, + Filesystem::signal_create, + '\Test\HookHelper', + 'createCallback' + ); + \OCP\Util::connectHook( + Filesystem::CLASSNAME, + Filesystem::signal_update, + '\Test\HookHelper', + 'updateCallback' + ); + \OCP\Util::connectHook( + Filesystem::CLASSNAME, + Filesystem::signal_write, + '\Test\HookHelper', + 'writeCallback' + ); + + \OCP\Util::connectHook( + Filesystem::CLASSNAME, + Filesystem::signal_post_create, + '\Test\HookHelper', + 'postCreateCallback' + ); + \OCP\Util::connectHook( + Filesystem::CLASSNAME, + Filesystem::signal_post_update, + '\Test\HookHelper', + 'postUpdateCallback' + ); + \OCP\Util::connectHook( + Filesystem::CLASSNAME, + Filesystem::signal_post_write, + '\Test\HookHelper', + 'postWriteCallback' + ); + } + + public static function clear() { + self::$hookCalls = []; + } + + public static function createCallback($params) { + self::$hookCalls[] = array( + 'signal' => Filesystem::signal_create, + 'params' => $params + ); + } + + public static function updateCallback($params) { + self::$hookCalls[] = array( + 'signal' => Filesystem::signal_update, + 'params' => $params + ); + } + + public static function writeCallback($params) { + self::$hookCalls[] = array( + 'signal' => Filesystem::signal_write, + 'params' => $params + ); + } + + public static function postCreateCallback($params) { + self::$hookCalls[] = array( + 'signal' => Filesystem::signal_post_create, + 'params' => $params + ); + } + + public static function postUpdateCallback($params) { + self::$hookCalls[] = array( + 'signal' => Filesystem::signal_post_update, + 'params' => $params + ); + } + + public static function postWriteCallback($params) { + self::$hookCalls[] = array( + 'signal' => Filesystem::signal_post_write, + 'params' => $params + ); + } + + /** + * Callback that sets the run paramter to false + */ + public static function cancellingCallback($params) { + $params[Filesystem::signal_param_run] = false; + } +} diff --git a/tests/lib/testcase.php b/tests/lib/testcase.php index e66dfb13353..76d5662da9d 100644 --- a/tests/lib/testcase.php +++ b/tests/lib/testcase.php @@ -182,6 +182,8 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase { static protected function logout() { \OC_Util::tearDownFS(); \OC_User::setUserId(''); + // needed for fully logout + \OC::$server->getUserSession()->setUser(null); } /** diff --git a/tests/settings/controller/userscontrollertest.php b/tests/settings/controller/userscontrollertest.php index b9d45d786ec..e70b235f603 100644 --- a/tests/settings/controller/userscontrollertest.php +++ b/tests/settings/controller/userscontrollertest.php @@ -1303,14 +1303,14 @@ class UsersControllerTest extends \Test\TestCase { ->expects($this->once()) ->method('isEnabledForUser') ->with( - $this->equalTo('files_encryption') + $this->equalTo('encryption') ) ->will($this->returnValue(true)); $this->container['Config'] ->expects($this->once()) ->method('getAppValue') ->with( - $this->equalTo('files_encryption'), + $this->equalTo('encryption'), $this->equalTo('recoveryAdminEnabled'), $this->anything() ) @@ -1321,8 +1321,8 @@ class UsersControllerTest extends \Test\TestCase { ->method('getUserValue') ->with( $this->anything(), - $this->equalTo('files_encryption'), - $this->equalTo('recovery_enabled'), + $this->equalTo('encryption'), + $this->equalTo('recoveryEnabled'), $this->anything() ) ->will($this->returnValue('1')); @@ -1339,7 +1339,7 @@ class UsersControllerTest extends \Test\TestCase { $this->container['OCP\\App\\IAppManager'] ->method('isEnabledForUser') ->with( - $this->equalTo('files_encryption') + $this->equalTo('encryption') ) ->will($this->returnValue(true)); @@ -1358,14 +1358,14 @@ class UsersControllerTest extends \Test\TestCase { ->expects($this->once()) ->method('isEnabledForUser') ->with( - $this->equalTo('files_encryption') + $this->equalTo('encryption') ) ->will($this->returnValue(true)); $this->container['Config'] ->expects($this->once()) ->method('getAppValue') ->with( - $this->equalTo('files_encryption'), + $this->equalTo('encryption'), $this->equalTo('recoveryAdminEnabled'), $this->anything() ) @@ -1376,8 +1376,8 @@ class UsersControllerTest extends \Test\TestCase { ->method('getUserValue') ->with( $this->anything(), - $this->equalTo('files_encryption'), - $this->equalTo('recovery_enabled'), + $this->equalTo('encryption'), + $this->equalTo('recoveryEnabled'), $this->anything() ) ->will($this->returnValue('0')); diff --git a/version.php b/version.php index 74e83533bbf..26744e47b85 100644 --- a/version.php +++ b/version.php @@ -23,10 +23,10 @@ // We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades // between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel // when updating major/minor version number. -$OC_Version=array(8, 1, 0, 5); +$OC_Version=array(8, 1, 0, 6); // The human readable string -$OC_VersionString='8.1 beta 1'; +$OC_VersionString='8.1 beta 2'; // The ownCloud channel $OC_Channel='git'; |