diff options
Diffstat (limited to 'apps')
39 files changed, 727 insertions, 270 deletions
diff --git a/apps/files/ajax/delete.php b/apps/files/ajax/delete.php index a28b7b76c95..aed53d5db5a 100644 --- a/apps/files/ajax/delete.php +++ b/apps/files/ajax/delete.php @@ -26,7 +26,8 @@ $success = true; //Now delete foreach ($files as $file) { - if (($dir === '' && $file === 'Shared') || !\OC\Files\Filesystem::unlink($dir . '/' . $file)) { + if (\OC\Files\Filesystem::file_exists($dir . '/' . $file) && + !\OC\Files\Filesystem::unlink($dir . '/' . $file)) { $filesWithError .= $file . "\n"; $success = false; } diff --git a/apps/files/appinfo/filesync.php b/apps/files/appinfo/filesync.php deleted file mode 100644 index 47884a4f15e..00000000000 --- a/apps/files/appinfo/filesync.php +++ /dev/null @@ -1,64 +0,0 @@ -<?php -/** - * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl> - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -/** - * filesync can be called with a PUT method. - * PUT takes a stream starting with a 2 byte blocksize, - * followed by binary md5 of the blocks. Everything in big-endian. - * The return is a json encoded with: - * - 'transferid' - * - 'needed' chunks - * - 'last' checked chunk - * The URL is made of 3 parts, the service url (remote.php/filesync/), the sync - * type and the path in ownCloud. - * At the moment the only supported sync type is 'oc_chunked'. - * The final URL will look like http://.../remote.php/filesync/oc_chunked/path/to/file - */ - -// load needed apps -$RUNTIME_APPTYPES=array('filesystem', 'authentication', 'logging'); -OC_App::loadApps($RUNTIME_APPTYPES); -if(!OC_User::isLoggedIn()) { - if(!isset($_SERVER['PHP_AUTH_USER'])) { - header('WWW-Authenticate: Basic realm="ownCloud Server"'); - header('HTTP/1.0 401 Unauthorized'); - echo 'Valid credentials must be supplied'; - exit(); - } else { - if(!OC_User::login($_SERVER["PHP_AUTH_USER"], $_SERVER["PHP_AUTH_PW"])) { - exit(); - } - } -} - -list($type, $file) = explode('/', substr($path_info, 1+strlen($service)+1), 2); - -if ($type != 'oc_chunked') { - OC_Response::setStatus(OC_Response::STATUS_NOT_FOUND); - die; -} - -if (!\OC\Files\Filesystem::is_file($file)) { - OC_Response::setStatus(OC_Response::STATUS_NOT_FOUND); - die; -} - -switch($_SERVER['REQUEST_METHOD']) { - case 'PUT': - $input = fopen("php://input", "r"); - $org_file = \OC\Files\Filesystem::fopen($file, 'rb'); - $info = array( - 'name' => basename($file), - ); - $sync = new OC_FileChunking($info); - $result = $sync->signature_split($org_file, $input); - echo json_encode($result); - break; - default: - OC_Response::setStatus(OC_Response::STATUS_NOT_FOUND); -} diff --git a/apps/files/appinfo/info.xml b/apps/files/appinfo/info.xml index 390d645e2a4..7f222c0cc7d 100644 --- a/apps/files/appinfo/info.xml +++ b/apps/files/appinfo/info.xml @@ -15,6 +15,5 @@ <remote> <files>appinfo/remote.php</files> <webdav>appinfo/remote.php</webdav> - <filesync>appinfo/filesync.php</filesync> </remote> </info> diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 1bab760a897..d443dd2fd7d 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -1322,6 +1322,10 @@ if (!result || result.status === 'error') { OC.dialogs.alert(result.data.message, t('files', 'Could not rename file')); fileInfo = oldFileInfo; + if (result.data.code === 'sourcenotfound') { + self.remove(result.data.newname, {updateSummary: true}); + return; + } } else { fileInfo = result.data; diff --git a/apps/files/l10n/ja.php b/apps/files/l10n/ja.php index d159acfa5bd..2e5247770a1 100644 --- a/apps/files/l10n/ja.php +++ b/apps/files/l10n/ja.php @@ -76,7 +76,7 @@ $TRANSLATIONS = array( "max. possible: " => "最大容量: ", "Save" => "保存", "WebDAV" => "WebDAV", -"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" => "<a href=\"%s\" target=\"_blank\">WebDAV 経由でファイルにアクセス</a> するにはこのアドレスを利用してください", +"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" => "<a href=\"%s\" target=\"_blank\">WebDAV経由でのファイルアクセス</a>にはこのアドレスを利用してください", "New" => "新規作成", "New text file" => "新規のテキストファイル作成", "Text file" => "テキストファイル", diff --git a/apps/files/lib/app.php b/apps/files/lib/app.php index e32225d0680..c21e44bff4e 100644 --- a/apps/files/lib/app.php +++ b/apps/files/lib/app.php @@ -71,15 +71,25 @@ class App { 'data' => NULL ); + $normalizedOldPath = \OC\Files\Filesystem::normalizePath($dir . '/' . $oldname); + $normalizedNewPath = \OC\Files\Filesystem::normalizePath($dir . '/' . $newname); + // rename to non-existing folder is denied - if (!$this->view->file_exists($dir)) { + if (!$this->view->file_exists($normalizedOldPath)) { + $result['data'] = array( + 'message' => $this->l10n->t('%s could not be renamed as it has been deleted', array($oldname)), + 'code' => 'sourcenotfound', + 'oldname' => $oldname, + 'newname' => $newname, + ); + }else if (!$this->view->file_exists($dir)) { $result['data'] = array('message' => (string)$this->l10n->t( 'The target folder has been moved or deleted.', array($dir)), 'code' => 'targetnotfound' ); // rename to existing file is denied - } else if ($this->view->file_exists($dir . '/' . $newname)) { + } else if ($this->view->file_exists($normalizedNewPath)) { $result['data'] = array( 'message' => $this->l10n->t( @@ -90,10 +100,10 @@ class App { // rename to "." is denied $newname !== '.' and // THEN try to rename - $this->view->rename($dir . '/' . $oldname, $dir . '/' . $newname) + $this->view->rename($normalizedOldPath, $normalizedNewPath) ) { // successful rename - $meta = $this->view->getFileInfo($dir . '/' . $newname); + $meta = $this->view->getFileInfo($normalizedNewPath); $fileinfo = \OCA\Files\Helper::formatFileInfo($meta); $result['success'] = true; $result['data'] = $fileinfo; diff --git a/apps/files/tests/ajax_rename.php b/apps/files/tests/ajax_rename.php index fed366aa8eb..5ed8b1931f4 100644 --- a/apps/files/tests/ajax_rename.php +++ b/apps/files/tests/ajax_rename.php @@ -73,10 +73,14 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase { $oldname = 'oldname'; $newname = 'newname'; - $this->viewMock->expects($this->at(0)) + $this->viewMock->expects($this->any()) ->method('file_exists') - ->with('/') - ->will($this->returnValue(true)); + ->with($this->anything()) + ->will($this->returnValueMap(array( + array('/', true), + array('/oldname', true) + ))); + $this->viewMock->expects($this->any()) ->method('getFileInfo') @@ -119,7 +123,7 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase { $this->viewMock->expects($this->at(0)) ->method('file_exists') - ->with('/unexist') + ->with('/unexist/oldname') ->will($this->returnValue(false)); $this->viewMock->expects($this->any()) @@ -137,6 +141,40 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase { $result = $this->files->rename($dir, $oldname, $newname); $this->assertFalse($result['success']); + $this->assertEquals('sourcenotfound', $result['data']['code']); + } + + /** + * Test move to a folder that doesn't exist any more + */ + function testRenameToNonExistingFolder() { + $dir = '/'; + $oldname = 'oldname'; + $newname = '/unexist/newname'; + + $this->viewMock->expects($this->any()) + ->method('file_exists') + ->with($this->anything()) + ->will($this->returnValueMap(array( + array('/oldname', true), + array('/unexist', false) + ))); + + $this->viewMock->expects($this->any()) + ->method('getFileInfo') + ->will($this->returnValue(array( + 'fileid' => 123, + 'type' => 'dir', + 'mimetype' => 'httpd/unix-directory', + 'size' => 18, + 'etag' => 'abcdef', + 'directory' => '/unexist', + 'name' => 'new_name', + ))); + + $result = $this->files->rename($dir, $oldname, $newname); + + $this->assertFalse($result['success']); $this->assertEquals('targetnotfound', $result['data']['code']); } } diff --git a/apps/files_encryption/ajax/changeRecoveryPassword.php b/apps/files_encryption/ajax/changeRecoveryPassword.php index 0cb010d3b56..99cc7b3cdde 100644 --- a/apps/files_encryption/ajax/changeRecoveryPassword.php +++ b/apps/files_encryption/ajax/changeRecoveryPassword.php @@ -35,11 +35,12 @@ $encryptedRecoveryKey = $view->file_get_contents($keyPath); $decryptedRecoveryKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedRecoveryKey, $oldPassword); if ($decryptedRecoveryKey) { - - $encryptedRecoveryKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($decryptedRecoveryKey, $newPassword); - $view->file_put_contents($keyPath, $encryptedRecoveryKey); - - $return = true; + $cipher = \OCA\Encryption\Helper::getCipher(); + $encryptedKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($decryptedRecoveryKey, $newPassword, $cipher); + if ($encryptedKey) { + \OCA\Encryption\Keymanager::setPrivateSystemKey($encryptedKey, $keyId . '.private.key'); + $return = true; + } } \OC_FileProxy::$enabled = $proxyStatus; diff --git a/apps/files_encryption/ajax/updatePrivateKeyPassword.php b/apps/files_encryption/ajax/updatePrivateKeyPassword.php index f7d20c486cf..a14c9fe5076 100644 --- a/apps/files_encryption/ajax/updatePrivateKeyPassword.php +++ b/apps/files_encryption/ajax/updatePrivateKeyPassword.php @@ -35,13 +35,13 @@ $encryptedKey = $view->file_get_contents($keyPath); $decryptedKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedKey, $oldPassword); if ($decryptedKey) { - - $encryptedKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($decryptedKey, $newPassword); - $view->file_put_contents($keyPath, $encryptedKey); - - $session->setPrivateKey($decryptedKey); - - $return = true; + $cipher = \OCA\Encryption\Helper::getCipher(); + $encryptedKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($decryptedKey, $newPassword, $cipher); + if ($encryptedKey) { + \OCA\Encryption\Keymanager::setPrivateKey($encryptedKey, $user); + $session->setPrivateKey($decryptedKey); + $return = true; + } } \OC_FileProxy::$enabled = $proxyStatus; diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index bd2268aa048..b1e7e8c52a5 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -200,10 +200,14 @@ class Hooks { $privateKey = $session->getPrivateKey();
// Encrypt private key with new user pwd as passphrase
- $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($privateKey, $params['password']);
+ $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($privateKey, $params['password'], Helper::getCipher());
// Save private key
- Keymanager::setPrivateKey($encryptedPrivateKey);
+ if ($encryptedPrivateKey) {
+ Keymanager::setPrivateKey($encryptedPrivateKey, \OCP\User::getUser());
+ } else {
+ \OCP\Util::writeLog('files_encryption', 'Could not update users encryption password', \OCP\Util::ERROR);
+ }
// NOTE: Session does not need to be updated as the
// private key has not changed, only the passphrase
@@ -238,16 +242,17 @@ class Hooks { // Save public key
$view->file_put_contents('/public-keys/' . $user . '.public.key', $keypair['publicKey']);
- // Encrypt private key empty passphrase
- $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $newUserPassword);
-
- // Save private key
- $view->file_put_contents(
- '/' . $user . '/files_encryption/' . $user . '.private.key', $encryptedPrivateKey);
-
- if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files
- $util = new Util($view, $user);
- $util->recoverUsersFiles($recoveryPassword);
+ // Encrypt private key with new password
+ $encryptedKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($keypair['privateKey'], $newUserPassword, Helper::getCipher());
+ if ($encryptedKey) {
+ Keymanager::setPrivateKey($encryptedKey, $user);
+
+ if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files
+ $util = new Util($view, $user);
+ $util->recoverUsersFiles($recoveryPassword);
+ }
+ } else {
+ \OCP\Util::writeLog('files_encryption', 'Could not update users encryption password', \OCP\Util::ERROR);
}
\OC_FileProxy::$enabled = $proxyStatus;
diff --git a/apps/files_encryption/l10n/bg_BG.php b/apps/files_encryption/l10n/bg_BG.php index 665d14af06b..fc6b40de0a8 100644 --- a/apps/files_encryption/l10n/bg_BG.php +++ b/apps/files_encryption/l10n/bg_BG.php @@ -30,6 +30,7 @@ $TRANSLATIONS = array( "New Recovery key password" => "Новата парола за възстановяване на ключа", "Repeat New Recovery key password" => "Повтори новата паролза за възстановяване на ключа", "Change Password" => "Промени Паролата", +"Your private key password no longer matches your log-in password." => "Личният ти ключ не съвпада с паролата за вписване.", "Set your old private key password to your current log-in password:" => "Промени паролата за тайния ти включ на паролата за вписване:", " If you don't remember your old password you can ask your administrator to recover your files." => "Ако не помниш старата парола помоли администратора да възстанови файловете ти.", "Old log-in password" => "Стара парола за вписване", diff --git a/apps/files_encryption/l10n/cs_CZ.php b/apps/files_encryption/l10n/cs_CZ.php index 7ef7d6dfae8..ce380c41ddb 100644 --- a/apps/files_encryption/l10n/cs_CZ.php +++ b/apps/files_encryption/l10n/cs_CZ.php @@ -30,6 +30,7 @@ $TRANSLATIONS = array( "New Recovery key password" => "Nové heslo klíče pro obnovu", "Repeat New Recovery key password" => "Zopakujte nové heslo klíče pro obnovu", "Change Password" => "Změnit heslo", +"Your private key password no longer matches your log-in password." => "Heslo vašeho soukromého klíče se již neshoduje s vaším přihlašovacím heslem.", "Set your old private key password to your current log-in password:" => "Změňte vaše staré heslo soukromého klíče na stejné, jako je vaše současné přihlašovací heslo:", " If you don't remember your old password you can ask your administrator to recover your files." => "Pokud si nepamatujete vaše původní heslo, můžete požádat správce o obnovu vašich souborů.", "Old log-in password" => "Původní přihlašovací heslo", diff --git a/apps/files_encryption/l10n/en_GB.php b/apps/files_encryption/l10n/en_GB.php index b5476566e11..21f69496183 100644 --- a/apps/files_encryption/l10n/en_GB.php +++ b/apps/files_encryption/l10n/en_GB.php @@ -30,6 +30,7 @@ $TRANSLATIONS = array( "New Recovery key password" => "New recovery key password", "Repeat New Recovery key password" => "Repeat new recovery key password", "Change Password" => "Change Password", +"Your private key password no longer matches your log-in password." => "Your private key password no longer matches your log-in password.", "Set your old private key password to your current log-in password:" => "Set your old private key password to your current log-in password:", " If you don't remember your old password you can ask your administrator to recover your files." => " If you don't remember your old password you can ask your administrator to recover your files.", "Old log-in password" => "Old login password", diff --git a/apps/files_encryption/l10n/es.php b/apps/files_encryption/l10n/es.php index 7a98a2d9e7c..3c4f89a09ab 100644 --- a/apps/files_encryption/l10n/es.php +++ b/apps/files_encryption/l10n/es.php @@ -30,6 +30,7 @@ $TRANSLATIONS = array( "New Recovery key password" => "Nueva clave de recuperación", "Repeat New Recovery key password" => "Repetir la nueva clave de recuperación", "Change Password" => "Cambiar contraseña", +"Your private key password no longer matches your log-in password." => "Tu contraseña de clave privada ya no concuerda con tu contraseña de inicio.", "Set your old private key password to your current log-in password:" => "Establezca la contraseña de clave privada antigua para su contraseña de inicio de sesión actual:", " If you don't remember your old password you can ask your administrator to recover your files." => "Si no recuerda su antigua contraseña puede pedir a su administrador que le recupere sus ficheros.", "Old log-in password" => "Contraseña de acceso antigua", diff --git a/apps/files_encryption/l10n/eu.php b/apps/files_encryption/l10n/eu.php index 0d2ab2a74fe..69de4a25b1b 100644 --- a/apps/files_encryption/l10n/eu.php +++ b/apps/files_encryption/l10n/eu.php @@ -30,12 +30,13 @@ $TRANSLATIONS = array( "New Recovery key password" => "Berreskuratze gako pasahitz berria", "Repeat New Recovery key password" => "Errepikatu berreskuratze gako berriaren pasahitza", "Change Password" => "Aldatu Pasahitza", -"Set your old private key password to your current log-in password:" => "Set your old private key password to your current log-in password:", +"Your private key password no longer matches your log-in password." => "Zure gako pasahitza pribatua ez da dagoeneko bat etortzen zure sartzeko pasahitzarekin.", +"Set your old private key password to your current log-in password:" => "Ezarri zure gako pasahitz zaharra orain duzun sartzeko pasahitzan:", " If you don't remember your old password you can ask your administrator to recover your files." => "Ez baduzu zure pasahitz zaharra gogoratzen eskatu zure administratzaileari zure fitxategiak berreskuratzeko.", "Old log-in password" => "Sartzeko pasahitz zaharra", "Current log-in password" => "Sartzeko oraingo pasahitza", -"Update Private Key Password" => "Eguneratu gako pribatu pasahitza", -"Enable password recovery:" => "Gaitu pasahitz berreskuratzea:", +"Update Private Key Password" => "Eguneratu gako pasahitza pribatua", +"Enable password recovery:" => "Gaitu pasahitzaren berreskuratzea:", "Enabling this option will allow you to reobtain access to your encrypted files in case of password loss" => "Aukera hau gaituz zure enkriptatutako fitxategiak berreskuratu ahal izango dituzu pasahitza galtzekotan", "File recovery settings updated" => "Fitxategi berreskuratze ezarpenak eguneratuak", "Could not update file recovery" => "Ezin da fitxategi berreskuratzea eguneratu" diff --git a/apps/files_encryption/l10n/fr.php b/apps/files_encryption/l10n/fr.php index d75c2866d72..c78f6aaabd6 100644 --- a/apps/files_encryption/l10n/fr.php +++ b/apps/files_encryption/l10n/fr.php @@ -30,6 +30,7 @@ $TRANSLATIONS = array( "New Recovery key password" => "Nouveau mot de passe de la clef de récupération", "Repeat New Recovery key password" => "Répétez le nouveau mot de passe de la clé de récupération", "Change Password" => "Changer de mot de passe", +"Your private key password no longer matches your log-in password." => "Le mot de passe de votre clef privée ne correspond plus à votre mot de passe de connexion.", "Set your old private key password to your current log-in password:" => "Configurez le mot de passe de votre ancienne clef privée avec votre mot de passe courant de connexion :", " If you don't remember your old password you can ask your administrator to recover your files." => "Si vous ne vous souvenez plus de votre ancien mot de passe, vous pouvez demander à votre administrateur de récupérer vos fichiers.", "Old log-in password" => "Ancien mot de passe de connexion", diff --git a/apps/files_encryption/l10n/gl.php b/apps/files_encryption/l10n/gl.php index 3e1ba65ffd7..6bf9c57552a 100644 --- a/apps/files_encryption/l10n/gl.php +++ b/apps/files_encryption/l10n/gl.php @@ -30,6 +30,7 @@ $TRANSLATIONS = array( "New Recovery key password" => "Novo contrasinal da chave de recuperación", "Repeat New Recovery key password" => "Repita o novo contrasinal da chave de recuperación", "Change Password" => "Cambiar o contrasinal", +"Your private key password no longer matches your log-in password." => "O seu contrasinal da chave privada non coincide co seu contrasinal de acceso.", "Set your old private key password to your current log-in password:" => "Estabeleza o seu contrasinal antigo da chave de recuperación ao seu contrasinal de acceso actual:", " If you don't remember your old password you can ask your administrator to recover your files." => "Se non lembra o seu antigo contrasinal pode pedírllelo ao seu administrador para recuperar os seus ficheiros.", "Old log-in password" => "Contrasinal antigo de acceso", diff --git a/apps/files_encryption/l10n/ja.php b/apps/files_encryption/l10n/ja.php index 954478de4be..e9950b3ac97 100644 --- a/apps/files_encryption/l10n/ja.php +++ b/apps/files_encryption/l10n/ja.php @@ -30,6 +30,8 @@ $TRANSLATIONS = array( "New Recovery key password" => "新しいリカバリキーのパスワード", "Repeat New Recovery key password" => "新しいリカバリキーのパスワードをもう一度入力", "Change Password" => "パスワードを変更", +"Your private key password no longer matches your log-in password." => "もはや秘密鍵はログインパスワードと一致しません。", +"Set your old private key password to your current log-in password:" => "古い秘密鍵のパスワードを現在のログインパスワードに設定:", " If you don't remember your old password you can ask your administrator to recover your files." => "古いパスワードを覚えていない場合、管理者に尋ねてファイルを回復することができます。", "Old log-in password" => "古いログインパスワード", "Current log-in password" => "現在のログインパスワード", diff --git a/apps/files_encryption/l10n/nl.php b/apps/files_encryption/l10n/nl.php index 8d504cf9c02..4c3f925621b 100644 --- a/apps/files_encryption/l10n/nl.php +++ b/apps/files_encryption/l10n/nl.php @@ -30,6 +30,7 @@ $TRANSLATIONS = array( "New Recovery key password" => "Nieuwe wachtwoord herstelsleutel", "Repeat New Recovery key password" => "Herhaal het nieuwe herstelsleutel wachtwoord", "Change Password" => "Wijzigen wachtwoord", +"Your private key password no longer matches your log-in password." => "Het wachtwoord van uw privésleutel komt niet meer overeen met uw inlogwachtwoord.", "Set your old private key password to your current log-in password:" => "Stel het wachtwoord van uw oude privésleutel in op uw huidige inlogwachtwoord.", " If you don't remember your old password you can ask your administrator to recover your files." => "Als u uw oude wachtwoord niet meer weet, kunt u uw beheerder vragen uw bestanden terug te halen.", "Old log-in password" => "Oude wachtwoord", diff --git a/apps/files_encryption/l10n/pt_BR.php b/apps/files_encryption/l10n/pt_BR.php index f55df165ff6..3b6895c0216 100644 --- a/apps/files_encryption/l10n/pt_BR.php +++ b/apps/files_encryption/l10n/pt_BR.php @@ -30,6 +30,7 @@ $TRANSLATIONS = array( "New Recovery key password" => "Nova senha da chave de recuperação", "Repeat New Recovery key password" => "Repita Nova senha da chave de recuperação", "Change Password" => "Trocar Senha", +"Your private key password no longer matches your log-in password." => "A sua senha de chave privada não corresponde a sua senha de login.", "Set your old private key password to your current log-in password:" => "Defina a sua antiga senha da chave privada para sua senha de login atual:", " If you don't remember your old password you can ask your administrator to recover your files." => "Se você não se lembra de sua antiga senha você pode pedir ao administrador que recupere seus arquivos.", "Old log-in password" => "Senha antiga de login", diff --git a/apps/files_encryption/l10n/sl.php b/apps/files_encryption/l10n/sl.php index bbb1edefa5f..aeaf80ac6ca 100644 --- a/apps/files_encryption/l10n/sl.php +++ b/apps/files_encryption/l10n/sl.php @@ -30,6 +30,8 @@ $TRANSLATIONS = array( "New Recovery key password" => "Novi ključ za obnovitev gesla", "Repeat New Recovery key password" => "Ponovi novi ključ za obnovitev gesla", "Change Password" => "Spremeni geslo", +"Your private key password no longer matches your log-in password." => "Zasebno geslo ni več skladno s prijavnim geslom.", +"Set your old private key password to your current log-in password:" => "Nastavite star zasebni ključ na trenutno prijavno geslo:", " If you don't remember your old password you can ask your administrator to recover your files." => "Če ste pozabili svoje geslo, lahko vaše datoteke obnovi le skrbnik sistema.", "Old log-in password" => "Staro geslo", "Current log-in password" => "Trenutno geslo", diff --git a/apps/files_encryption/l10n/tr.php b/apps/files_encryption/l10n/tr.php index 5d1b737f974..7055859a33d 100644 --- a/apps/files_encryption/l10n/tr.php +++ b/apps/files_encryption/l10n/tr.php @@ -30,6 +30,7 @@ $TRANSLATIONS = array( "New Recovery key password" => "Yeni Kurtarma anahtarı parolası", "Repeat New Recovery key password" => "Yeni Kurtarma anahtarı parolasını yineleyin", "Change Password" => "Parola Değiştir", +"Your private key password no longer matches your log-in password." => "Özel anahtar parolanız artık oturum açma parolanız ile eşleşmiyor.", "Set your old private key password to your current log-in password:" => "Eski özel anahtar parolanızı, geçerli oturum açma parolanız olarak ayarlayın:", " If you don't remember your old password you can ask your administrator to recover your files." => "Eğer eski parolanızı hatırlamıyorsanız, yöneticinizden dosyalarınızı kurtarmasını talep edebilirsiniz.", "Old log-in password" => "Eski oturum açma parolası", diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 18f0224391d..7974598729e 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -36,6 +36,11 @@ class Crypt { const ENCRYPTION_PRIVATE_KEY_NOT_VALID_ERROR = 2;
const ENCRYPTION_NO_SHARE_KEY_FOUND = 3;
+ const BLOCKSIZE = 8192; // block size will always be 8192 for a PHP stream https://bugs.php.net/bug.php?id=21641
+ const DEFAULT_CIPHER = 'AES-256-CFB';
+
+ const HEADERSTART = 'HBEGIN';
+ const HEADEREND = 'HEND';
/**
* return encryption mode client or server side encryption
@@ -181,19 +186,22 @@ class Crypt { * @param string $plainContent
* @param string $iv
* @param string $passphrase
+ * @param string $cypher used for encryption, currently we support AES-128-CFB and AES-256-CFB
* @return string encrypted file content
+ * @throws \OCA\Encryption\Exceptions\EncryptionException
*/
- private static function encrypt($plainContent, $iv, $passphrase = '') {
+ private static function encrypt($plainContent, $iv, $passphrase = '', $cipher = Crypt::DEFAULT_CIPHER) {
- if ($encryptedContent = openssl_encrypt($plainContent, 'AES-128-CFB', $passphrase, false, $iv)) {
- return $encryptedContent;
- } else {
- \OCP\Util::writeLog('Encryption library', 'Encryption (symmetric) of content failed', \OCP\Util::ERROR);
- \OCP\Util::writeLog('Encryption library', openssl_error_string(), \OCP\Util::ERROR);
- return false;
+ $encryptedContent = openssl_encrypt($plainContent, $cipher, $passphrase, false, $iv);
+ if (!$encryptedContent) {
+ $error = "Encryption (symmetric) of content failed: " . openssl_error_string();
+ \OCP\Util::writeLog('Encryption library', $error, \OCP\Util::ERROR);
+ throw new Exceptions\EncryptionException($error, 50);
}
+ return $encryptedContent;
+
}
/**
@@ -201,19 +209,18 @@ class Crypt { * @param string $encryptedContent
* @param string $iv
* @param string $passphrase
+ * @param string $cipher cipher user for decryption, currently we support aes128 and aes256
* @throws \Exception
* @return string decrypted file content
*/
- private static function decrypt($encryptedContent, $iv, $passphrase) {
+ private static function decrypt($encryptedContent, $iv, $passphrase, $cipher = Crypt::DEFAULT_CIPHER) {
- if ($plainContent = openssl_decrypt($encryptedContent, 'AES-128-CFB', $passphrase, false, $iv)) {
+ $plainContent = openssl_decrypt($encryptedContent, $cipher, $passphrase, false, $iv);
+ if ($plainContent) {
return $plainContent;
-
} else {
-
throw new \Exception('Encryption library: Decryption (symmetric) of content failed');
-
}
}
@@ -261,11 +268,12 @@ class Crypt { * Symmetrically encrypts a string and returns keyfile content
* @param string $plainContent content to be encrypted in keyfile
* @param string $passphrase
+ * @param string $cypher used for encryption, currently we support AES-128-CFB and AES-256-CFB
* @return false|string encrypted content combined with IV
* @note IV need not be specified, as it will be stored in the returned keyfile
* and remain accessible therein.
*/
- public static function symmetricEncryptFileContent($plainContent, $passphrase = '') {
+ public static function symmetricEncryptFileContent($plainContent, $passphrase = '', $cipher = Crypt::DEFAULT_CIPHER) {
if (!$plainContent) {
\OCP\Util::writeLog('Encryption library', 'symmetrically encryption failed, no content given.', \OCP\Util::ERROR);
@@ -274,15 +282,16 @@ class Crypt { $iv = self::generateIv();
- if ($encryptedContent = self::encrypt($plainContent, $iv, $passphrase)) {
+ try {
+ $encryptedContent = self::encrypt($plainContent, $iv, $passphrase, $cipher);
// Combine content to encrypt with IV identifier and actual IV
$catfile = self::concatIv($encryptedContent, $iv);
$padded = self::addPadding($catfile);
return $padded;
-
- } else {
- \OCP\Util::writeLog('Encryption library', 'Encryption (symmetric) of keyfile content failed', \OCP\Util::ERROR);
+ } catch (OCA\Encryption\Exceptions\EncryptionException $e) {
+ $message = 'Could not encrypt file content (code: ' . $e->getCode . '): ';
+ \OCP\Util::writeLog('files_encryption', $message . $e->getMessage, \OCP\Util::ERROR);
return false;
}
@@ -293,6 +302,7 @@ class Crypt { * Symmetrically decrypts keyfile content
* @param string $keyfileContent
* @param string $passphrase
+ * @param string $cipher cipher used for decryption, currently aes128 and aes256 is supported.
* @throws \Exception
* @return string|false
* @internal param string $source
@@ -302,7 +312,7 @@ class Crypt { *
* This function decrypts a file
*/
- public static function symmetricDecryptFileContent($keyfileContent, $passphrase = '') {
+ public static function symmetricDecryptFileContent($keyfileContent, $passphrase = '', $cipher = Crypt::DEFAULT_CIPHER) {
if (!$keyfileContent) {
@@ -316,7 +326,7 @@ class Crypt { // Split into enc data and catfile
$catfile = self::splitIv($noPadding);
- if ($plainContent = self::decrypt($catfile['encrypted'], $catfile['iv'], $passphrase)) {
+ if ($plainContent = self::decrypt($catfile['encrypted'], $catfile['iv'], $passphrase, $cipher)) {
return $plainContent;
@@ -328,6 +338,7 @@ class Crypt { /**
* Decrypt private key and check if the result is a valid keyfile
+ *
* @param string $encryptedKey encrypted keyfile
* @param string $passphrase to decrypt keyfile
* @return string|false encrypted private key or false
@@ -336,7 +347,15 @@ class Crypt { */
public static function decryptPrivateKey($encryptedKey, $passphrase) {
- $plainKey = self::symmetricDecryptFileContent($encryptedKey, $passphrase);
+ $header = self::parseHeader($encryptedKey);
+ $cipher = self::getCipher($header);
+
+ // if we found a header we need to remove it from the key we want to decrypt
+ if (!empty($header)) {
+ $encryptedKey = substr($encryptedKey, strpos($encryptedKey, self::HEADEREND) + strlen(self::HEADEREND));
+ }
+
+ $plainKey = self::symmetricDecryptFileContent($encryptedKey, $passphrase, $cipher);
// check if this a valid private key
$res = openssl_pkey_get_private($plainKey);
@@ -481,4 +500,76 @@ class Crypt { }
+ /**
+ * read header into array
+ *
+ * @param string $data
+ * @return array
+ */
+ public static function parseHeader($data) {
+
+ $result = array();
+
+ if (substr($data, 0, strlen(self::HEADERSTART)) === self::HEADERSTART) {
+ $endAt = strpos($data, self::HEADEREND);
+ $header = substr($data, 0, $endAt + strlen(self::HEADEREND));
+
+ // +1 to not start with an ':' which would result in empty element at the beginning
+ $exploded = explode(':', substr($header, strlen(self::HEADERSTART)+1));
+
+ $element = array_shift($exploded);
+ while ($element !== self::HEADEREND) {
+
+ $result[$element] = array_shift($exploded);
+
+ $element = array_shift($exploded);
+
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * check if data block is the header
+ *
+ * @param string $data
+ * @return boolean
+ */
+ public static function isHeader($data) {
+
+ if (substr($data, 0, strlen(self::HEADERSTART)) === self::HEADERSTART) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * get chiper from header
+ *
+ * @param array $header
+ * @throws \OCA\Encryption\Exceptions\EncryptionException
+ */
+ public static function getCipher($header) {
+ $cipher = isset($header['cipher']) ? $header['cipher'] : 'AES-128-CFB';
+
+ if ($cipher !== 'AES-256-CFB' && $cipher !== 'AES-128-CFB') {
+
+ throw new \OCA\Encryption\Exceptions\EncryptionException('file header broken, no supported cipher defined', 40);
+ }
+
+ return $cipher;
+ }
+
+ /**
+ * generate header for encrypted file
+ */
+ public static function generateHeader() {
+ $cipher = Helper::getCipher();
+ $header = self::HEADERSTART . ':cipher:' . $cipher . ':' . self::HEADEREND;
+
+ return $header;
+ }
+
}
diff --git a/apps/files_encryption/lib/exceptions.php b/apps/files_encryption/lib/exceptions.php index a409b0f0fb2..3ea27faf406 100644 --- a/apps/files_encryption/lib/exceptions.php +++ b/apps/files_encryption/lib/exceptions.php @@ -22,6 +22,15 @@ namespace OCA\Encryption\Exceptions; +/** + * General encryption exception + * Possible Error Codes: + * 10 - unexpected end of encryption header + * 20 - unexpected blog size + * 30 - encryption header to large + * 40 - unknown cipher + * 50 - encryption failed + */ class EncryptionException extends \Exception { } diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php index 214e212b675..d427c51732f 100755 --- a/apps/files_encryption/lib/helper.php +++ b/apps/files_encryption/lib/helper.php @@ -144,19 +144,17 @@ class Helper { $view->file_put_contents('/public-keys/' . $recoveryKeyId . '.public.key', $keypair['publicKey']); - // Encrypt private key empty passphrase - $encryptedPrivateKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($keypair['privateKey'], $recoveryPassword); - - // Save private key - $view->file_put_contents('/owncloud_private_key/' . $recoveryKeyId . '.private.key', $encryptedPrivateKey); + $cipher = \OCA\Encryption\Helper::getCipher(); + $encryptedKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($keypair['privateKey'], $recoveryPassword, $cipher); + if ($encryptedKey) { + Keymanager::setPrivateSystemKey($encryptedKey, $recoveryKeyId . '.private.key'); + // Set recoveryAdmin as enabled + $appConfig->setValue('files_encryption', 'recoveryAdminEnabled', 1); + $return = true; + } \OC_FileProxy::$enabled = true; - // Set recoveryAdmin as enabled - $appConfig->setValue('files_encryption', 'recoveryAdminEnabled', 1); - - $return = true; - } else { // get recovery key and check the password $util = new \OCA\Encryption\Util(new \OC\Files\View('/'), \OCP\User::getUser()); $return = $util->checkRecoveryPassword($recoveryPassword); @@ -230,7 +228,6 @@ class Helper { return $return; } - /** * checks if access is public/anonymous user * @return bool @@ -478,5 +475,25 @@ class Helper { return false; } + + /** + * read the cipher used for encryption from the config.php + * + * @return string + */ + public static function getCipher() { + + $cipher = \OCP\Config::getSystemValue('cipher', Crypt::DEFAULT_CIPHER); + + if ($cipher !== 'AES-256-CFB' && $cipher !== 'AES-128-CFB') { + \OCP\Util::writeLog('files_encryption', + 'wrong cipher defined in config.php, only AES-128-CFB and AES-256-CFB is supported. Fall back ' . Crypt::DEFAULT_CIPHER, + \OCP\Util::WARN); + + $cipher = Crypt::DEFAULT_CIPHER; + } + + return $cipher; + } } diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index da84e975a05..931469f4b74 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -258,9 +258,13 @@ class Keymanager { * @note Encryption of the private key must be performed by client code * as no encryption takes place here */ - public static function setPrivateKey($key) { + public static function setPrivateKey($key, $user = '') { - $user = \OCP\User::getUser(); + if ($user === '') { + $user = \OCP\User::getUser(); + } + + $header = Crypt::generateHeader(); $view = new \OC\Files\View('/' . $user . '/files_encryption'); @@ -271,7 +275,7 @@ class Keymanager { $view->mkdir(''); } - $result = $view->file_put_contents($user . '.private.key', $key); + $result = $view->file_put_contents($user . '.private.key', $header . $key); \OC_FileProxy::$enabled = $proxyStatus; @@ -280,6 +284,33 @@ class Keymanager { } /** + * write private system key (recovery and public share key) to disk + * + * @param string $key encrypted key + * @param string $keyName name of the key file + * @return boolean + */ + public static function setPrivateSystemKey($key, $keyName) { + + $header = Crypt::generateHeader(); + + $view = new \OC\Files\View('/owncloud_private_key'); + + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + if (!$view->file_exists('')) { + $view->mkdir(''); + } + + $result = $view->file_put_contents($keyName, $header . $key); + + \OC_FileProxy::$enabled = $proxyStatus; + + return $result; + } + + /** * store share key * * @param \OC\Files\View $view diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php index 84599181ba2..ff8fbd24ecb 100644 --- a/apps/files_encryption/lib/session.php +++ b/apps/files_encryption/lib/session.php @@ -80,11 +80,13 @@ class Session { $this->view->file_put_contents('/public-keys/' . $publicShareKeyId . '.public.key', $keypair['publicKey']); // Encrypt private key empty passphrase - $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], ''); - - // Save private key - $this->view->file_put_contents( - '/owncloud_private_key/' . $publicShareKeyId . '.private.key', $encryptedPrivateKey); + $cipher = \OCA\Encryption\Helper::getCipher(); + $encryptedKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($keypair['privateKey'], '', $cipher); + if ($encryptedKey) { + Keymanager::setPrivateSystemKey($encryptedKey, $publicShareKeyId . '.private.key'); + } else { + \OCP\Util::writeLog('files_encryption', 'Could not create public share keys', \OCP\Util::ERROR); + } \OC_FileProxy::$enabled = $proxyStatus; diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index 341114214d5..f74812a7253 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -2,9 +2,10 @@ /** * ownCloud * - * @author Robin Appelman - * @copyright 2012 Sam Tuke <samtuke@owncloud.com>, 2011 Robin Appelman - * <icewind1991@gmail.com> + * @author Bjoern Schiessle, Robin Appelman + * @copyright 2014 Bjoern Schiessle <schiessle@owncloud.com> + * 2012 Sam Tuke <samtuke@owncloud.com>, + * 2011 Robin Appelman <icewind1991@gmail.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -49,9 +50,11 @@ namespace OCA\Encryption; * encryption proxies are used and keyfiles deleted. */ class Stream { + + const PADDING_CHAR = '-'; + private $plainKey; private $encKeyfiles; - private $rawPath; // The raw path relative to the data dir private $relPath; // rel path to users file dir private $userId; @@ -66,6 +69,9 @@ class Stream { private $newFile; // helper var, we only need to write the keyfile for new files private $isLocalTmpFile = false; // do we operate on a local tmp file private $localTmpFile; // path of local tmp file + private $headerWritten = false; + private $containHeader = false; // the file contain a header + private $cipher; // cipher used for encryption/decryption /** * @var \OC\Files\View @@ -87,6 +93,9 @@ class Stream { */ public function stream_open($path, $mode, $options, &$opened_path) { + // read default cipher from config + $this->cipher = Helper::getCipher(); + // assume that the file already exist before we decide it finally in getKey() $this->newFile = false; @@ -150,6 +159,9 @@ class Stream { } $this->size = $this->rootView->filesize($this->rawPath); + + $this->readHeader(); + } if ($this->isLocalTmpFile) { @@ -178,6 +190,29 @@ class Stream { } + private function readHeader() { + + if ($this->isLocalTmpFile) { + $handle = fopen($this->localTmpFile, 'r'); + } else { + $handle = $this->rootView->fopen($this->rawPath, 'r'); + } + + if (is_resource($handle)) { + $data = fread($handle, Crypt::BLOCKSIZE); + + $header = Crypt::parseHeader($data); + $this->cipher = Crypt::getCipher($header); + + // remeber that we found a header + if (!empty($header)) { + $this->containHeader = true; + } + + fclose($handle); + } + } + /** * Returns the current position of the file pointer * @return int position of the file pointer @@ -195,6 +230,11 @@ class Stream { $this->flush(); + // ignore the header and just overstep it + if ($this->containHeader) { + $offset += Crypt::BLOCKSIZE; + } + // this wrapper needs to return "true" for success. // the fseek call itself returns 0 on succeess return !fseek($this->handle, $offset, $whence); @@ -204,25 +244,25 @@ class Stream { /** * @param int $count * @return bool|string - * @throws \Exception + * @throws \OCA\Encryption\Exceptions\EncryptionException */ public function stream_read($count) { $this->writeCache = ''; - if ($count !== 8192) { - - // $count will always be 8192 https://bugs.php.net/bug.php?id=21641 - // This makes this function a lot simpler, but will break this class if the above 'bug' gets 'fixed' + if ($count !== Crypt::BLOCKSIZE) { \OCP\Util::writeLog('Encryption library', 'PHP "bug" 21641 no longer holds, decryption system requires refactoring', \OCP\Util::FATAL); - - die(); - + throw new \OCA\Encryption\Exceptions\EncryptionException('expected a blog size of 8192 byte', 20); } // Get the data from the file handle $data = fread($this->handle, $count); + // if this block contained the header we move on to the next block + if (Crypt::isHeader($data)) { + $data = fread($this->handle, $count); + } + $result = null; if (strlen($data)) { @@ -236,7 +276,7 @@ class Stream { } else { // Decrypt data - $result = Crypt::symmetricDecryptFileContent($data, $this->plainKey); + $result = Crypt::symmetricDecryptFileContent($data, $this->plainKey, $this->cipher); } } @@ -254,7 +294,7 @@ class Stream { public function preWriteEncrypt($plainData, $key) { // Encrypt data to 'catfile', which includes IV - if ($encrypted = Crypt::symmetricEncryptFileContent($plainData, $key)) { + if ($encrypted = Crypt::symmetricEncryptFileContent($plainData, $key, $this->cipher)) { return $encrypted; @@ -318,6 +358,25 @@ class Stream { } /** + * write header at beginning of encrypted file + * + * @throws Exceptions\EncryptionException + */ + private function writeHeader() { + + $header = Crypt::generateHeader(); + + if (strlen($header) > Crypt::BLOCKSIZE) { + throw new Exceptions\EncryptionException('max header size exceeded', 30); + } + + $paddedHeader = str_pad($header, Crypt::BLOCKSIZE, self::PADDING_CHAR, STR_PAD_RIGHT); + + fwrite($this->handle, $paddedHeader); + $this->headerWritten = true; + } + + /** * Handle plain data from the stream, and write it in 8192 byte blocks * @param string $data data to be written to disk * @note the data will be written to the path stored in the stream handle, set in stream_open() @@ -334,6 +393,10 @@ class Stream { return strlen($data); } + if ($this->headerWritten === false) { + $this->writeHeader(); + } + // Disable the file proxies so that encryption is not // automatically attempted when the file is written to disk - // we are handling that separately here and we don't want to diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php index e44a8bd3dda..087dada7f1b 100644 --- a/apps/files_encryption/lib/util.php +++ b/apps/files_encryption/lib/util.php @@ -167,11 +167,12 @@ class Util { \OC_FileProxy::$enabled = false; // Encrypt private key with user pwd as passphrase - $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $passphrase); + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $passphrase, Helper::getCipher()); // Save key-pair if ($encryptedPrivateKey) { - $this->view->file_put_contents($this->privateKeyPath, $encryptedPrivateKey); + $header = crypt::generateHeader(); + $this->view->file_put_contents($this->privateKeyPath, $header . $encryptedPrivateKey); $this->view->file_put_contents($this->publicKeyPath, $keypair['publicKey']); } @@ -384,8 +385,14 @@ class Util { && $this->isEncryptedPath($path) ) { - // get the size from filesystem - $size = $this->view->filesize($path); + $offset = 0; + if ($this->containHeader($path)) { + $offset = Crypt::BLOCKSIZE; + } + + // get the size from filesystem if the file contains a encryption header we + // we substract it + $size = $this->view->filesize($path) - $offset; // fast path, else the calculation for $lastChunkNr is bogus if ($size === 0) { @@ -396,15 +403,15 @@ class Util { // calculate last chunk nr // next highest is end of chunks, one subtracted is last one // we have to read the last chunk, we can't just calculate it (because of padding etc) - $lastChunkNr = ceil($size/ 8192) - 1; - $lastChunkSize = $size - ($lastChunkNr * 8192); + $lastChunkNr = ceil($size/ Crypt::BLOCKSIZE) - 1; + $lastChunkSize = $size - ($lastChunkNr * Crypt::BLOCKSIZE); // open stream $stream = fopen('crypt://' . $path, "r"); if (is_resource($stream)) { // calculate last chunk position - $lastChunckPos = ($lastChunkNr * 8192); + $lastChunckPos = ($lastChunkNr * Crypt::BLOCKSIZE); // seek to end if (@fseek($stream, $lastChunckPos) === -1) { @@ -439,6 +446,30 @@ class Util { } /** + * check if encrypted file contain a encryption header + * + * @param string $path + * @return boolean + */ + private function containHeader($path) { + // Disable encryption proxy to read the raw data + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + $isHeader = false; + $handle = $this->view->fopen($path, 'r'); + + if (is_resource($handle)) { + $firstBlock = fread($handle, Crypt::BLOCKSIZE); + $isHeader = Crypt::isHeader($firstBlock); + } + + \OC_FileProxy::$enabled = $proxyStatus; + + return $isHeader; + } + + /** * fix the file size of the encrypted file * @param string $path absolute path * @return boolean true / false if file is encrypted @@ -993,10 +1024,10 @@ class Util { // check if it is a group mount if (\OCP\App::isEnabled("files_external")) { - $mount = \OC_Mount_Config::getSystemMountPoints(); - foreach ($mount as $mountPoint => $data) { - if ($mountPoint == substr($ownerPath, 1, strlen($mountPoint))) { - $userIds = array_merge($userIds, $this->getUserWithAccessToMountPoint($data['applicable']['users'], $data['applicable']['groups'])); + $mounts = \OC_Mount_Config::getSystemMountPoints(); + foreach ($mounts as $mount) { + if ($mount['mountpoint'] == substr($ownerPath, 1, strlen($mount['mountpoint']))) { + $userIds = array_merge($userIds, $this->getUserWithAccessToMountPoint($mount['applicable']['users'], $mount['applicable']['groups'])); } } } @@ -1454,10 +1485,12 @@ class Util { public function isSystemWideMountPoint($path) { $normalizedPath = ltrim($path, '/'); if (\OCP\App::isEnabled("files_external")) { - $mount = \OC_Mount_Config::getSystemMountPoints(); - foreach ($mount as $mountPoint => $data) { - if ($mountPoint == substr($normalizedPath, 0, strlen($mountPoint))) { - return true; + $mounts = \OC_Mount_Config::getSystemMountPoints(); + foreach ($mounts as $mount) { + if ($mount['mountpoint'] == substr($normalizedPath, 0, strlen($mount['mountpoint']))) { + if ($this->isMountPointApplicableToUser($mount)) { + return true; + } } } } @@ -1465,6 +1498,29 @@ class Util { } /** + * check if mount point is applicable to user + * + * @param array $mount contains $mount['applicable']['users'], $mount['applicable']['groups'] + * @return boolean + */ + protected function isMountPointApplicableToUser($mount) { + $uid = \OCP\User::getUser(); + $acceptedUids = array('all', $uid); + // check if mount point is applicable for the user + $intersection = array_intersect($acceptedUids, $mount['applicable']['users']); + if (!empty($intersection)) { + return true; + } + // check if mount point is applicable for group where the user is a member + foreach ($mount['applicable']['groups'] as $gid) { + if (\OC_Group::inGroup($uid, $gid)) { + return true; + } + } + return false; + } + + /** * decrypt private key and add it to the current session * @param array $params with 'uid' and 'password' * @return mixed session or false diff --git a/apps/files_encryption/tests/crypt.php b/apps/files_encryption/tests/crypt.php index a1a51c749b0..5eb9580e3b4 100755 --- a/apps/files_encryption/tests/crypt.php +++ b/apps/files_encryption/tests/crypt.php @@ -96,6 +96,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { } $this->assertTrue(\OC_FileProxy::$enabled); + \OCP\Config::deleteSystemValue('cipher'); } public static function tearDownAfterClass() { @@ -121,7 +122,9 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { // test successful decrypt $crypted = Encryption\Crypt::symmetricEncryptFileContent($this->genPrivateKey, 'hat'); - $decrypted = Encryption\Crypt::decryptPrivateKey($crypted, 'hat'); + $header = Encryption\Crypt::generateHeader(); + + $decrypted = Encryption\Crypt::decryptPrivateKey($header . $crypted, 'hat'); $this->assertEquals($this->genPrivateKey, $decrypted); @@ -154,12 +157,28 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { /** * @medium */ + function testSymmetricEncryptFileContentAes128() { + + # TODO: search in keyfile for actual content as IV will ensure this test always passes + + $crypted = Encryption\Crypt::symmetricEncryptFileContent($this->dataShort, 'hat', 'AES-128-CFB'); + + $this->assertNotEquals($this->dataShort, $crypted); + + + $decrypt = Encryption\Crypt::symmetricDecryptFileContent($crypted, 'hat', 'AES-128-CFB'); + + $this->assertEquals($this->dataShort, $decrypt); + + } + + /** + * @medium + */ function testSymmetricStreamEncryptShortFileContent() { $filename = 'tmp-' . uniqid() . '.test'; - $util = new Encryption\Util(new \OC\Files\View(), $this->userId); - $cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/'. $filename, $this->dataShort); // Test that data was successfully written @@ -178,26 +197,52 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { // Check that the file was encrypted before being written to disk $this->assertNotEquals($this->dataShort, $retreivedCryptedFile); - // Get the encrypted keyfile - $encKeyfile = Encryption\Keymanager::getFileKey($this->view, $util, $filename); + // Get file contents with the encryption wrapper + $decrypted = file_get_contents('crypt:///' . $this->userId . '/files/'. $filename); + + // Check that decrypted data matches + $this->assertEquals($this->dataShort, $decrypted); + + // Teardown + $this->view->unlink($this->userId . '/files/' . $filename); + + Encryption\Keymanager::deleteFileKey($this->view, $filename); + } + + /** + * @medium + */ + function testSymmetricStreamEncryptShortFileContentAes128() { + + $filename = 'tmp-' . uniqid() . '.test'; + + \OCP\Config::setSystemValue('cipher', 'AES-128-CFB'); + + $cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/'. $filename, $this->dataShort); - // Attempt to fetch the user's shareKey - $shareKey = Encryption\Keymanager::getShareKey($this->view, $this->userId, $util, $filename); + // Test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); - // get session - $session = new \OCA\Encryption\Session($this->view); + \OCP\Config::deleteSystemValue('cipher'); - // get private key - $privateKey = $session->getPrivateKey($this->userId); + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + + // Get file contents without using any wrapper to get it's actual contents on disk + $retreivedCryptedFile = $this->view->file_get_contents($this->userId . '/files/' . $filename); + + // Re-enable proxy - our work is done + \OC_FileProxy::$enabled = $proxyStatus; - // Decrypt keyfile with shareKey - $plainKeyfile = Encryption\Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + // Check that the file was encrypted before being written to disk + $this->assertNotEquals($this->dataShort, $retreivedCryptedFile); - // Manually decrypt - $manualDecrypt = Encryption\Crypt::symmetricDecryptFileContent($retreivedCryptedFile, $plainKeyfile); + // Get file contents with the encryption wrapper + $decrypted = file_get_contents('crypt:///' . $this->userId . '/files/'. $filename); // Check that decrypted data matches - $this->assertEquals($this->dataShort, $manualDecrypt); + $this->assertEquals($this->dataShort, $decrypted); // Teardown $this->view->unlink($this->userId . '/files/' . $filename); @@ -217,8 +262,6 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { // Generate a a random filename $filename = 'tmp-' . uniqid() . '.test'; - $util = new Encryption\Util(new \OC\Files\View(), $this->userId); - // Save long data as encrypted file using stream wrapper $cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong . $this->dataLong); @@ -239,50 +282,57 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { // Check that the file was encrypted before being written to disk $this->assertNotEquals($this->dataLong . $this->dataLong, $retreivedCryptedFile); - // Manuallly split saved file into separate IVs and encrypted chunks - $r = preg_split('/(00iv00.{16,18})/', $retreivedCryptedFile, NULL, PREG_SPLIT_DELIM_CAPTURE); + $decrypted = file_get_contents('crypt:///' . $this->userId . '/files/'. $filename); - //print_r($r); + $this->assertEquals($this->dataLong . $this->dataLong, $decrypted); - // Join IVs and their respective data chunks - $e = array(); - $i = 0; - while ($i < count($r)-1) { - $e[] = $r[$i] . $r[$i+1]; - $i = $i + 2; - } + // Teardown - //print_r($e); + $this->view->unlink($this->userId . '/files/' . $filename); - // Get the encrypted keyfile - $encKeyfile = Encryption\Keymanager::getFileKey($this->view, $util, $filename); + Encryption\Keymanager::deleteFileKey($this->view, $filename); - // Attempt to fetch the user's shareKey - $shareKey = Encryption\Keymanager::getShareKey($this->view, $this->userId, $util, $filename); + } - // get session - $session = new \OCA\Encryption\Session($this->view); + /** + * @medium + * Test that data that is written by the crypto stream wrapper with AES 128 + * @note Encrypted data is manually prepared and decrypted here to avoid dependency on success of stream_read + * @note If this test fails with truncate content, check that enough array slices are being rejoined to form $e, as the crypt.php file may have gotten longer and broken the manual + * reassembly of its data + */ + function testSymmetricStreamEncryptLongFileContentAes128() { - // get private key - $privateKey = $session->getPrivateKey($this->userId); + // Generate a a random filename + $filename = 'tmp-' . uniqid() . '.test'; - // Decrypt keyfile with shareKey - $plainKeyfile = Encryption\Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey); + \OCP\Config::setSystemValue('cipher', 'AES-128-CFB'); - // Set var for reassembling decrypted content - $decrypt = ''; + // Save long data as encrypted file using stream wrapper + $cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong . $this->dataLong); - // Manually decrypt chunk - foreach ($e as $chunk) { + // Test that data was successfully written + $this->assertTrue(is_int($cryptedFile)); - $chunkDecrypt = Encryption\Crypt::symmetricDecryptFileContent($chunk, $plainKeyfile); + // Disable encryption proxy to prevent recursive calls + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; - // Assemble decrypted chunks - $decrypt .= $chunkDecrypt; + \OCP\Config::deleteSystemValue('cipher'); + + // Get file contents without using any wrapper to get it's actual contents on disk + $retreivedCryptedFile = $this->view->file_get_contents($this->userId . '/files/' . $filename); + + // Re-enable proxy - our work is done + \OC_FileProxy::$enabled = $proxyStatus; - } - $this->assertEquals($this->dataLong . $this->dataLong, $decrypt); + // Check that the file was encrypted before being written to disk + $this->assertNotEquals($this->dataLong . $this->dataLong, $retreivedCryptedFile); + + $decrypted = file_get_contents('crypt:///' . $this->userId . '/files/'. $filename); + + $this->assertEquals($this->dataLong . $this->dataLong, $decrypted); // Teardown @@ -294,14 +344,22 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { /** * @medium - * Test that data that is read by the crypto stream wrapper + * Test that data that is written by the crypto stream wrapper with AES 128 + * @note Encrypted data is manually prepared and decrypted here to avoid dependency on success of stream_read + * @note If this test fails with truncate content, check that enough array slices are being rejoined to form $e, as the crypt.php file may have gotten longer and broken the manual + * reassembly of its data */ - function testSymmetricStreamDecryptShortFileContent() { + function testStreamDecryptLongFileContentWithoutHeader() { - $filename = 'tmp-' . uniqid(); + // Generate a a random filename + $filename = 'tmp-' . uniqid() . '.test'; + + \OCP\Config::setSystemValue('cipher', 'AES-128-CFB'); // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents('crypt:///'. $this->userId . '/files/' . $filename, $this->dataShort); + $cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong . $this->dataLong); + + \OCP\Config::deleteSystemValue('cipher'); // Test that data was successfully written $this->assertTrue(is_int($cryptedFile)); @@ -310,39 +368,30 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - $this->assertTrue(Encryption\Crypt::isEncryptedMeta($filename)); - - \OC_FileProxy::$enabled = $proxyStatus; + // Get file contents without using any wrapper to get it's actual contents on disk + $retreivedCryptedFile = $this->view->file_get_contents($this->userId . '/files/' . $filename); - // Get file decrypted contents - $decrypt = file_get_contents('crypt:///' . $this->userId . '/files/' . $filename); + // Check that the file was encrypted before being written to disk + $this->assertNotEquals($this->dataLong . $this->dataLong, $retreivedCryptedFile); - $this->assertEquals($this->dataShort, $decrypt); + // remove the header to check if we can also decrypt old files without a header, + // this files should fall back to AES-128 + $cryptedWithoutHeader = substr($retreivedCryptedFile, Encryption\Crypt::BLOCKSIZE); + $this->view->file_put_contents($this->userId . '/files/' . $filename, $cryptedWithoutHeader); - // tear down - $this->view->unlink($this->userId . '/files/' . $filename); - } - - /** - * @medium - */ - function testSymmetricStreamDecryptLongFileContent() { + // Re-enable proxy - our work is done + \OC_FileProxy::$enabled = $proxyStatus; - $filename = 'tmp-' . uniqid(); + $decrypted = file_get_contents('crypt:///' . $this->userId . '/files/'. $filename); - // Save long data as encrypted file using stream wrapper - $cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong); + $this->assertEquals($this->dataLong . $this->dataLong, $decrypted); - // Test that data was successfully written - $this->assertTrue(is_int($cryptedFile)); + // Teardown - // Get file decrypted contents - $decrypt = file_get_contents('crypt:///' . $this->userId . '/files/' . $filename); + $this->view->unlink($this->userId . '/files/' . $filename); - $this->assertEquals($this->dataLong, $decrypt); + Encryption\Keymanager::deleteFileKey($this->view, $filename); - // tear down - $this->view->unlink($this->userId . '/files/' . $filename); } /** @@ -354,7 +403,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase { $this->assertFalse(Encryption\Crypt::isCatfileContent($this->legacyEncryptedData)); - $keyfileContent = Encryption\Crypt::symmetricEncryptFileContent($this->dataUrl, 'hat'); + $keyfileContent = Encryption\Crypt::symmetricEncryptFileContent($this->dataUrl, 'hat', 'AES-128-CFB'); $this->assertTrue(Encryption\Crypt::isCatfileContent($keyfileContent)); diff --git a/apps/files_encryption/tests/keymanager.php b/apps/files_encryption/tests/keymanager.php index e779f8341e6..f90832280a2 100644 --- a/apps/files_encryption/tests/keymanager.php +++ b/apps/files_encryption/tests/keymanager.php @@ -107,7 +107,7 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { $key = Encryption\Keymanager::getPrivateKey($this->view, $this->userId); - $privateKey = Encryption\Crypt::symmetricDecryptFileContent($key, $this->pass); + $privateKey = Encryption\Crypt::decryptPrivateKey($key, $this->pass); $res = openssl_pkey_get_private($privateKey); @@ -177,6 +177,38 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { /** * @medium */ + function testSetPrivateKey() { + + $key = "dummy key"; + + Encryption\Keymanager::setPrivateKey($key, 'dummyUser'); + + $this->assertTrue($this->view->file_exists('/dummyUser/files_encryption/dummyUser.private.key')); + + //clean up + $this->view->deleteAll('/dummyUser'); + } + + /** + * @medium + */ + function testSetPrivateSystemKey() { + + $key = "dummy key"; + $keyName = "myDummyKey.private.key"; + + Encryption\Keymanager::setPrivateSystemKey($key, $keyName); + + $this->assertTrue($this->view->file_exists('/owncloud_private_key/' . $keyName)); + + // clean up + $this->view->unlink('/owncloud_private_key/' . $keyName); + } + + + /** + * @medium + */ function testGetUserKeys() { $keys = Encryption\Keymanager::getUserKeys($this->view, $this->userId); @@ -189,7 +221,7 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase { $this->assertArrayHasKey('key', $sslInfoPublic); - $privateKey = Encryption\Crypt::symmetricDecryptFileContent($keys['privateKey'], $this->pass); + $privateKey = Encryption\Crypt::decryptPrivateKey($keys['privateKey'], $this->pass); $resPrivate = openssl_pkey_get_private($privateKey); diff --git a/apps/files_encryption/tests/share.php b/apps/files_encryption/tests/share.php index 7bbea6488bc..1f1304bb527 100755 --- a/apps/files_encryption/tests/share.php +++ b/apps/files_encryption/tests/share.php @@ -540,9 +540,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase { . $this->filename . '.' . $publicShareKeyId . '.shareKey')); // some hacking to simulate public link - $GLOBALS['app'] = 'files_sharing'; - $GLOBALS['fileOwner'] = \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1; - \OC_User::setUserId(false); + //$GLOBALS['app'] = 'files_sharing'; + //$GLOBALS['fileOwner'] = \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1; + \Test_Encryption_Util::logoutHelper(); // get file contents $retrievedCryptedFile = file_get_contents('crypt:///' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename); diff --git a/apps/files_encryption/tests/util.php b/apps/files_encryption/tests/util.php index d9fc819f981..f337eb46355 100755 --- a/apps/files_encryption/tests/util.php +++ b/apps/files_encryption/tests/util.php @@ -22,6 +22,9 @@ use OCA\Encryption; class Test_Encryption_Util extends \PHPUnit_Framework_TestCase { const TEST_ENCRYPTION_UTIL_USER1 = "test-util-user1"; + const TEST_ENCRYPTION_UTIL_USER2 = "test-util-user2"; + const TEST_ENCRYPTION_UTIL_GROUP1 = "test-util-group1"; + const TEST_ENCRYPTION_UTIL_GROUP2 = "test-util-group2"; const TEST_ENCRYPTION_UTIL_LEGACY_USER = "test-legacy-user"; public $userId; @@ -59,7 +62,15 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase { // create test user \Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1, true); + \Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER2, true); \Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER, true); + + // create groups + \OC_Group::createGroup(self::TEST_ENCRYPTION_UTIL_GROUP1); + \OC_Group::createGroup(self::TEST_ENCRYPTION_UTIL_GROUP2); + + // add user 1 to group1 + \OC_Group::addToGroup(self::TEST_ENCRYPTION_UTIL_USER1, self::TEST_ENCRYPTION_UTIL_GROUP1); } @@ -116,7 +127,11 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase { public static function tearDownAfterClass() { // cleanup test user \OC_User::deleteUser(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1); + \OC_User::deleteUser(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER2); \OC_User::deleteUser(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER); + //cleanup groups + \OC_Group::deleteGroup(self::TEST_ENCRYPTION_UTIL_GROUP1); + \OC_Group::deleteGroup(self::TEST_ENCRYPTION_UTIL_GROUP2); } /** @@ -458,6 +473,29 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase { } /** + * @dataProvider dataProviderFortestIsMountPointApplicableToUser + */ + function testIsMountPointApplicableToUser($mount, $expectedResult) { + self::loginHelper(self::TEST_ENCRYPTION_UTIL_USER1); + $dummyClass = new DummyUtilClass($this->view, self::TEST_ENCRYPTION_UTIL_USER1); + $result = $dummyClass->testIsMountPointApplicableToUser($mount); + + $this->assertSame($expectedResult, $result); + } + + function dataProviderFortestIsMountPointApplicableToUser() { + return array( + array(array('applicable' => array('groups' => array(), 'users' => array(self::TEST_ENCRYPTION_UTIL_USER1))), true), + array(array('applicable' => array('groups' => array(), 'users' => array(self::TEST_ENCRYPTION_UTIL_USER2))), false), + array(array('applicable' => array('groups' => array(self::TEST_ENCRYPTION_UTIL_GROUP1), 'users' => array())), true), + array(array('applicable' => array('groups' => array(self::TEST_ENCRYPTION_UTIL_GROUP1), 'users' => array(self::TEST_ENCRYPTION_UTIL_USER2))), true), + array(array('applicable' => array('groups' => array(self::TEST_ENCRYPTION_UTIL_GROUP2), 'users' => array(self::TEST_ENCRYPTION_UTIL_USER2))), false), + array(array('applicable' => array('groups' => array(self::TEST_ENCRYPTION_UTIL_GROUP2), 'users' => array(self::TEST_ENCRYPTION_UTIL_USER2, 'all'))), true), + array(array('applicable' => array('groups' => array(self::TEST_ENCRYPTION_UTIL_GROUP2), 'users' => array('all'))), true), + ); + } + + /** * @param string $user * @param bool $create * @param bool $password @@ -490,7 +528,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase { public static function logoutHelper() { \OC_Util::tearDownFS(); - \OC_User::setUserId(''); + \OC_User::setUserId(false); \OC\Files\Filesystem::tearDown(); } @@ -507,3 +545,12 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase { } } + +/** + * dummy class extends \OCA\Encryption\Util to access protected methods for testing + */ +class DummyUtilClass extends \OCA\Encryption\Util { + public function testIsMountPointApplicableToUser($mount) { + return $this->isMountPointApplicableToUser($mount); + } +} diff --git a/apps/files_external/l10n/sl.php b/apps/files_external/l10n/sl.php index 2c6c3220d95..5751782c861 100644 --- a/apps/files_external/l10n/sl.php +++ b/apps/files_external/l10n/sl.php @@ -29,6 +29,7 @@ $TRANSLATIONS = array( "OpenStack Object Storage" => "Shramba predmeta OpenStack", "Username (required)" => "Uporabniško ime (zahtevano)", "Region (optional for OpenStack Object Storage)" => "Območje (zahtevano za shrambo predmeta OpenStack)", +"API Key (required for Rackspace Cloud Files)" => "Ključ programskega vmesnika (API) (zahtevan je za datoteke v oblaku Rackspace)", "Tenantname (required for OpenStack Object Storage)" => "Ime uporabnika (zahtevano za shrambo predmeta OpenStack)", "Password (required for OpenStack Object Storage)" => "Geslo (zahtevano za shrambo predmeta OpenStack)", "Service Name (required for OpenStack Object Storage)" => "Ime storitve (zahtevano za shrambo predmeta OpenStack)", diff --git a/apps/files_sharing/ajax/external.php b/apps/files_sharing/ajax/external.php index 0dbd3ab8c95..390d5bfb9d8 100644 --- a/apps/files_sharing/ajax/external.php +++ b/apps/files_sharing/ajax/external.php @@ -33,16 +33,22 @@ $externalManager = new \OCA\Files_Sharing\External\Manager( $name = OCP\Files::buildNotExistingFileName('/', $name); -$mount = $externalManager->addShare($remote, $token, $password, $name, $owner); -/** - * @var \OCA\Files_Sharing\External\Storage $storage - */ -$storage = $mount->getStorage(); -$result = $storage->file_exists(''); -if($result){ - $storage->getScanner()->scanAll(); - \OCP\JSON::success(); +// check for ssl cert +if (substr($remote, 0, 5) === 'https' and !OC_Util::getUrlContent($remote)) { + \OCP\JSON::error(array('data' => array('message' => $l->t("Invalid or untrusted ssl certificate")))); + exit; } else { - $externalManager->removeShare($mount->getMountPoint()); - \OCP\JSON::error(array('data' => array('message' => $l->t("Couldn't add remote share")))); + $mount = $externalManager->addShare($remote, $token, $password, $name, $owner); + /** + * @var \OCA\Files_Sharing\External\Storage $storage + */ + $storage = $mount->getStorage(); + $result = $storage->file_exists(''); + if ($result) { + $storage->getScanner()->scanAll(); + \OCP\JSON::success(); + } else { + $externalManager->removeShare($mount->getMountPoint()); + \OCP\JSON::error(array('data' => array('message' => $l->t("Couldn't add remote share")))); + } } diff --git a/apps/files_sharing/l10n/fa.php b/apps/files_sharing/l10n/fa.php index 8370c185b5f..b19879075e4 100644 --- a/apps/files_sharing/l10n/fa.php +++ b/apps/files_sharing/l10n/fa.php @@ -1,20 +1,38 @@ <?php $TRANSLATIONS = array( "Server to server sharing is not enabled on this server" => "اشتراک سرور به سرور در این سرور فعال نیست .", +"Couldn't add remote share" => "امکان افزودن اشتراک گذاری از راه دور وجود ندارد", +"Shared with you" => "موارد به اشتراک گذاشته شده با شما", +"Shared with others" => "موارد به اشتراک گذاشته شده با دیگران", +"Shared by link" => "اشتراک گذاشته شده از طریق پیوند", +"No files have been shared with you yet." => "هنوز هیچ فایلی با شما به اشتراک گذاشته نشده است.", +"You haven't shared any files yet." => "شما هنوز هیچ فایلی را به اشتراک نگذاشته اید.", +"You haven't shared any files by link yet." => "شما هنوز هیچ فایلی را از طریق پیوند با کسی به اشتراک نگذاشته اید.", +"Do you want to add the remote share {name} from {owner}@{remote}?" => "آیا مایل به افزودن اشتراک از راه دور {name} از {owner}@{remote} هستید.", +"Remote share" => "اشتراک از راه دور", +"Remote share password" => "رمز عبور اشتراک از راه دور", "Cancel" => "منصرف شدن", +"Add remote share" => "افزودن اشتراک از راه دور", +"No ownCloud installation found at {remote}" => "نمونه ای از ownCloud نصب شده در {remote} یافت نشد", +"Invalid ownCloud url" => "آدرس نمونه ownCloud غیر معتبر است", "Shared by" => "اشتراک گذاشته شده به وسیله", "This share is password-protected" => "این اشتراک توسط رمز عبور محافظت می شود", "The password is wrong. Try again." => "رمزعبور اشتباه می باشد. دوباره امتحان کنید.", "Password" => "گذرواژه", "Name" => "نام", +"Share time" => "زمان به اشتراک گذاری", "Sorry, this link doesn’t seem to work anymore." => "متاسفانه این پیوند دیگر کار نمی کند", "Reasons might be:" => "ممکن است به این دلایل باشد:", "the item was removed" => "این مورد حذف شده است", "the link expired" => "این پیوند منقضی شده است", "sharing is disabled" => "قابلیت اشتراک گذاری غیرفعال است", "For more info, please ask the person who sent this link." => "برای اطلاعات بیشتر، لطفا از شخصی که این پیوند را ارسال کرده سوال بفرمایید.", +"Add to your ownCloud" => "افزودن به ownCloud شما", "Download" => "دانلود", "Download %s" => "دانلود %s", -"Direct link" => "پیوند مستقیم" +"Direct link" => "پیوند مستقیم", +"Remote Shares" => "اشتراک های از راه دور", +"Allow other instances to mount public links shared from this server" => "اجازه به نمونه های دیگر برای مانت کردن پیوند های عمومی به اشتراک گذاشته شده از این سرور", +"Allow users to mount public link shares" => "اجازه دادن به کاربران برای مانت پیوندهای عمومی موارد به اشتراک گذاری" ); $PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/apps/files_sharing/lib/sharedstorage.php b/apps/files_sharing/lib/sharedstorage.php index 8d5b22dc283..02fcd7041dd 100644 --- a/apps/files_sharing/lib/sharedstorage.php +++ b/apps/files_sharing/lib/sharedstorage.php @@ -48,10 +48,10 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage { /** * get file cache of the shared item source - * @return string + * @return int */ public function getSourceId() { - return $this->share['file_source']; + return (int) $this->share['file_source']; } /** diff --git a/apps/files_trashbin/l10n/ja.php b/apps/files_trashbin/l10n/ja.php index b24e40aa23d..059579fc88d 100644 --- a/apps/files_trashbin/l10n/ja.php +++ b/apps/files_trashbin/l10n/ja.php @@ -8,7 +8,7 @@ $TRANSLATIONS = array( "restored" => "復元済", "Nothing in here. Your trash bin is empty!" => "ここには何もありません。ゴミ箱は空です!", "Name" => "名前", -"Deleted" => "削除済み", +"Deleted" => "削除日時", "Delete" => "削除" ); $PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/apps/user_ldap/l10n/fa.php b/apps/user_ldap/l10n/fa.php index 1e149a11207..cf350991b44 100644 --- a/apps/user_ldap/l10n/fa.php +++ b/apps/user_ldap/l10n/fa.php @@ -4,23 +4,48 @@ $TRANSLATIONS = array( "Failed to delete the server configuration" => "عملیات حذف پیکربندی سرور ناموفق ماند", "The configuration is valid and the connection could be established!" => "پیکربندی معتبر است و ارتباط می تواند برقرار شود", "The configuration is valid, but the Bind failed. Please check the server settings and credentials." => "پیکربندی معتبراست، اما اتصال شکست خورد. لطفا تنظیمات و اعتبارهای سرور را بررسی کنید.", +"No action specified" => "فعالیتی مشخص نشده است", +"No configuration specified" => "هیچ پیکربندی مشخص نشده است", +"No data specified" => "داده ای مشخص نشده است", "Deletion failed" => "حذف کردن انجام نشد", "Keep settings?" => "آیا تنظیمات ذخیره شود ؟", +"{nthServer}. Server" => "سرور {nthServer}.", "Cannot add server configuration" => "نمی توان پیکربندی سرور را اضافه نمود", "mappings cleared" => "نگاشت پاک شده است", "Success" => "موفقیت", "Error" => "خطا", +"Please specify a Base DN" => "لطفا نام دامنه (DN) پایه را مشخص کنید.", +"Could not determine Base DN" => "امکان تشخیص نام دامنه (DN) پایه وجود ندارد", +"Please specify the port" => "لطفا پورت مورد نظر را مشخص کنید.", +"Configuration OK" => "پیکربندی صحیح است", +"Configuration incorrect" => "پیکربندی نادرست است", +"Configuration incomplete" => "پیکربندی کامل نیست", +"Select groups" => "انتخاب گروه ها", +"Select object classes" => "انتخاب کلاس های اشیا", +"Select attributes" => "انتخاب مشخصه ها", "Connection test succeeded" => "تست اتصال با موفقیت انجام گردید", "Connection test failed" => "تست اتصال ناموفق بود", "Do you really want to delete the current Server Configuration?" => "آیا واقعا می خواهید پیکربندی کنونی سرور را حذف کنید؟", "Confirm Deletion" => "تایید حذف", -"_%s group found_::_%s groups found_" => array(""), -"_%s user found_::_%s users found_" => array(""), +"_%s group found_::_%s groups found_" => array("%s گروه بافت شد"), +"_%s user found_::_%s users found_" => array("%s کاربر بافت شد"), +"Invalid Host" => "هاست نامعتبر است", +"Server" => "سرور", +"User Filter" => "فیلتر کاربر", +"Login Filter" => "فیلتر لاگین", "Group Filter" => "فیلتر گروه", "Save" => "ذخیره", "Test Configuration" => "امتحان پیکربندی", "Help" => "راهنما", +"Raw LDAP filter" => "فیلتر ال.دپ خام", +"groups found" => "گروه های یافت شده", +"LDAP Username:" => "نام کاربری LDAP:", +"LDAP Email Address:" => "آدرس ایمیل LDAP:", +"Other Attributes:" => "مشخصه های دیگر:", +"1. Server" => "1. سرور", +"%s. Server:" => "%s. سرور:", "Add Server Configuration" => "افزودن پیکربندی سرور", +"Delete Configuration" => "حذف پیکربندی", "Host" => "میزبانی", "Port" => "درگاه", "User DN" => "کاربر DN", @@ -28,8 +53,10 @@ $TRANSLATIONS = array( "For anonymous access, leave DN and Password empty." => "برای دسترسی ناشناس، DN را رها نموده و رمزعبور را خالی بگذارید.", "One Base DN per line" => "یک پایه DN در هر خط", "You can specify Base DN for users and groups in the Advanced tab" => "شما می توانید پایه DN را برای کاربران و گروه ها در زبانه Advanced مشخص کنید.", +"users found" => "کاربران یافت شده", "Back" => "بازگشت", "Continue" => "ادامه", +"Expert" => "حرفه ای", "Advanced" => "پیشرفته", "Connection Settings" => "تنظیمات اتصال", "Configuration Active" => "پیکربندی فعال", |