summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorin Peter <github@florin-peter.de>2013-05-15 10:18:25 +0200
committerFlorin Peter <github@florin-peter.de>2013-05-15 10:18:25 +0200
commit01f1153b0870b8a24586c099131679f992e0d05e (patch)
tree484c32f288c5593d4b646332db1eae382fe762f9
parent226aec8d5602e112c413f8c0548b18c737a65a02 (diff)
parent7461e9c2b5bdabd0b712f91a22445a0d933cf88f (diff)
downloadnextcloud-server-01f1153b0870b8a24586c099131679f992e0d05e.tar.gz
nextcloud-server-01f1153b0870b8a24586c099131679f992e0d05e.zip
Merge branch 'files_encryption' of https://github.com/owncloud/core into files_encryption
Conflicts: apps/files/l10n/ar.php apps/files/l10n/bn_BD.php apps/files/l10n/de.php apps/files/l10n/de_DE.php apps/files/l10n/el.php apps/files/l10n/es.php apps/files/l10n/fa.php apps/files/l10n/fr.php apps/files/l10n/gl.php apps/files/l10n/id.php apps/files/l10n/ko.php apps/files/l10n/nl.php apps/files/l10n/nn_NO.php apps/files/l10n/pl.php apps/files/l10n/pt_BR.php apps/files/l10n/pt_PT.php apps/files/l10n/ro.php apps/files/l10n/ru.php apps/files/l10n/sl.php apps/files/l10n/uk.php apps/files/l10n/vi.php apps/files_encryption/l10n/ca.php apps/files_sharing/lib/cache.php apps/files_sharing/lib/sharedstorage.php apps/user_ldap/l10n/tr.php core/l10n/cs_CZ.php core/l10n/de.php core/l10n/de_DE.php core/l10n/ru.php core/l10n/sk_SK.php core/l10n/tr.php core/l10n/vi.php core/l10n/zh_CN.php l10n/af_ZA/files.po l10n/ar/files.po l10n/be/files.po l10n/bg_BG/files.po l10n/bn_BD/files.po l10n/ca/files.po l10n/ca/files_encryption.po l10n/cs_CZ/core.po l10n/cs_CZ/files.po l10n/da/files.po l10n/da/settings.po l10n/de/core.po l10n/de/files.po l10n/de/files_encryption.po l10n/de/files_external.po l10n/de/files_sharing.po l10n/de/files_trashbin.po l10n/de/files_versions.po l10n/de/lib.po l10n/de/settings.po l10n/de/user_ldap.po l10n/de_DE/files.po l10n/de_DE/files_encryption.po l10n/de_DE/files_external.po l10n/de_DE/files_sharing.po l10n/de_DE/files_trashbin.po l10n/de_DE/lib.po l10n/de_DE/settings.po l10n/de_DE/user_ldap.po l10n/el/files.po l10n/eo/files.po l10n/es/files.po l10n/es/lib.po l10n/es/settings.po l10n/es_AR/files.po l10n/eu/files.po l10n/fa/files.po l10n/fi/files.po l10n/fi_FI/files.po l10n/fr/core.po l10n/fr/files.po l10n/gl/files.po l10n/gl/settings.po l10n/he/core.po l10n/he/files.po l10n/he/user_ldap.po l10n/hi/files.po l10n/hr/files.po l10n/hu_HU/core.po l10n/hu_HU/files.po l10n/hu_HU/files_external.po l10n/hu_HU/settings.po l10n/hy/files.po l10n/ia/core.po l10n/ia/files.po l10n/ia/files_trashbin.po l10n/ia/settings.po l10n/id/files.po l10n/is/files.po l10n/it/files.po l10n/ja_JP/files.po l10n/ja_JP/user_ldap.po l10n/ka/files.po l10n/ka_GE/files.po l10n/kn/files.po l10n/ko/files.po l10n/ko/files_trashbin.po l10n/ko/settings.po l10n/ku_IQ/files.po l10n/lb/files.po l10n/lt_LT/core.po l10n/lt_LT/files.po l10n/lv/files.po l10n/mk/files.po l10n/ms_MY/files.po l10n/my_MM/files.po l10n/nb_NO/files.po l10n/ne/files.po l10n/nl/core.po l10n/nl/files.po l10n/nn_NO/files.po l10n/oc/files.po l10n/pl/files.po l10n/pl_PL/files.po l10n/pt_BR/files.po l10n/pt_PT/core.po l10n/pt_PT/files.po l10n/pt_PT/files_external.po l10n/pt_PT/settings.po l10n/ro/files.po l10n/ru/core.po l10n/ru/files.po l10n/si_LK/files.po l10n/sk/files.po l10n/sk_SK/core.po l10n/sk_SK/files.po l10n/sl/core.po l10n/sl/files.po l10n/sq/files.po l10n/sr/files.po l10n/sr@latin/files.po l10n/sv/files.po l10n/sw_KE/files.po l10n/ta_LK/files.po l10n/te/files.po l10n/th_TH/files.po l10n/tr/core.po l10n/tr/files.po l10n/tr/lib.po l10n/tr/settings.po l10n/tr/user_ldap.po l10n/uk/files.po l10n/ur_PK/files.po l10n/vi/core.po l10n/vi/files.po l10n/vi/files_external.po l10n/zh_CN.GB2312/files.po l10n/zh_CN/core.po l10n/zh_CN/files.po l10n/zh_CN/settings.po l10n/zh_HK/files.po l10n/zh_TW/core.po l10n/zh_TW/files.po l10n/zh_TW/files_versions.po l10n/zh_TW/settings.po l10n/zh_TW/user_ldap.po lib/base.php lib/files/filesystem.php lib/files/view.php lib/public/share.php settings/l10n/es.php settings/l10n/pt_PT.php settings/l10n/tr.php settings/l10n/zh_CN.php settings/personal.php
-rw-r--r--apps/files_encryption/ajax/adminrecovery.php121
-rw-r--r--apps/files_encryption/ajax/encryptall.php40
-rw-r--r--apps/files_encryption/ajax/userrecovery.php27
-rw-r--r--apps/files_encryption/appinfo/app.php24
-rw-r--r--apps/files_encryption/appinfo/database.xml7
-rw-r--r--apps/files_encryption/css/settings-personal.css10
-rw-r--r--apps/files_encryption/hooks/hooks.php398
-rw-r--r--apps/files_encryption/js/settings-admin.js40
-rw-r--r--apps/files_encryption/js/settings-personal.js60
-rw-r--r--apps/files_encryption/js/settings.js36
-rw-r--r--apps/files_encryption/l10n/de.php2
-rw-r--r--apps/files_encryption/l10n/de_DE.php2
-rw-r--r--apps/files_encryption/l10n/el.php2
-rw-r--r--apps/files_encryption/l10n/eu.php2
-rw-r--r--apps/files_encryption/l10n/it.php2
-rw-r--r--apps/files_encryption/l10n/pl.php2
-rw-r--r--apps/files_encryption/l10n/pt_BR.php2
-rw-r--r--apps/files_encryption/l10n/ru.php2
-rw-r--r--apps/files_encryption/l10n/sk_SK.php2
-rw-r--r--apps/files_encryption/l10n/th_TH.php2
-rw-r--r--apps/files_encryption/l10n/vi.php2
-rwxr-xr-xapps/files_encryption/lib/helper.php93
-rwxr-xr-xapps/files_encryption/lib/keymanager.php139
-rw-r--r--apps/files_encryption/lib/proxy.php267
-rw-r--r--apps/files_encryption/lib/session.php65
-rw-r--r--apps/files_encryption/lib/stream.php97
-rw-r--r--apps/files_encryption/lib/util.php628
-rw-r--r--apps/files_encryption/settings-admin.php (renamed from apps/files_encryption/settings.php)12
-rw-r--r--apps/files_encryption/settings-personal.php25
-rw-r--r--apps/files_encryption/templates/settings-admin.php (renamed from apps/files_encryption/templates/settings.php)20
-rw-r--r--apps/files_encryption/templates/settings-personal.php48
-rw-r--r--apps/files_encryption/tests/binary (renamed from apps/files_encryption/test/binary)bin9734 -> 9734 bytes
-rwxr-xr-xapps/files_encryption/tests/crypt.php (renamed from apps/files_encryption/test/crypt.php)248
-rw-r--r--apps/files_encryption/tests/keymanager.php (renamed from apps/files_encryption/test/keymanager.php)78
-rw-r--r--apps/files_encryption/tests/legacy-encrypted-text.txt (renamed from apps/files_encryption/test/legacy-encrypted-text.txt)bin3360 -> 3360 bytes
-rw-r--r--apps/files_encryption/tests/proxy.php (renamed from apps/files_encryption/test/proxy.php)0
-rwxr-xr-xapps/files_encryption/tests/share.php473
-rw-r--r--apps/files_encryption/tests/stream.php (renamed from apps/files_encryption/test/stream.php)2
-rwxr-xr-xapps/files_encryption/tests/util.php (renamed from apps/files_encryption/test/util.php)100
-rw-r--r--apps/files_encryption/tests/zeros (renamed from apps/files_encryption/test/zeros)bin10238 -> 10238 bytes
-rw-r--r--apps/files_trashbin/l10n/bg_BG.php3
-rw-r--r--apps/files_trashbin/l10n/id.php8
-rw-r--r--apps/files_trashbin/l10n/nn_NO.php5
-rw-r--r--apps/files_trashbin/l10n/pl.php4
-rw-r--r--apps/files_trashbin/l10n/pt_PT.php2
-rw-r--r--apps/files_trashbin/l10n/ro.php1
-rw-r--r--apps/files_trashbin/l10n/sk_SK.php2
-rw-r--r--apps/files_trashbin/lib/trash.php190
-rw-r--r--tests/enable_all.php1
49 files changed, 2464 insertions, 832 deletions
diff --git a/apps/files_encryption/ajax/adminrecovery.php b/apps/files_encryption/ajax/adminrecovery.php
index cec0cd4ddda..6a056dc7b3d 100644
--- a/apps/files_encryption/ajax/adminrecovery.php
+++ b/apps/files_encryption/ajax/adminrecovery.php
@@ -1,6 +1,5 @@
-setValue( $app, $key, $value )
-
<?php
+
/**
* Copyright (c) 2013, Sam Tuke <samtuke@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or later.
@@ -8,69 +7,79 @@ setValue( $app, $key, $value )
*
* @brief Script to handle admin settings for encrypted key recovery
*/
-
use OCA\Encryption;
\OCP\JSON::checkAdminUser();
-\OCP\JSON::checkAppEnabled( 'files_encryption' );
+\OCP\JSON::checkAppEnabled('files_encryption');
\OCP\JSON::callCheck();
-$return = $doSetup = false;
+$return = false;
+
+// Enable recoveryAdmin
-if (
- isset( $_POST['adminEnableRecovery'] )
- && $_POST['adminEnableRecovery'] == 1
- && isset( $_POST['recoveryPassword'] )
- && ! empty ( $_POST['recoveryPassword'] )
+if (
+ isset($_POST['adminEnableRecovery'])
+ && 1 == $_POST['adminEnableRecovery']
) {
- // TODO: Let the admin set this themselves
- $recoveryAdminUid = 'recoveryAdmin';
-
- // If desired recoveryAdmin UID is already in use
- if ( ! \OC_User::userExists( $recoveryAdminUid ) ) {
-
- // Create new recoveryAdmin user
- \OC_User::createUser( $recoveryAdminUid, $_POST['recoveryPassword'] );
-
- $doSetup = true;
-
- } else {
-
- // Get list of admin users
- $admins = OC_Group::usersInGroup( 'admin' );
-
- // If the existing recoveryAdmin UID is an admin
- if ( in_array( $recoveryAdminUid, $admins ) ) {
-
- // The desired recoveryAdmi UID pre-exists and can be used
- $doSetup = true;
-
- // If the recoveryAdmin UID exists but doesn't have admin rights
- } else {
-
- $return = false;
-
- }
-
+ $view = new \OC\Files\View('/');
+
+ $recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId');
+
+ if ($recoveryKeyId === null) {
+ $recoveryKeyId = 'recovery_' . substr(md5(time()), 0, 8);
+ \OC_Appconfig::setValue('files_encryption', 'recoveryKeyId', $recoveryKeyId);
}
-
- // If recoveryAdmin has passed other checks
- if ( $doSetup ) {
-
- $view = new \OC_FilesystemView( '/' );
- $util = new Util( $view, $recoveryAdminUid );
-
- // Ensure recoveryAdmin is ready for encryption (has usable keypair etc.)
- $util->setupServerSide( $_POST['recoveryPassword'] );
-
- // Store the UID in the DB
- OC_Appconfig::setValue( 'files_encryption', 'recoveryAdminUid', $recoveryAdminUid );
-
- $return = true;
-
+
+ if (!$view->is_dir('/owncloud_private_key')) {
+ $view->mkdir('/owncloud_private_key');
+ }
+
+ if (
+ (!$view->file_exists("/public-keys/" . $recoveryKeyId . ".public.key")
+ || !$view->file_exists("/owncloud_private_key/" . $recoveryKeyId . ".private.key"))
+ && isset($_POST['recoveryPassword'])
+ && !empty($_POST['recoveryPassword'])
+ ) {
+
+ $keypair = \OCA\Encryption\Crypt::createKeypair();
+
+ \OC_FileProxy::$enabled = false;
+
+ // Save public key
+
+ if (!$view->is_dir('/public-keys')) {
+ $view->mkdir('/public-keys');
+ }
+
+ $view->file_put_contents('/public-keys/' . $recoveryKeyId . '.public.key', $keypair['publicKey']);
+
+ // Encrypt private key empthy passphrase
+ $encryptedPrivateKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($keypair['privateKey'], $_POST['recoveryPassword']);
+
+ // Save private key
+ $view->file_put_contents('/owncloud_private_key/' . $recoveryKeyId . '.private.key', $encryptedPrivateKey);
+
+ \OC_FileProxy::$enabled = true;
+
}
-
+
+ // Set recoveryAdmin as enabled
+ OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1);
+
+ $return = true;
+
+// Disable recoveryAdmin
+} elseif (
+ isset($_POST['adminEnableRecovery'])
+ && 0 == $_POST['adminEnableRecovery']
+) {
+
+ // Set recoveryAdmin as enabled
+ OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 0);
+
+ $return = true;
}
-($return) ? OC_JSON::success() : OC_JSON::error(); \ No newline at end of file
+// Return success or failure
+( $return ) ? \OCP\JSON::success() : \OCP\JSON::error(); \ No newline at end of file
diff --git a/apps/files_encryption/ajax/encryptall.php b/apps/files_encryption/ajax/encryptall.php
new file mode 100644
index 00000000000..ce613ca4435
--- /dev/null
+++ b/apps/files_encryption/ajax/encryptall.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Copyright (c) 2013, Sam Tuke <samtuke@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or later.
+ * See the COPYING-README file.
+ *
+ * @brief Script to handle manual trigger of \OCA\Encryption\Util{}->encryptAll()
+ */
+
+use OCA\Encryption;
+
+\OCP\JSON::checkAppEnabled( 'files_encryption' );
+\OCP\JSON::callCheck();
+
+$return = false;
+
+if (
+ isset( $_POST['encryptAll'] )
+ && ! empty( $_POST['userPassword'] )
+) {
+
+ $view = new \OC_FilesystemView( '' );
+ $userId = \OCP\User::getUser();
+ $util = new \OCA\Encryption\Util( $view, $userId );
+ $session = new \OCA\Encryption\Session( $view );
+ $publicKey = \OCA\Encryption\Keymanager::getPublicKey( $view, $userId );
+ $path = '/' . $userId . '/' . 'files';
+
+ $util->encryptAll( $publicKey, $path, $session->getLegacyKey(), $_POST['userPassword'] );
+
+ $return = true;
+
+} else {
+
+ $return = false;
+
+}
+
+// Return success or failure
+( $return ) ? \OCP\JSON::success() : \OCP\JSON::error(); \ No newline at end of file
diff --git a/apps/files_encryption/ajax/userrecovery.php b/apps/files_encryption/ajax/userrecovery.php
index 56c18f7ad5b..85a799011d7 100644
--- a/apps/files_encryption/ajax/userrecovery.php
+++ b/apps/files_encryption/ajax/userrecovery.php
@@ -1,5 +1,3 @@
-setValue( $app, $key, $value )
-
<?php
/**
* Copyright (c) 2013, Sam Tuke <samtuke@owncloud.com>
@@ -17,26 +15,21 @@ use OCA\Encryption;
if (
isset( $_POST['userEnableRecovery'] )
+ && ( 0 == $_POST['userEnableRecovery'] || 1 == $_POST['userEnableRecovery'] )
) {
- // Ensure preference is an integer
- $recoveryEnabled = intval( $_POST['userEnableRecovery'] );
-
$userId = \OCP\USER::getUser();
$view = new \OC_FilesystemView( '/' );
- $util = new Util( $view, $userId );
+ $util = new \OCA\Encryption\Util( $view, $userId );
// Save recovery preference to DB
- $result = $util->setRecovery( $recoveryEnabled );
-
- if ( $result ) {
+ $return = $util->setRecoveryForUser( $_POST['userEnableRecovery'] );
- \OCP\JSON::success();
-
- } else {
-
- \OCP\JSON::error();
-
- }
+} else {
+
+ $return = false;
-} \ No newline at end of file
+}
+
+// Return success or failure
+( $return ) ? \OCP\JSON::success() : \OCP\JSON::error(); \ No newline at end of file
diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php
index c2de9d0b441..b611eb798f3 100644
--- a/apps/files_encryption/appinfo/app.php
+++ b/apps/files_encryption/appinfo/app.php
@@ -8,24 +8,25 @@ OC::$CLASSPATH['OCA\Encryption\Stream'] = 'files_encryption/lib/stream.php';
OC::$CLASSPATH['OCA\Encryption\Proxy'] = 'files_encryption/lib/proxy.php';
OC::$CLASSPATH['OCA\Encryption\Session'] = 'files_encryption/lib/session.php';
OC::$CLASSPATH['OCA\Encryption\Capabilities'] = 'files_encryption/lib/capabilities.php';
+OC::$CLASSPATH['OCA\Encryption\Helper'] = 'files_encryption/lib/helper.php';
OC_FileProxy::register( new OCA\Encryption\Proxy() );
-// User-related hooks
-OCP\Util::connectHook( 'OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login' );
-OCP\Util::connectHook( 'OC_User', 'pre_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase' );
+// User related hooks
+OCA\Encryption\Helper::registerUserHooks();
-// Sharing-related hooks
-OCP\Util::connectHook( 'OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared' );
-OCP\Util::connectHook( 'OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare' );
-OCP\Util::connectHook( 'OCP\Share', 'post_unshareAll', 'OCA\Encryption\Hooks', 'postUnshareAll' );
+// Sharing related hooks
+OCA\Encryption\Helper::registerShareHooks();
-// Webdav-related hooks
-OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfileFromClient' );
+// Webdav related hooks
+OCA\Encryption\Helper::registerWebdavHooks();
+
+// Filesystem related hooks
+OCA\Encryption\Helper::registerFilesystemHooks();
stream_wrapper_register( 'crypt', 'OCA\Encryption\Stream' );
-$view = new OC_FilesystemView( '/' );
+$view = new \OC\Files\View( '/' );
$session = new OCA\Encryption\Session( $view );
@@ -47,5 +48,6 @@ if (
}
// Register settings scripts
-OCP\App::registerAdmin( 'files_encryption', 'settings' );
+OCP\App::registerAdmin( 'files_encryption', 'settings-admin' );
OCP\App::registerPersonal( 'files_encryption', 'settings-personal' );
+
diff --git a/apps/files_encryption/appinfo/database.xml b/apps/files_encryption/appinfo/database.xml
index b144b6cb2a4..64c9ef65fa8 100644
--- a/apps/files_encryption/appinfo/database.xml
+++ b/apps/files_encryption/appinfo/database.xml
@@ -27,6 +27,13 @@
<default>0</default>
<comments>Whether encryption key recovery is enabled</comments>
</field>
+ <field>
+ <name>migrationStatus</name>
+ <type>boolean</type>
+ <notnull>true</notnull>
+ <default>0</default>
+ <comments>Whether encryption migration has been performed</comments>
+ </field>
</declaration>
</table>
</database> \ No newline at end of file
diff --git a/apps/files_encryption/css/settings-personal.css b/apps/files_encryption/css/settings-personal.css
new file mode 100644
index 00000000000..4ee0acc9768
--- /dev/null
+++ b/apps/files_encryption/css/settings-personal.css
@@ -0,0 +1,10 @@
+/* Copyright (c) 2013, Sam Tuke, <samtuke@owncloud.com>
+ This file is licensed under the Affero General Public License version 3 or later.
+ See the COPYING-README file. */
+
+#encryptAllError
+, #encryptAllSuccess
+, #recoveryEnabledError
+, #recoveryEnabledSuccess {
+ display: none;
+} \ No newline at end of file
diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php
index 2ac74ad6c44..31175d1c346 100644
--- a/apps/files_encryption/hooks/hooks.php
+++ b/apps/files_encryption/hooks/hooks.php
@@ -23,10 +23,11 @@
namespace OCA\Encryption;
+use OC\Files\Filesystem;
+
/**
* Class for hook specific logic
*/
-
class Hooks {
// TODO: use passphrase for encrypting private key that is separate to
@@ -46,15 +47,11 @@ class Hooks {
$view = new \OC_FilesystemView( '/' );
$util = new Util( $view, $params['uid'] );
-
- // Check files_encryption infrastructure is ready for action
- if ( ! $util->ready() ) {
-
- \OC_Log::write( 'Encryption library', 'User account "' . $params['uid'] . '" is not ready for encryption; configuration started', \OC_Log::DEBUG );
-
- return $util->setupServerSide( $params['password'] );
- }
+ // setup user, if user not ready force relogin
+ if(Helper::setupUser($util, $params['password']) === false) {
+ return false;
+ }
\OC_FileProxy::$enabled = false;
@@ -67,49 +64,89 @@ class Hooks {
$session = new Session( $view );
$session->setPrivateKey( $privateKey, $params['uid'] );
-
- //FIXME: disabled because it gets called each time a user do an operation on iPhone
- //FIXME: we need a better place doing this and maybe only one time or by user
- /*$view1 = new \OC_FilesystemView( '/' . $params['uid'] );
- // Set legacy encryption key if it exists, to support
- // depreciated encryption system
- if (
- $view1->file_exists( 'encryption.key' )
- && $encLegacyKey = $view1->file_get_contents( 'encryption.key' )
- ) {
+ // Check if first-run file migration has already been performed
+ $migrationCompleted = $util->getMigrationStatus();
- $plainLegacyKey = Crypt::legacyDecrypt( $encLegacyKey, $params['password'] );
-
- $session->setLegacyKey( $plainLegacyKey );
+ // If migration not yet done
+ if ( ! $migrationCompleted ) {
- }
-
- \OC_FileProxy::$enabled = false;
-
- $publicKey = Keymanager::getPublicKey( $view, $params['uid'] );
-
- \OC_FileProxy::$enabled = false;*/
-
- // Encrypt existing user files:
- // This serves to upgrade old versions of the encryption
- // app (see appinfo/spec.txt)
- /*if (
- $util->encryptAll( $publicKey, '/' . $params['uid'] . '/' . 'files', $session->getLegacyKey(), $params['password'] )
- ) {
+ $view1 = new \OC_FilesystemView( '/' . $params['uid'] );
+
+ // Set legacy encryption key if it exists, to support
+ // depreciated encryption system
+ if (
+ $view1->file_exists( 'encryption.key' )
+ && $encLegacyKey = $view1->file_get_contents( 'encryption.key' )
+ ) {
+
+ $plainLegacyKey = Crypt::legacyDecrypt( $encLegacyKey, $params['password'] );
+
+ $session->setLegacyKey( $plainLegacyKey );
- \OC_Log::write(
- 'Encryption library', 'Encryption of existing files belonging to "' . $params['uid'] . '" started at login'
- , \OC_Log::INFO
- );
+ }
+
+ \OC_FileProxy::$enabled = false;
+
+ $publicKey = Keymanager::getPublicKey( $view, $params['uid'] );
+
+ \OC_FileProxy::$enabled = false;
+
+ // Encrypt existing user files:
+ // This serves to upgrade old versions of the encryption
+ // app (see appinfo/spec.txt)
+ if (
+ $util->encryptAll( $publicKey, '/' . $params['uid'] . '/' . 'files', $session->getLegacyKey(), $params['password'] )
+ ) {
+
+ \OC_Log::write(
+ 'Encryption library', 'Encryption of existing files belonging to "' . $params['uid'] . '" completed'
+ , \OC_Log::INFO
+ );
+
+ }
+
+ // Register successful migration in DB
+ $util->setMigrationStatus( 1 );
- }*/
+ }
return true;
}
-
- /**
+
+ /**
+ * @brief setup encryption backend upon user created
+ * @note This method should never be called for users using client side encryption
+ */
+ public static function postCreateUser( $params ) {
+ $view = new \OC_FilesystemView( '/' );
+
+ $util = new Util( $view, $params['uid'] );
+
+ Helper::setupUser($util, $params['password']);
+ }
+
+ /**
+ * @brief cleanup encryption backend upon user deleted
+ * @note This method should never be called for users using client side encryption
+ */
+ public static function postDeleteUser( $params ) {
+ $view = new \OC_FilesystemView( '/' );
+
+ // cleanup public key
+ $publicKey = '/public-keys/' . $params['uid'] . '.public.key';
+
+ // Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ $view->unlink($publicKey);
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+ }
+
+ /**
* @brief Change a user's encryption passphrase
* @param array $params keys: uid, password
*/
@@ -119,8 +156,10 @@ class Hooks {
// is in use (client-side encryption does not have access to
// the necessary keys)
if ( Crypt::mode() == 'server' ) {
-
- $session = new Session();
+
+ $view = new \OC_FilesystemView( '/' );
+
+ $session = new Session($view);
// Get existing decrypted private key
$privateKey = $session->getPrivateKey();
@@ -165,7 +204,36 @@ class Hooks {
}
}
-
+
+ /*
+ * @brief check if files can be encrypted to every user.
+ */
+ public static function preShared($params) {
+
+ $users = array();
+ $view = new \OC\Files\View('/public-keys/');
+
+ switch ($params['shareType']) {
+ case \OCP\Share::SHARE_TYPE_USER:
+ $users[] = $params['shareWith'];
+ break;
+ case \OCP\Share::SHARE_TYPE_GROUP:
+ $users = \OC_Group::usersInGroup($params['shareWith']);
+ break;
+ }
+
+ foreach ($users as $user) {
+ if (!$view->file_exists($user . '.public.key')) {
+ // Set flag var 'run' to notify emitting
+ // script that hook execution failed
+ $params['run']->run = false;
+ // TODO: Make sure files_sharing provides user
+ // feedback on failed share
+ break;
+ }
+ }
+ }
+
/**
* @brief
*/
@@ -187,7 +255,9 @@ class Hooks {
// [fileTarget] => /test8
// [id] => 10
// [token] =>
+ // [run] => whether emitting script should continue to run
// TODO: Should other kinds of item be encrypted too?
+
if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
$view = new \OC_FilesystemView('/');
@@ -196,13 +266,55 @@ class Hooks {
$util = new Util($view, $userId);
$path = $util->fileIdToPath($params['itemSource']);
- //check if this is a reshare action, that's true if the item source is already shared with me
- $sharedItem = \OCP\Share::getItemSharedWithBySource($params['itemType'], $params['itemSource']);
- if ($sharedItem) {
- // if it is a re-share than the file is located in my Shared folder
- $path = '/Shared'.$sharedItem['file_target'];
- } else {
- $path = $util->fileIdToPath($params['itemSource']);
+ //if parent is set, then this is a re-share action
+ if ($params['parent']) {
+
+ // get the parent from current share
+ $parent = $util->getShareParent($params['parent']);
+
+ // if parent is file the it is an 1:1 share
+ if ($parent['item_type'] === 'file') {
+
+ // prefix path with Shared
+ $path = '/Shared' . $parent['file_target'];
+ } else {
+
+ // NOTE: parent is folder but shared was a file!
+ // we try to rebuild the missing path
+ // some examples we face here
+ // user1 share folder1 with user2 folder1 has
+ // the following structure
+ // /folder1/subfolder1/subsubfolder1/somefile.txt
+ // user2 re-share subfolder2 with user3
+ // user3 re-share somefile.txt user4
+ // so our path should be
+ // /Shared/subfolder1/subsubfolder1/somefile.txt
+ // while user3 is sharing
+
+ if ($params['itemType'] === 'file') {
+ // get target path
+ $targetPath = $util->fileIdToPath($params['fileSource']);
+ $targetPathSplit = array_reverse(explode('/', $targetPath));
+
+ // init values
+ $path = '';
+ $sharedPart = ltrim($parent['file_target'], '/');
+
+ // rebuild path
+ foreach ($targetPathSplit as $pathPart) {
+ if ($pathPart !== $sharedPart) {
+ $path = '/' . $pathPart . $path;
+ } else {
+ break;
+ }
+ }
+ // prefix path with Shared
+ $path = '/Shared' . $parent['file_target'] . $path;
+ } else {
+ // prefix path with Shared
+ $path = '/Shared' . $parent['file_target'] . $params['fileTarget'];
+ }
+ }
}
$sharingEnabled = \OCP\Share::isEnabled();
@@ -216,23 +328,7 @@ class Hooks {
foreach ($allFiles as $path) {
$usersSharing = $util->getSharingUsersArray($sharingEnabled, $path);
-
- $failed = array();
-
- // Attempt to set shareKey
- if (!$util->setSharedFileKeyfiles($session, $usersSharing, $path)) {
-
- $failed[] = $path;
- }
- }
-
- // If no attempts to set keyfiles failed
- if (empty($failed)) {
-
- return true;
- } else {
-
- return false;
+ $util->setSharedFileKeyfiles( $session, $usersSharing, $path );
}
}
}
@@ -241,51 +337,89 @@ class Hooks {
* @brief
*/
public static function postUnshare( $params ) {
-
+
// NOTE: $params has keys:
// [itemType] => file
// [itemSource] => 13
// [shareType] => 0
// [shareWith] => test1
-
- if ( $params['itemType'] === 'file' || $params['itemType'] === 'folder' ) {
-
+ // [itemParent] =>
+
+ if ( $params['itemType'] === 'file' || $params['itemType'] === 'folder' ) {
+
$view = new \OC_FilesystemView( '/' );
- $session = new Session($view);
$userId = \OCP\User::getUser();
- $util = new Util( $view, $userId );
+ $util = new Util( $view, $userId);
$path = $util->fileIdToPath( $params['itemSource'] );
+ // check if this is a re-share
+ if ( $params['itemParent'] ) {
+
+ // get the parent from current share
+ $parent = $util->getShareParent( $params['itemParent'] );
+
+ // get target path
+ $targetPath = $util->fileIdToPath( $params['itemSource'] );
+ $targetPathSplit = array_reverse( explode( '/', $targetPath ) );
+
+ // init values
+ $path = '';
+ $sharedPart = ltrim( $parent['file_target'], '/' );
+
+ // rebuild path
+ foreach ( $targetPathSplit as $pathPart ) {
+
+ if ( $pathPart !== $sharedPart ) {
+
+ $path = '/' . $pathPart . $path;
+
+ } else {
+
+ break;
+
+ }
+
+ }
+
+ // prefix path with Shared
+ $path = '/Shared' . $parent['file_target'] . $path;
+ }
+
// for group shares get a list of the group members
- if ($params['shareType'] == \OCP\Share::SHARE_TYPE_GROUP) {
+ if ( $params['shareType'] == \OCP\Share::SHARE_TYPE_GROUP ) {
$userIds = \OC_Group::usersInGroup($params['shareWith']);
+ } else if ( $params['shareType'] == \OCP\Share::SHARE_TYPE_LINK ){
+ $userIds = array( $util->getPublicShareKeyId() );
} else {
- $userIds = array($params['shareWith']);
+ $userIds = array( $params['shareWith'] );
}
// if we unshare a folder we need a list of all (sub-)files
- if ($params['itemType'] === 'folder') {
- $allFiles = $util->getAllFiles($path);
+ if ( $params['itemType'] === 'folder' ) {
+
+ $allFiles = $util->getAllFiles( $path );
+
} else {
- $allFiles = array($path);
+
+ $allFiles = array( $path );
}
-
foreach ( $allFiles as $path ) {
// check if the user still has access to the file, otherwise delete share key
- $sharingUsers = $util->getSharingUsersArray(true, $path);
+ $sharingUsers = $util->getSharingUsersArray( true, $path );
// Unshare every user who no longer has access to the file
- $delUsers = array_diff($userIds, $sharingUsers);
- if ( ! Keymanager::delShareKey( $view, $delUsers, $path ) ) {
+ $delUsers = array_diff( $userIds, $sharingUsers);
+
+ if ( !Keymanager::delShareKey( $view, $delUsers, $path ) ) {
$failed[] = $path;
-
- }
+ }
+
}
-
+
// If no attempts to set keyfiles failed
if ( empty( $failed ) ) {
@@ -296,19 +430,99 @@ class Hooks {
return false;
}
-
}
-
}
/**
* @brief
*/
public static function postUnshareAll( $params ) {
-
+
// NOTE: It appears that this is never called for files, so
// we may not need to implement it
}
-
+
+
+ /**
+ * @brief after a file is renamed, rename its keyfile and share-keys also fix the file size and fix also the sharing
+ * @param array with oldpath and newpath
+ *
+ * This function is connected to the rename signal of OC_Filesystem and adjust the name and location
+ * of the stored versions along the actual file
+ */
+ public static function postRename($params) {
+ // Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ $view = new \OC_FilesystemView('/');
+ $session = new Session($view);
+ $userId = \OCP\User::getUser();
+ $util = new Util( $view, $userId );
+
+ // Format paths to be relative to user files dir
+ $oldKeyfilePath = \OC\Files\Filesystem::normalizePath($userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $params['oldpath']);
+ $newKeyfilePath = \OC\Files\Filesystem::normalizePath($userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $params['newpath']);
+
+ // add key ext if this is not an folder
+ if (!$view->is_dir($oldKeyfilePath)) {
+ $oldKeyfilePath .= '.key';
+ $newKeyfilePath .= '.key';
+
+ // handle share-keys
+ $localKeyPath = $view->getLocalFile($userId.'/files_encryption/share-keys/'.$params['oldpath']);
+ $matches = glob(preg_quote($localKeyPath).'*.shareKey');
+ foreach ($matches as $src) {
+ $dst = \OC\Files\Filesystem::normalizePath(str_replace($params['oldpath'], $params['newpath'], $src));
+
+ // create destination folder if not exists
+ if(!file_exists(dirname($dst))) {
+ mkdir(dirname($dst), 0750, true);
+ }
+
+ rename($src, $dst);
+ }
+
+ } else {
+ // handle share-keys folders
+ $oldShareKeyfilePath = \OC\Files\Filesystem::normalizePath($userId . '/' . 'files_encryption' . '/' . 'share-keys' . '/' . $params['oldpath']);
+ $newShareKeyfilePath = \OC\Files\Filesystem::normalizePath($userId . '/' . 'files_encryption' . '/' . 'share-keys' . '/' . $params['newpath']);
+
+ // create destination folder if not exists
+ if(!$view->file_exists(dirname($newShareKeyfilePath))) {
+ $view->mkdir(dirname($newShareKeyfilePath), 0750, true);
+ }
+
+ $view->rename($oldShareKeyfilePath, $newShareKeyfilePath);
+ }
+
+ // Rename keyfile so it isn't orphaned
+ if($view->file_exists($oldKeyfilePath)) {
+
+ // create destination folder if not exists
+ if(!$view->file_exists(dirname($newKeyfilePath))) {
+ $view->mkdir(dirname($newKeyfilePath), 0750, true);
+ }
+
+ $view->rename($oldKeyfilePath, $newKeyfilePath);
+ }
+
+ // build the path to the file
+ $newPath = '/' . $userId . '/files' .$params['newpath'];
+ $newPathRelative = $params['newpath'];
+
+ if($util->fixFileSize($newPath)) {
+ // get sharing app state
+ $sharingEnabled = \OCP\Share::isEnabled();
+
+ // get users
+ $usersSharing = $util->getSharingUsersArray($sharingEnabled, $newPathRelative);
+
+ // update sharing-keys
+ $util->setSharedFileKeyfiles($session, $usersSharing, $newPathRelative);
+ }
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+ }
}
diff --git a/apps/files_encryption/js/settings-admin.js b/apps/files_encryption/js/settings-admin.js
new file mode 100644
index 00000000000..9cdb7aca68a
--- /dev/null
+++ b/apps/files_encryption/js/settings-admin.js
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2013, Sam Tuke <samtuke@owncloud.com>, Robin Appelman
+ * <icewind1991@gmail.com>
+ * This file is licensed under the Affero General Public License version 3 or later.
+ * See the COPYING-README file.
+ */
+
+
+$(document).ready(function(){
+ // Trigger ajax on recoveryAdmin status change
+ $( 'input:radio[name="adminEnableRecovery"]' ).change(
+ function() {
+
+ var recoveryStatus = $( this ).val();
+ var recoveryPassword = $( '#recoveryPassword' ).val();
+
+ if ( '' == recoveryPassword ) {
+
+ // FIXME: add proper OC notification
+ alert( 'You must set a recovery account password first' );
+
+ } else {
+
+ $.post(
+ OC.filePath( 'files_encryption', 'ajax', 'adminrecovery.php' )
+ , { adminEnableRecovery: recoveryStatus, recoveryPassword: recoveryPassword }
+ , function( data ) {
+ alert( data );
+ }
+ );
+
+ }
+ }
+ );
+
+ function blackListChange(){
+ var blackList=$( '#encryption_blacklist' ).val().join( ',' );
+ OC.AppConfig.setValue( 'files_encryption', 'type_blacklist', blackList );
+ }
+}) \ No newline at end of file
diff --git a/apps/files_encryption/js/settings-personal.js b/apps/files_encryption/js/settings-personal.js
new file mode 100644
index 00000000000..3b9b00dc797
--- /dev/null
+++ b/apps/files_encryption/js/settings-personal.js
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2013, Sam Tuke <samtuke@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or later.
+ * See the COPYING-README file.
+ */
+
+$(document).ready(function(){
+ // Trigger ajax on recoveryAdmin status change
+ $( 'input:radio[name="userEnableRecovery"]' ).change(
+ function() {
+
+ // Hide feedback messages in case they're already visible
+ $('#recoveryEnabledSuccess').hide();
+ $('#recoveryEnabledError').hide();
+
+ var recoveryStatus = $( this ).val();
+
+ $.post(
+ OC.filePath( 'files_encryption', 'ajax', 'userrecovery.php' )
+ , { userEnableRecovery: recoveryStatus }
+ , function( data ) {
+ if ( data.status == "success" ) {
+ $('#recoveryEnabledSuccess').show();
+ } else {
+ $('#recoveryEnabledError').show();
+ }
+ }
+ );
+ // Ensure page is not reloaded on form submit
+ return false;
+ }
+ );
+
+ $("#encryptAll").click(
+ function(){
+
+ // Hide feedback messages in case they're already visible
+ $('#encryptAllSuccess').hide();
+ $('#encryptAllError').hide();
+
+ var userPassword = $( '#userPassword' ).val();
+ var encryptAll = $( '#encryptAll' ).val();
+
+ $.post(
+ OC.filePath( 'files_encryption', 'ajax', 'encryptall.php' )
+ , { encryptAll: encryptAll, userPassword: userPassword }
+ , function( data ) {
+ if ( data.status == "success" ) {
+ $('#encryptAllSuccess').show();
+ } else {
+ $('#encryptAllError').show();
+ }
+ }
+ );
+ // Ensure page is not reloaded on form submit
+ return false;
+ }
+
+ );
+}) \ No newline at end of file
diff --git a/apps/files_encryption/js/settings.js b/apps/files_encryption/js/settings.js
deleted file mode 100644
index 9a0bebf2478..00000000000
--- a/apps/files_encryption/js/settings.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * Copyright (c) 2011, Robin Appelman <icewind1991@gmail.com>
- * This file is licensed under the Affero General Public License version 3 or later.
- * See the COPYING-README file.
- */
-
-
-$(document).ready(function(){
- // Trigger ajax on filetype blacklist change
- $('#encryption_blacklist').multiSelect({
- oncheck:blackListChange,
- onuncheck:blackListChange,
- createText:'...'
- });
-
- // Trigger ajax on recoveryAdmin status change
- $( 'input:radio[name="adminEnableRecovery"]' ).change(
- function() {
-
- var foo = $( this ).val();
-
- $.post(
- OC.filePath('files_encryption', 'ajax', 'adminrecovery.php')
- , { adminEnableRecovery: foo, recoveryPassword: 'password' }
- , function( data ) {
- alert( data );
- }
- );
- }
- );
-
- function blackListChange(){
- var blackList=$('#encryption_blacklist').val().join(',');
- OC.AppConfig.setValue('files_encryption','type_blacklist',blackList);
- }
-}) \ No newline at end of file
diff --git a/apps/files_encryption/l10n/de.php b/apps/files_encryption/l10n/de.php
index bcf0ca5ad63..cdcd8a40b23 100644
--- a/apps/files_encryption/l10n/de.php
+++ b/apps/files_encryption/l10n/de.php
@@ -3,5 +3,5 @@
"File encryption is enabled." => "Dateiverschlüsselung ist aktiviert",
"The following file types will not be encrypted:" => "Die folgenden Dateitypen werden nicht verschlüsselt:",
"Exclude the following file types from encryption:" => "Schließe die folgenden Dateitypen von der Verschlüsselung aus:",
-"None" => "Nichts"
+"None" => "Keine"
);
diff --git a/apps/files_encryption/l10n/de_DE.php b/apps/files_encryption/l10n/de_DE.php
index 71fd7d96711..4f08b98eb29 100644
--- a/apps/files_encryption/l10n/de_DE.php
+++ b/apps/files_encryption/l10n/de_DE.php
@@ -3,5 +3,5 @@
"File encryption is enabled." => "Datei-Verschlüsselung ist aktiviert",
"The following file types will not be encrypted:" => "Die folgenden Dateitypen werden nicht verschlüsselt:",
"Exclude the following file types from encryption:" => "Die folgenden Dateitypen von der Verschlüsselung ausnehmen:",
-"None" => "Nichts"
+"None" => "Keine"
);
diff --git a/apps/files_encryption/l10n/el.php b/apps/files_encryption/l10n/el.php
index 82a4c92ec28..0031a731944 100644
--- a/apps/files_encryption/l10n/el.php
+++ b/apps/files_encryption/l10n/el.php
@@ -3,5 +3,5 @@
"File encryption is enabled." => "Η κρυπτογράφηση αρχείων είναι ενεργή.",
"The following file types will not be encrypted:" => "Οι παρακάτω τύποι αρχείων δεν θα κρυπτογραφηθούν:",
"Exclude the following file types from encryption:" => "Εξαίρεση των παρακάτω τύπων αρχείων από την κρυπτογράφηση:",
-"None" => "Τίποτα"
+"None" => "Καμία"
);
diff --git a/apps/files_encryption/l10n/eu.php b/apps/files_encryption/l10n/eu.php
index 7e3b7611ff2..5a22b65728e 100644
--- a/apps/files_encryption/l10n/eu.php
+++ b/apps/files_encryption/l10n/eu.php
@@ -3,5 +3,5 @@
"File encryption is enabled." => "Fitxategien enkriptazioa gaituta dago.",
"The following file types will not be encrypted:" => "Hurrengo fitxategi motak ez dira enkriptatuko:",
"Exclude the following file types from encryption:" => "Baztertu hurrengo fitxategi motak enkriptatzetik:",
-"None" => "Ezer"
+"None" => "Bat ere ez"
);
diff --git a/apps/files_encryption/l10n/it.php b/apps/files_encryption/l10n/it.php
index c7171345269..9ab9bc492a0 100644
--- a/apps/files_encryption/l10n/it.php
+++ b/apps/files_encryption/l10n/it.php
@@ -3,5 +3,5 @@
"File encryption is enabled." => "La cifratura dei file è abilitata.",
"The following file types will not be encrypted:" => "I seguenti tipi di file non saranno cifrati:",
"Exclude the following file types from encryption:" => "Escludi i seguenti tipi di file dalla cifratura:",
-"None" => "Nessuno"
+"None" => "Nessuna"
);
diff --git a/apps/files_encryption/l10n/pl.php b/apps/files_encryption/l10n/pl.php
index 836f5453596..2fa86f454f9 100644
--- a/apps/files_encryption/l10n/pl.php
+++ b/apps/files_encryption/l10n/pl.php
@@ -3,5 +3,5 @@
"File encryption is enabled." => "Szyfrowanie plików jest włączone",
"The following file types will not be encrypted:" => "Poniższe typy plików nie będą szyfrowane:",
"Exclude the following file types from encryption:" => "Wyłącz poniższe typy plików z szyfrowania:",
-"None" => "Nic"
+"None" => "Brak"
);
diff --git a/apps/files_encryption/l10n/pt_BR.php b/apps/files_encryption/l10n/pt_BR.php
index b41c6ed3153..28807db72ce 100644
--- a/apps/files_encryption/l10n/pt_BR.php
+++ b/apps/files_encryption/l10n/pt_BR.php
@@ -3,5 +3,5 @@
"File encryption is enabled." => "A criptografia de arquivos está ativada.",
"The following file types will not be encrypted:" => "Os seguintes tipos de arquivo não serão criptografados:",
"Exclude the following file types from encryption:" => "Excluir os seguintes tipos de arquivo da criptografia:",
-"None" => "Nada"
+"None" => "Nenhuma"
);
diff --git a/apps/files_encryption/l10n/ru.php b/apps/files_encryption/l10n/ru.php
index f07dec621d7..22c1e3da374 100644
--- a/apps/files_encryption/l10n/ru.php
+++ b/apps/files_encryption/l10n/ru.php
@@ -3,5 +3,5 @@
"File encryption is enabled." => "Шифрование файла включено.",
"The following file types will not be encrypted:" => "Следующие типы файлов не будут зашифрованы:",
"Exclude the following file types from encryption:" => "Исключить следующие типы файлов из шифрованных:",
-"None" => "Нет новостей"
+"None" => "Ничего"
);
diff --git a/apps/files_encryption/l10n/sk_SK.php b/apps/files_encryption/l10n/sk_SK.php
index aaea9da21b4..bebb6234710 100644
--- a/apps/files_encryption/l10n/sk_SK.php
+++ b/apps/files_encryption/l10n/sk_SK.php
@@ -3,5 +3,5 @@
"File encryption is enabled." => "Šifrovanie súborov nastavené.",
"The following file types will not be encrypted:" => "Uvedené typy súborov nebudú šifrované:",
"Exclude the following file types from encryption:" => "Nešifrovať uvedené typy súborov",
-"None" => "Žiadny"
+"None" => "Žiadne"
);
diff --git a/apps/files_encryption/l10n/th_TH.php b/apps/files_encryption/l10n/th_TH.php
index 30c0324a988..e46d2491186 100644
--- a/apps/files_encryption/l10n/th_TH.php
+++ b/apps/files_encryption/l10n/th_TH.php
@@ -1,4 +1,4 @@
<?php $TRANSLATIONS = array(
"Encryption" => "การเข้ารหัส",
-"None" => "ไม่มี"
+"None" => "ไม่ต้อง"
);
diff --git a/apps/files_encryption/l10n/vi.php b/apps/files_encryption/l10n/vi.php
index 40d4b1d0fec..0a88d1b2db6 100644
--- a/apps/files_encryption/l10n/vi.php
+++ b/apps/files_encryption/l10n/vi.php
@@ -3,5 +3,5 @@
"File encryption is enabled." => "Mã hóa file đã mở",
"The following file types will not be encrypted:" => "Loại file sau sẽ không được mã hóa",
"Exclude the following file types from encryption:" => "Việc mã hóa không bao gồm loại file sau",
-"None" => "Không gì cả"
+"None" => "Không có gì hết"
);
diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php
new file mode 100755
index 00000000000..783cebeee5b
--- /dev/null
+++ b/apps/files_encryption/lib/helper.php
@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * ownCloud
+ *
+ * @author Florin Peter
+ * @copyright 2013 Florin Peter <owncloud@florin-peter.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library 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 along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Encryption;
+
+/**
+ * @brief Class to manage registration of hooks an various helper methods
+ */
+class Helper {
+
+ /**
+ * @brief register share related hooks
+ *
+ */
+ public static function registerShareHooks() {
+
+ \OCP\Util::connectHook( 'OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared' );
+ \OCP\Util::connectHook( 'OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared' );
+ \OCP\Util::connectHook( 'OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare' );
+ \OCP\Util::connectHook( 'OCP\Share', 'post_unshareAll', 'OCA\Encryption\Hooks', 'postUnshareAll' );
+ }
+
+ /**
+ * @brief register user related hooks
+ *
+ */
+ public static function registerUserHooks() {
+
+ \OCP\Util::connectHook( 'OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login' );
+ \OCP\Util::connectHook( 'OC_User', 'pre_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase' );
+ \OCP\Util::connectHook( 'OC_User', 'post_createUser', 'OCA\Encryption\Hooks', 'postCreateUser' );
+ \OCP\Util::connectHook( 'OC_User', 'post_deleteUser', 'OCA\Encryption\Hooks', 'postDeleteUser' );
+ }
+
+ /**
+ * @brief register webdav related hooks
+ *
+ */
+ public static function registerWebdavHooks() {
+
+ \OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfileFromClient' );
+ }
+
+ /**
+ * @brief register filesystem related hooks
+ *
+ */
+ public static function registerFilesystemHooks() {
+
+ \OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename');
+ }
+
+ /**
+ * @brief setup user for files_encryption
+ *
+ * @param Util $util
+ * @param string $password
+ * @return bool
+ */
+ public static function setupUser($util, $password) {
+ // Check files_encryption infrastructure is ready for action
+ if ( ! $util->ready() ) {
+
+ \OC_Log::write( 'Encryption library', 'User account "' . $util->getUserId() . '" is not ready for encryption; configuration started', \OC_Log::DEBUG );
+
+ if(!$util->setupServerSide( $password )) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+} \ No newline at end of file
diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php
index cfc13ee132d..74462a0d1ed 100755
--- a/apps/files_encryption/lib/keymanager.php
+++ b/apps/files_encryption/lib/keymanager.php
@@ -32,15 +32,20 @@ class Keymanager {
/**
* @brief retrieve the ENCRYPTED private key from a user
*
- * @return string private key or false
+ * @return string private key or false (hopefully)
* @note the key returned by this method must be decrypted before use
*/
public static function getPrivateKey( \OC_FilesystemView $view, $user ) {
$path = '/' . $user . '/' . 'files_encryption' . '/' . $user.'.private.key';
-
+
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
$key = $view->file_get_contents( $path );
-
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
return $key;
}
@@ -113,8 +118,8 @@ class Keymanager {
\OC_FileProxy::$enabled = false;
//here we need the currently logged in user, while userId can be a different user
- $util = new Util($view, \OCP\User::getUser());
- list($owner, $filename) = $util->getUidAndFilename($path);
+ $util = new Util( $view, \OCP\User::getUser() );
+ list( $owner, $filename ) = $util->getUidAndFilename( $path );
$basePath = '/' . $owner . '/files_encryption/keyfiles';
@@ -123,22 +128,74 @@ class Keymanager {
if ( !$view->is_dir( $basePath . '/' . $targetPath ) ) {
// create all parent folders
- $info=pathinfo($basePath . '/' . $targetPath);
- $keyfileFolderName=$view->getLocalFolder($info['dirname']);
- if(!file_exists($keyfileFolderName)) {
- mkdir($keyfileFolderName, 0750, true);
+ $info = pathinfo( $basePath . '/' . $targetPath );
+ $keyfileFolderName = $view->getLocalFolder( $info['dirname'] );
+
+ if ( ! file_exists( $keyfileFolderName ) ) {
+
+ mkdir( $keyfileFolderName, 0750, true );
+
}
}
+
+ // try reusing key file if part file
+ if ( self::isPartialFilePath( $targetPath ) ) {
- $result = $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile );
+ $result = $view->file_put_contents( $basePath . '/' . self::fixPartialFilePath( $targetPath ) . '.key', $catfile );
+
+ } else {
+ $result = $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile );
+
+ }
\OC_FileProxy::$enabled = $proxyStatus;
return $result;
}
+
+ /**
+ * @brief Remove .path extension from a file path
+ * @param string $path Path that may identify a .part file
+ * @return string File path without .part extension
+ * @note this is needed for reusing keys
+ */
+ public static function fixPartialFilePath( $path ) {
+ if (preg_match('/\.part$/', $path)) {
+
+ $newLength = strlen($path) - 5;
+ $fPath = substr($path, 0, $newLength);
+
+ return $fPath;
+
+ } else {
+
+ return $path;
+
+ }
+
+ }
+
+ /**
+ * @brief Check if a path is a .part file
+ * @param string $path Path that may identify a .part file
+ * @return bool
+ */
+ public static function isPartialFilePath( $path ) {
+
+ if ( preg_match('/\.part$/', $path ) ) {
+
+ return true;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
/**
* @brief retrieve keyfile for an encrypted file
* @param \OC_FilesystemView $view
@@ -150,14 +207,27 @@ class Keymanager {
* of the keyfile must be performed by client code
*/
public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) {
+
+ // try reusing key file if part file
+ if ( self::isPartialFilePath( $filePath ) ) {
+
+ $result = self::getFileKey( $view, $userId, self::fixPartialFilePath( $filePath ) );
+ if ( $result ) {
+
+ return $result;
+
+ }
+
+ }
+
$util = new Util($view, \OCP\User::getUser());
list($owner, $filename) = $util->getUidAndFilename($filePath);
$filePath_f = ltrim( $filename, '/' );
-
+
$keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key';
- $proxyStatus = \OC_FileProxy::$enabled;
+ $proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
if ( $view->file_exists( $keyfilePath ) ) {
@@ -226,7 +296,7 @@ class Keymanager {
$view = new \OC_FilesystemView( '/' . $user . '/files_encryption' );
- $proxyStatus = \OC_FileProxy::$enabled;
+ $proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
if ( !$view->file_exists( '' ) ) $view->mkdir( '' );
@@ -235,7 +305,8 @@ class Keymanager {
\OC_FileProxy::$enabled = $proxyStatus;
- return $result;
+ return $result;
+
}
/**
@@ -261,7 +332,7 @@ class Keymanager {
$view = new \OC_FilesystemView( '/public-keys' );
- $proxyStatus = \OC_FileProxy::$enabled;
+ $proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
if ( !$view->file_exists( '' ) ) $view->mkdir( '' );
@@ -270,7 +341,7 @@ class Keymanager {
\OC_FileProxy::$enabled = $proxyStatus;
- return $result;
+ return $result;
}
@@ -287,23 +358,32 @@ class Keymanager {
*/
public static function setShareKey( \OC_FilesystemView $view, $path, $userId, $shareKey ) {
- //here we need the currently logged in user, while userId can be a different user
+ // Here we need the currently logged in user, while userId can be a different user
$util = new Util( $view, \OCP\User::getUser() );
- list($owner, $filename) = $util->getUidAndFilename($path);
+ list( $owner, $filename ) = $util->getUidAndFilename( $path );
$basePath = '/' . $owner . '/files_encryption/share-keys';
$shareKeyPath = self::keySetPreparation( $view, $filename, $basePath, $owner );
+
+ // try reusing key file if part file
+ if(self::isPartialFilePath($shareKeyPath)) {
+
+ $writePath = $basePath . '/' . self::fixPartialFilePath($shareKeyPath) . '.' . $userId . '.shareKey';
+
+ } else {
- $writePath = $basePath . '/' . $shareKeyPath . '.' . $userId . '.shareKey';
+ $writePath = $basePath . '/' . $shareKeyPath . '.' . $userId . '.shareKey';
+
+ }
- $proxyStatus = \OC_FileProxy::$enabled;
+ $proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$result = $view->file_put_contents( $writePath, $shareKey );
- \OC_FileProxy::$enabled = $proxyStatus;
+ \OC_FileProxy::$enabled = $proxyStatus;
if (
is_int( $result )
@@ -359,7 +439,20 @@ class Keymanager {
*/
public static function getShareKey( \OC_FilesystemView $view, $userId, $filePath ) {
- $proxyStatus = \OC_FileProxy::$enabled;
+ // try reusing key file if part file
+ if(self::isPartialFilePath($filePath)) {
+
+ $result = self::getShareKey($view, $userId, self::fixPartialFilePath($filePath));
+
+ if($result) {
+
+ return $result;
+
+ }
+
+ }
+
+ $proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
//here we need the currently logged in user, while userId can be a different user
@@ -367,7 +460,7 @@ class Keymanager {
list($owner, $filename) = $util->getUidAndFilename($filePath);
- $shareKeyPath = '/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey';
+ $shareKeyPath = \OC\Files\Filesystem::normalizePath('/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey');
if ( $view->file_exists( $shareKeyPath ) ) {
$result = $view->file_get_contents( $shareKeyPath );
diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php
index 73f72a9e23e..36d05d7e0fe 100644
--- a/apps/files_encryption/lib/proxy.php
+++ b/apps/files_encryption/lib/proxy.php
@@ -93,29 +93,29 @@ class Proxy extends \OC_FileProxy {
public function preFile_put_contents( $path, &$data ) {
- if ( self::shouldEncrypt( $path ) ) {
+ if ( self::shouldEncrypt( $path ) ) {
- // Stream put contents should have been converted to fopen
+ // Stream put contents should have been converted to fopen
if ( !is_resource( $data ) ) {
- $userId = \OCP\USER::getUser();
- $rootView = new \OC_FilesystemView( '/' );
- $util = new Util( $rootView, $userId );
- $session = new Session( $rootView );
+ $userId = \OCP\USER::getUser();
+ $view = new \OC_FilesystemView( '/' );
+ $util = new Util( $view, $userId );
+ $session = new Session( $view );
$privateKey = $session->getPrivateKey();
$filePath = $util->stripUserFilesPath( $path );
// Set the filesize for userland, before encrypting
$size = strlen( $data );
-
+
// Disable encryption proxy to prevent recursive calls
- $proxyStatus = \OC_FileProxy::$enabled;
- \OC_FileProxy::$enabled = false;
-
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
// Check if there is an existing key we can reuse
- if ( $encKeyfile = Keymanager::getFileKey( $rootView, $userId, $filePath ) ) {
+ if ( $encKeyfile = Keymanager::getFileKey( $view, $userId, $filePath ) ) {
// Fetch shareKey
- $shareKey = Keymanager::getShareKey( $rootView, $userId, $filePath );
+ $shareKey = Keymanager::getShareKey( $view, $userId, $filePath );
// Decrypt the keyfile
$plainKey = Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey );
@@ -124,7 +124,7 @@ class Proxy extends \OC_FileProxy {
// Make a new key
$plainKey = Crypt::generateKey();
-
+
}
// Encrypt data
@@ -134,36 +134,37 @@ class Proxy extends \OC_FileProxy {
$uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $filePath, $userId );
- // Fetch public keys for all users who will share the file
- $publicKeys = Keymanager::getPublicKeys( $rootView, $uniqueUserIds );
+ // Fetch public keys for all users who will share the file
+ $publicKeys = Keymanager::getPublicKeys( $view, $uniqueUserIds );
- // Encrypt plain keyfile to multiple sharefiles
+ // Encrypt plain keyfile to multiple sharefiles
$multiEncrypted = Crypt::multiKeyEncrypt( $plainKey, $publicKeys );
// Save sharekeys to user folders
- Keymanager::setShareKeys( $rootView, $filePath, $multiEncrypted['keys'] );
+ Keymanager::setShareKeys( $view, $filePath, $multiEncrypted['keys'] );
// Set encrypted keyfile as common varname
$encKey = $multiEncrypted['data'];
// Save keyfile for newly encrypted file in parallel directory tree
- Keymanager::setFileKey( $rootView, $filePath, $userId, $encKey );
+ Keymanager::setFileKey( $view, $filePath, $userId, $encKey );
// Replace plain content with encrypted content by reference
$data = $encData;
-
+
// Update the file cache with file info
- \OC\Files\Filesystem::putFileInfo( $path, array( 'encrypted'=>true, 'size' => $size ), '' );
-
+ \OC\Files\Filesystem::putFileInfo( $filePath, array( 'encrypted'=>true, 'size' => strlen($size), 'unencrypted_size' => $size), '' );
+
// Re-enable proxy - our work is done
\OC_FileProxy::$enabled = $proxyStatus;
}
}
- return true;
+ return true;
+
}
-
+
/**
* @param string $path Path of file from which has been read
* @param string $data Data that has been read from file
@@ -273,136 +274,22 @@ class Proxy extends \OC_FileProxy {
}
/**
- * @brief When a file is renamed, rename its keyfile also
- * @return bool Result of rename()
- * @note This is pre rather than post because using post didn't work
- */
- public function preRename( $oldPath, $newPath )
- {
-
- // Disable encryption proxy to prevent recursive calls
- $proxyStatus = \OC_FileProxy::$enabled;
- \OC_FileProxy::$enabled = false;
-
- $view = new \OC_FilesystemView('/');
-
- $userId = \OCP\USER::getUser();
-
- // Format paths to be relative to user files dir
- $oldTrimmed = ltrim($oldPath, '/');
- $oldSplit = explode('/', $oldTrimmed);
- $oldSliced = array_slice($oldSplit, 2);
- $oldRelPath = implode('/', $oldSliced);
- $oldKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $oldRelPath;
-
- $newTrimmed = ltrim($newPath, '/');
- $newSplit = explode('/', $newTrimmed);
- $newSliced = array_slice($newSplit, 2);
- $newRelPath = implode('/', $newSliced);
- $newKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $newRelPath;
-
- // add key ext if this is not an folder
- if (!$view->is_dir($oldKeyfilePath)) {
- $oldKeyfilePath .= '.key';
- $newKeyfilePath .= '.key';
-
- // handle share-keys
- $localKeyPath = $view->getLocalFile($userId.'/files_encryption/share-keys/'.$oldRelPath);
- $matches = glob(preg_quote($localKeyPath).'*.shareKey');
- foreach ($matches as $src) {
- $dst = str_replace($oldRelPath, $newRelPath, $src);
- rename($src, $dst);
- }
-
- } else {
- // handle share-keys folders
- $oldShareKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'share-keys' . '/' . $oldRelPath;
- $newShareKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'share-keys' . '/' . $newRelPath;
- $view->rename($oldShareKeyfilePath, $newShareKeyfilePath);
- }
-
- // Rename keyfile so it isn't orphaned
- $result = $view->rename($oldKeyfilePath, $newKeyfilePath);
-
- \OC_FileProxy::$enabled = $proxyStatus;
-
- return $result;
-
- }
-
- /**
* @brief When a file is renamed, rename its keyfile also
* @return bool Result of rename()
* @note This is pre rather than post because using post didn't work
*/
- public function postRename( $oldPath, $newPath )
+ public function postWrite( $path )
{
+ $this->handleFile($path);
- // Disable encryption proxy to prevent recursive calls
- $proxyStatus = \OC_FileProxy::$enabled;
- \OC_FileProxy::$enabled = false;
-
- $view = new \OC_FilesystemView('/');
- $session = new Session($view);
- $userId = \OCP\User::getUser();
- $util = new Util( $view, $userId );
-
- // Reformat path for use with OC_FSV
- $newPathSplit = explode( '/', $newPath );
- $newPathRelative = implode( '/', array_slice( $newPathSplit, 3 ) );
-
- // get file info from database/cache
- //$newFileInfo = \OC\Files\Filesystem::getFileInfo($newPathRelative);
-
- if ($util->isEncryptedPath($newPath)) {
- $cached = $view->getFileInfo($newPath);
- $cached['encrypted'] = 1;
-
- // get the size from filesystem
- $size = $view->filesize($newPath);
-
- // calculate last chunk nr
- $lastChunckNr = floor($size / 8192);
-
- // open stream
- $result = fopen('crypt://' . $newPathRelative, "r");
-
- if(is_resource($result)) {
- // calculate last chunk position
- $lastChunckPos = ($lastChunckNr * 8192);
-
- // seek to end
- fseek($result, $lastChunckPos);
-
- // get the content of the last chunck
- $lastChunkContent = fread($result, 8192);
-
- // calc the real file size with the size of the last chunk
- $realSize = (($lastChunckNr * 6126) + strlen($lastChunkContent));
-
- // set the size
- $cached['unencrypted_size'] = $realSize;
- }
-
- $view->putFileInfo( $newPath, $cached );
-
- // get sharing app state
- $sharingEnabled = \OCP\Share::isEnabled();
-
- // get users
- $usersSharing = $util->getSharingUsersArray($sharingEnabled, $newPathRelative);
-
- // update sharing-keys
- $util->setSharedFileKeyfiles($session, $usersSharing, $newPathRelative);
- }
-
-
-
+ return true;
+ }
- \OC_FileProxy::$enabled = $proxyStatus;
+ public function postTouch( $path )
+ {
+ $this->handleFile($path);
return true;
-
}
public function postFopen( $path, &$result ){
@@ -518,25 +405,28 @@ class Proxy extends \OC_FileProxy {
return $data;
}
- public function postStat( $path, $data ) {
+ public function postStat($path, $data)
+ {
+ // check if file is encrypted
+ if (Crypt::isCatfileContent($path)) {
+
+ // get file info from cache
+ $cached = \OC\Files\Filesystem::getFileInfo($path, '');
- if ( Crypt::isCatfileContent( $path ) ) {
-
- $cached = \OC\Files\Filesystem::getFileInfo( $path, '' );
-
- $data['size'] = $cached['unencrypted_size'];
-
- }
-
- return $data;
- }
+ // set the real file size
+ $data['size'] = $cached['unencrypted_size'];
+ }
- public function postFileSize( $path, $size ) {
+ return $data;
+ }
- $view = new \OC_FilesystemView( '/' );
+ public function postFileSize($path, $size)
+ {
+
+ $view = new \OC_FilesystemView('/');
// if path is a folder do nothing
- if($view->is_dir($path)) {
+ if ($view->is_dir($path)) {
return $size;
}
@@ -544,14 +434,65 @@ class Proxy extends \OC_FileProxy {
$path_split = explode('/', $path);
$path_f = implode('/', array_slice($path_split, 3));
+ // if path is empty we cannot resolve anything
+ if(empty($path_f)) {
+ return $size;
+ }
+
// get file info from database/cache
$fileInfo = \OC\Files\Filesystem::getFileInfo($path_f);
// if file is encrypted return real file size
- if(is_array($fileInfo) && $fileInfo['encrypted'] == 1) {
- return $fileInfo['unencrypted_size'];
+ if (is_array($fileInfo) && $fileInfo['encrypted'] === true) {
+ $size = $fileInfo['unencrypted_size'];
} else {
- return $size;
+ // self healing if file was removed from file cache
+ if(is_array($fileInfo)) {
+ $userId = \OCP\User::getUser();
+ $util = new Util( $view, $userId );
+ $fixSize = $util->getFileSize($path);
+ if($fixSize > 0) {
+ $size = $fixSize;
+
+ $fileInfo['encrypted'] = true;
+ $fileInfo['unencrypted_size'] = $size;
+
+ // put file info
+ $view->putFileInfo( $path_f, $fileInfo );
+ }
+ }
}
- }
-}
+ return $size;
+ }
+
+ public function handleFile($path) {
+
+ // Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ $view = new \OC_FilesystemView('/');
+ $session = new Session($view);
+ $userId = \OCP\User::getUser();
+ $util = new Util( $view, $userId );
+
+ // Reformat path for use with OC_FSV
+ $path_split = explode( '/', $path );
+ $path_f = implode( '/', array_slice( $path_split, 3 ) );
+
+ // only if file is on 'files' folder fix file size and sharing
+ if($path_split[2] == 'files' && $util->fixFileSize($path)) {
+
+ // get sharing app state
+ $sharingEnabled = \OCP\Share::isEnabled();
+
+ // get users
+ $usersSharing = $util->getSharingUsersArray($sharingEnabled, $path_f);
+
+ // update sharing-keys
+ $util->setSharedFileKeyfiles($session, $usersSharing, $path_f);
+ }
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+ }
+ }
diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php
index 0c6a7131fd9..f02315f95df 100644
--- a/apps/files_encryption/lib/session.php
+++ b/apps/files_encryption/lib/session.php
@@ -35,43 +35,64 @@ class Session {
*
* The ownCloud key pair is used to allow public link sharing even if encryption is enabled
*/
- public function __construct( \OC_FilesystemView $view ) {
+ public function __construct( $view ) {
$this->view = $view;
if ( ! $this->view->is_dir( 'owncloud_private_key' ) ) {
- $this->view->mkdir('owncloud_private_key');
+ $this->view->mkdir( 'owncloud_private_key' );
+
+ }
+
+ $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId');
+
+ if ($publicShareKeyId === null) {
+ $publicShareKeyId = 'pubShare_'.substr(md5(time()),0,8);
+ \OC_Appconfig::setValue('files_encryption', 'publicShareKeyId', $publicShareKeyId);
}
-
if (
- ! $this->view->file_exists("/public-keys/owncloud.public.key")
- || ! $this->view->file_exists("/owncloud_private_key/owncloud.private.key" )
+ ! $this->view->file_exists( "/public-keys/".$publicShareKeyId.".public.key" )
+ || ! $this->view->file_exists( "/owncloud_private_key/".$publicShareKeyId.".private.key" )
) {
+
+ $keypair = Crypt::createKeypair();
- $keypair = Crypt::createKeypair();
-
- \OC_FileProxy::$enabled = false;
-
- // Save public key
+ // Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
- if (!$view->is_dir('/public-keys')) {
- $view->mkdir('/public-keys');
- }
-
- $this->view->file_put_contents( '/public-keys/owncloud.public.key', $keypair['publicKey'] );
-
- // Encrypt private key empthy passphrase
- $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], '' );
-
- // Save private key
- $this->view->file_put_contents( '/owncloud_private_key/owncloud.private.key', $encryptedPrivateKey );
+ // Save public key
+
+ if (!$view->is_dir('/public-keys')) {
+ $view->mkdir('/public-keys');
+ }
+
+ $this->view->file_put_contents( '/public-keys/'.$publicShareKeyId.'.public.key', $keypair['publicKey'] );
+
+ // Encrypt private key empthy passphrase
+ $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], '' );
+
+ // Save private key
+ $this->view->file_put_contents( '/owncloud_private_key/'.$publicShareKeyId.'.private.key', $encryptedPrivateKey );
- \OC_FileProxy::$enabled = true;
+ \OC_FileProxy::$enabled = $proxyStatus;
}
+
+ if(\OCP\USER::getUser() === false) {
+ // Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ $encryptedKey = $this->view->file_get_contents( '/owncloud_private_key/'.$publicShareKeyId.'.private.key' );
+ $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, '' );
+ $this->setPrivateKey($privateKey);
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+ }
}
/**
diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php
index 411bcdac92d..ab967835082 100644
--- a/apps/files_encryption/lib/stream.php
+++ b/apps/files_encryption/lib/stream.php
@@ -72,20 +72,20 @@ class Stream {
private $rootView; // a fsview object set to '/'
public function stream_open( $path, $mode, $options, &$opened_path ) {
-
- $this->userId = \OCP\User::getUser();
-
- if ( ! isset( $this->rootView ) ) {
+ if ( ! isset( $this->rootView ) ) {
$this->rootView = new \OC_FilesystemView( '/' );
-
}
- // Strip identifier text from path, this gives us the path relative to data/<user>/files
- $this->relPath = str_replace( 'crypt://', '', $path );
+ $util = new Util( $this->rootView, \OCP\USER::getUser());
+
+ $this->userId = $util->getUserId();
+
+ // Strip identifier text from path, this gives us the path relative to data/<user>/files
+ $this->relPath = \OC\Files\Filesystem::normalizePath(str_replace( 'crypt://', '', $path ));
// rawPath is relative to the data directory
- $this->rawPath = $this->userId . '/files/' . $this->relPath;
+ $this->rawPath = $util->getUserFilesDir() . $this->relPath;
if (
dirname( $this->rawPath ) == 'streams'
@@ -298,7 +298,8 @@ class Stream {
// automatically attempted when the file is written to disk -
// we are handling that separately here and we don't want to
// get into an infinite loop
- //\OC_FileProxy::$enabled = false;
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
// Get the length of the unencrypted data that we are handling
$length = strlen( $data );
@@ -322,30 +323,7 @@ class Stream {
}
- // Fetch user's public key
- $this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId );
-
- // Check if OC sharing api is enabled
- $sharingEnabled = \OCP\Share::isEnabled();
-
- $util = new Util( $this->rootView, $this->userId );
-
- // Get all users sharing the file includes current user
- $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $this->relPath, $this->userId);
-
- // Fetch public keys for all sharing users
- $publicKeys = Keymanager::getPublicKeys( $this->rootView, $uniqueUserIds );
- // Encrypt enc key for all sharing users
- $this->encKeyfiles = Crypt::multiKeyEncrypt( $this->plainKey, $publicKeys );
-
- $view = new \OC_FilesystemView( '/' );
-
- // Save the new encrypted file key
- Keymanager::setFileKey( $this->rootView, $this->relPath, $this->userId, $this->encKeyfiles['data'] );
-
- // Save the sharekeys
- Keymanager::setShareKeys( $view, $this->relPath, $this->encKeyfiles['keys'] );
// If extra data is left over from the last round, make sure it
// is integrated into the next 6126 / 8192 block
@@ -437,6 +415,8 @@ class Stream {
$this->size = max( $this->size, $pointer + $length );
$this->unencryptedSize += $length;
+ \OC_FileProxy::$enabled = $proxyStatus;
+
return $length;
}
@@ -492,14 +472,59 @@ class Stream {
}
public function stream_close() {
-
- $this->flush();
+
+ $this->flush();
if (
$this->meta['mode']!='r'
- and $this->meta['mode']!='rb'
+ and $this->meta['mode']!='rb'
+ and $this->size > 0
) {
- \OC\Files\Filesystem::putFileInfo( $this->relPath, array( 'encrypted' => 1, 'size' => $this->size, 'unencrypted_size' => $this->unencryptedSize ), '' );
+ // Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ // Fetch user's public key
+ $this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId );
+
+ // Check if OC sharing api is enabled
+ $sharingEnabled = \OCP\Share::isEnabled();
+
+ $util = new Util( $this->rootView, $this->userId );
+
+ // Get all users sharing the file includes current user
+ $uniqueUserIds = $util->getSharingUsersArray( $sharingEnabled, $this->relPath, $this->userId);
+
+ // Fetch public keys for all sharing users
+ $publicKeys = Keymanager::getPublicKeys( $this->rootView, $uniqueUserIds );
+
+ // Encrypt enc key for all sharing users
+ $this->encKeyfiles = Crypt::multiKeyEncrypt( $this->plainKey, $publicKeys );
+
+ $view = new \OC_FilesystemView( '/' );
+
+ // Save the new encrypted file key
+ Keymanager::setFileKey( $this->rootView, $this->relPath, $this->userId, $this->encKeyfiles['data'] );
+
+ // Save the sharekeys
+ Keymanager::setShareKeys( $view, $this->relPath, $this->encKeyfiles['keys'] );
+
+ // get file info
+ $fileInfo = $view->getFileInfo($this->rawPath);
+ if(!is_array($fileInfo)) {
+ $fileInfo = array();
+ }
+
+ // Re-enable proxy - our work is done
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ // set encryption data
+ $fileInfo['encrypted'] = true;
+ $fileInfo['size'] = $this->size;
+ $fileInfo['unencrypted_size'] = $this->unencryptedSize;
+
+ // set fileinfo
+ $view->putFileInfo( $this->rawPath, $fileInfo);
}
return fclose( $this->handle );
diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php
index 2198963ce14..19c9cd72a19 100644
--- a/apps/files_encryption/lib/util.php
+++ b/apps/files_encryption/lib/util.php
@@ -3,8 +3,8 @@
* ownCloud
*
* @author Sam Tuke, Frank Karlitschek
- * @copyright 2012 Sam Tuke samtuke@owncloud.com,
- * Frank Karlitschek frank@owncloud.org
+ * @copyright 2012 Sam Tuke <samtuke@owncloud.com>,
+ * Frank Karlitschek <frank@owncloud.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@@ -24,11 +24,8 @@
# Bugs
# ----
# Sharing a file to a user without encryption set up will not provide them with access but won't notify the sharer
-# Timeouts on first login due to encryption of very large files (fix in progress, as a result streaming is currently broken)
# Sharing all files to admin for recovery purposes still in progress
# Possibly public links are broken (not tested since last merge of master)
-# encryptAll during login mangles paths: /files/files/
-# encryptAll is accessing files via encryption proxy - perhaps proxies should be disabled?
# Missing features
@@ -91,20 +88,13 @@ class Util {
//// TODO: add support for optional recovery in case of lost passphrase / keys
//// TODO: add admin optional required long passphrase for users
- //// TODO: add UI buttons for encrypt / decrypt everything
//// TODO: implement flag system to allow user to specify encryption by folder, subfolder, etc.
- // Sharing:
-
- //// TODO: add support for encrypting to multiple public keys
- //// TODO: add support for decrypting to multiple private keys
-
-
// Integration testing:
//// TODO: test new encryption with versioning
- //// TODO: test new encryption with sharing
+ //// DONE: test new encryption with sharing
//// TODO: test new encryption with proxies
@@ -118,38 +108,65 @@ class Util {
private $shareKeysPath; // Dir containing env keys for shared files
private $publicKeyPath; // Path to user's public key
private $privateKeyPath; // Path to user's private key
+ private $publicShareKeyId;
+ private $recoveryKeyId;
+ private $isPublic;
public function __construct( \OC_FilesystemView $view, $userId, $client = false ) {
-
+
$this->view = $view;
$this->userId = $userId;
$this->client = $client;
- $this->userDir = '/' . $this->userId;
- $this->fileFolderName = 'files';
- $this->userFilesDir = '/' . $this->userId . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable?
- $this->publicKeyDir = '/' . 'public-keys';
- $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption';
- $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles';
- $this->shareKeysPath = $this->encryptionDir . '/' . 'share-keys';
- $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key
- $this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key
-
+ $this->isPublic = false;
+
+ $this->publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId');
+ $this->recoveryKeyId = \OC_Appconfig::getValue('files_encryption', 'recoveryKeyId');
+
+ // if we are anonymous/public
+ if($this->userId === false) {
+ $this->userId = $this->publicShareKeyId;
+
+ // only handle for files_sharing app
+ if($GLOBALS['app'] === 'files_sharing') {
+ $this->userDir = '/' . $GLOBALS['fileOwner'];
+ $this->fileFolderName = 'files';
+ $this->userFilesDir = '/' . $GLOBALS['fileOwner'] . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable?
+ $this->publicKeyDir = '/' . 'public-keys';
+ $this->encryptionDir = '/' . $GLOBALS['fileOwner'] . '/' . 'files_encryption';
+ $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles';
+ $this->shareKeysPath = $this->encryptionDir . '/' . 'share-keys';
+ $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key
+ $this->privateKeyPath = '/owncloud_private_key/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key
+ $this->isPublic = true;
+ }
+
+ } else {
+ $this->userDir = '/' . $this->userId;
+ $this->fileFolderName = 'files';
+ $this->userFilesDir = '/' . $this->userId . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable?
+ $this->publicKeyDir = '/' . 'public-keys';
+ $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption';
+ $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles';
+ $this->shareKeysPath = $this->encryptionDir . '/' . 'share-keys';
+ $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key
+ $this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key
+ }
}
public function ready() {
if(
- !$this->view->file_exists( $this->encryptionDir )
- or !$this->view->file_exists( $this->keyfilesPath )
- or !$this->view->file_exists( $this->shareKeysPath )
- or !$this->view->file_exists( $this->publicKeyPath )
- or !$this->view->file_exists( $this->privateKeyPath )
+ ! $this->view->file_exists( $this->encryptionDir )
+ or ! $this->view->file_exists( $this->keyfilesPath )
+ or ! $this->view->file_exists( $this->shareKeysPath )
+ or ! $this->view->file_exists( $this->publicKeyPath )
+ or ! $this->view->file_exists( $this->privateKeyPath )
) {
return false;
} else {
-
+
return true;
}
@@ -207,17 +224,32 @@ class Util {
}
+ // If there's no record for this user's encryption preferences
+ if ( false === $this->recoveryEnabledForUser() ) {
+
+ // create database configuration
+ $sql = 'INSERT INTO `*PREFIX*encryption` (`uid`,`mode`,`recovery`) VALUES (?,?,?)';
+ $args = array( $this->userId, 'server-side', 0);
+ $query = \OCP\DB::prepare( $sql );
+ $query->execute( $args );
+
+ }
+
return true;
}
+
+ public function getPublicShareKeyId() {
+ return $this->publicShareKeyId;
+ }
/**
* @brief Check whether pwd recovery is enabled for a given user
- * @return bool
+ * @return 1 = yes, 0 = no, false = no record
* @note If records are not being returned, check for a hidden space
* at the start of the uid in db
*/
- public function recoveryEnabled() {
+ public function recoveryEnabledForUser() {
$sql = 'SELECT
recovery
@@ -232,16 +264,25 @@ class Util {
$result = $query->execute( $args );
- // Set default in case no records found
- $recoveryEnabled = 0;
+ $recoveryEnabled = array();
while( $row = $result->fetchRow() ) {
- $recoveryEnabled = $row['recovery'];
+ $recoveryEnabled[] = $row['recovery'];
}
- return $recoveryEnabled;
+ // If no record is found
+ if ( empty( $recoveryEnabled ) ) {
+
+ return false;
+
+ // If a record is found
+ } else {
+
+ return $recoveryEnabled[0];
+
+ }
}
@@ -250,20 +291,33 @@ class Util {
* @param bool $enabled Whether to enable or disable recovery
* @return bool
*/
- public function setRecovery( $enabled ) {
+ public function setRecoveryForUser( $enabled ) {
- $sql = 'UPDATE
- *PREFIX*encryption
- SET
- recovery = ?
- WHERE
- uid = ?';
+ $recoveryStatus = $this->recoveryEnabledForUser();
+
+ // If a record for this user already exists, update it
+ if ( false === $recoveryStatus ) {
- // Ensure value is an integer
- $enabled = intval( $enabled );
+ $sql = 'INSERT INTO `*PREFIX*encryption`
+ (`uid`,`mode`,`recovery`)
+ VALUES (?,?,?)';
+
+ $args = array( $this->userId, 'server-side', $enabled );
- $args = array( $enabled, $this->userId );
-
+ // Create a new record instead
+ } else {
+
+ $sql = 'UPDATE
+ *PREFIX*encryption
+ SET
+ recovery = ?
+ WHERE
+ uid = ?';
+
+ $args = array( $enabled, $this->userId );
+
+ }
+
$query = \OCP\DB::prepare( $sql );
if ( $query->execute( $args ) ) {
@@ -282,7 +336,6 @@ class Util {
* @brief Find all files and their encryption status within a directory
* @param string $directory The path of the parent directory to search
* @return mixed false if 0 found, array on success. Keys: name, path
-
* @note $directory needs to be a path relative to OC data dir. e.g.
* /admin/files NOT /backup OR /home/www/oc/data/admin/files
*/
@@ -421,26 +474,123 @@ class Util {
return $text;
}
- /**
- * @brief Check if a given path identifies an encrypted file
- * @return true / false
- */
+ /**
+ * @brief Check if a given path identifies an encrypted file
+ * @return true / false
+ */
public function isEncryptedPath( $path ) {
- // Disable encryption proxy so data retreived is in its
+ // Disable encryption proxy so data retrieved is in its
// original form
+ $proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
-
- $data = $this->view->file_get_contents( $path );
-
- \OC_FileProxy::$enabled = true;
+
+ // we only need 24 byte from the last chunk
+ $data = '';
+ $handle = $this->view->fopen( $path, 'r' );
+ if(!fseek($handle, -24, SEEK_END)) {
+ $data = fgets($handle);
+ }
+
+ // re-enable proxy
+ \OC_FileProxy::$enabled = $proxyStatus;
return Crypt::isCatfileContent( $data );
}
+
+ /**
+ * @brief get the file size of the unencrypted file
+ * @param $path absolute path
+ * @return bool
+ */
+
+ public function getFileSize( $path ) {
+
+ $result = 0;
+
+ // Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ // Reformat path for use with OC_FSV
+ $pathSplit = explode( '/', $path );
+ $pathRelative = implode( '/', array_slice( $pathSplit, 3 ) );
+
+ if ($pathSplit[2] == 'files' && $this->view->file_exists($path) && $this->isEncryptedPath($path)) {
+
+ // get the size from filesystem
+ $fullPath = $this->view->getLocalFile($path);
+ $size = filesize($fullPath);
+
+ // calculate last chunk nr
+ $lastChunckNr = floor($size / 8192);
+
+ // open stream
+ $stream = fopen('crypt://' . $pathRelative, "r");
+
+ if(is_resource($stream)) {
+ // calculate last chunk position
+ $lastChunckPos = ($lastChunckNr * 8192);
+
+ // seek to end
+ fseek($stream, $lastChunckPos);
+
+ // get the content of the last chunk
+ $lastChunkContent = fread($stream, 8192);
+
+ // calc the real file size with the size of the last chunk
+ $realSize = (($lastChunckNr * 6126) + strlen($lastChunkContent));
+
+ // store file size
+ $result = $realSize;
+ }
+ }
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ return $result;
+ }
+
+ /**
+ * @brief fix the file size of the encrypted file
+ * @param $path absolute path
+ * @return true / false if file is encrypted
+ */
+
+ public function fixFileSize( $path ) {
+ $result = false;
+
+ // Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ $realSize = $this->getFileSize( $path );
+
+ if ( $realSize > 0 ) {
+
+ $cached = $this->view->getFileInfo( $path );
+ $cached['encrypted'] = true;
+
+ // set the size
+ $cached['unencrypted_size'] = $realSize;
+
+ // put file info
+ $this->view->putFileInfo( $path, $cached );
+
+ $result = true;
+
+ }
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ return $result;
+ }
+
/**
* @brief Format a path to be relative to the /user/files/ directory
+ * @note e.g. turns '/admin/files/test.txt' into 'test.txt'
*/
public function stripUserFilesPath( $path ) {
@@ -454,6 +604,21 @@ class Util {
}
/**
+ * @brief Format a path to be relative to the /user directory
+ * @note e.g. turns '/admin/files/test.txt' into 'files/test.txt'
+ */
+ public function stripFilesPath( $path ) {
+
+ $trimmed = ltrim( $path, '/' );
+ $split = explode( '/', $trimmed );
+ $sliced = array_slice( $split, 1 );
+ $relPath = implode( '/', $sliced );
+
+ return $relPath;
+
+ }
+
+ /**
* @brief Format a shared path to be relative to the /user/files/ directory
* @note Expects a path like /uid/files/Shared/filepath
*/
@@ -517,7 +682,7 @@ class Util {
stream_copy_to_stream( $plainHandle1, $plainHandle2 );
// Close access to original file
-// $this->view->fclose( $plainHandle1 ); // not implemented in view{}
+ // $this->view->fclose( $plainHandle1 ); // not implemented in view{}
// Delete original plain file so we can rename enc file later
$this->view->unlink( $rawPath );
@@ -653,7 +818,7 @@ class Util {
* @return multi-dimensional array. keys: ready, unready
*/
public function filterShareReadyUsers( $unfilteredUsers ) {
-
+
// This array will collect the filtered IDs
$readyIds = $unreadyIds = array();
@@ -665,8 +830,9 @@ class Util {
// Check that the user is encryption capable, or is the
// public system user 'ownCloud' (for public shares)
if (
- $util->ready()
- or $user == 'owncloud'
+ $user == $this->publicShareKeyId
+ or $user == $this->recoveryKeyId
+ or $util->ready()
) {
// Construct array of ready UIDs for Keymanager{}
@@ -738,25 +904,27 @@ class Util {
* @brief Encrypt keyfile to multiple users
* @param array $users list of users which should be able to access the file
* @param string $filePath path of the file to be shared
+ * @return bool
*/
public function setSharedFileKeyfiles( Session $session, array $users, $filePath ) {
-
+
// Make sure users are capable of sharing
$filteredUids = $this->filterShareReadyUsers( $users );
-// trigger_error( print_r($filteredUids, 1) );
-
+ // If we're attempting to share to unready users
if ( ! empty( $filteredUids['unready'] ) ) {
-
- // Notify user of unready userDir
- // TODO: Move this out of here; it belongs somewhere else
- \OCP\JSON::error();
+
+ \OC_Log::write( 'Encryption library', 'Sharing to these user(s) failed as they are unready for encryption:"'.print_r( $filteredUids['unready'], 1 ), \OC_Log::WARN );
+
+ return false;
}
// Get public keys for each user, ready for generating sharekeys
$userPubKeys = Keymanager::getPublicKeys( $this->view, $filteredUids['ready'] );
-
+
+ // Note proxy status then disable it
+ $proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
// Get the current users's private key for decrypting existing keyfile
@@ -772,21 +940,19 @@ class Util {
// Save the recrypted key to it's owner's keyfiles directory
// Save new sharekeys to all necessary user directory
- // TODO: Reuse the keyfile, it it exists, instead of making a new one
if (
! Keymanager::setFileKey( $this->view, $filePath, $fileOwner, $multiEncKey['data'] )
|| ! Keymanager::setShareKeys( $this->view, $filePath, $multiEncKey['keys'] )
) {
- trigger_error( "SET Share keys failed" );
+ \OC_Log::write( 'Encryption library', 'Keyfiles could not be saved for users sharing ' . $filePath, \OC_Log::ERROR );
+
+ return false;
}
-
- // Delete existing keyfile
- // Do this last to ensure file is recoverable in case of error
- // Keymanager::deleteFileKey( $this->view, $this->userId, $params['fileTarget'] );
-
- \OC_FileProxy::$enabled = true;
+
+ // Return proxy to original status
+ \OC_FileProxy::$enabled = $proxyStatus;
return true;
}
@@ -798,33 +964,51 @@ class Util {
public function getSharingUsersArray( $sharingEnabled, $filePath, $currentUserId = false ) {
// Check if key recovery is enabled
- $recoveryEnabled = $this->recoveryEnabled();
+ if (
+ \OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' )
+ && $this->recoveryEnabledForUser()
+ ) {
+
+ $recoveryEnabled = true;
+
+ } else {
+
+ $recoveryEnabled = false;
+
+ }
// Make sure that a share key is generated for the owner too
- list($owner, $ownerPath) = $this->getUidAndFilename($filePath);
+ list( $owner, $ownerPath ) = $this->getUidAndFilename( $filePath );
if ( $sharingEnabled ) {
// Find out who, if anyone, is sharing the file
- $userIds = \OCP\Share::getUsersSharingFile( $ownerPath, $owner,true, true, true );
+ $result = \OCP\Share::getUsersSharingFile( $ownerPath, $owner,true, true, true );
+ $userIds = $result['users'];
+ if ( $result['public'] ) {
+ $userIds[] = $this->publicShareKeyId;
+ }
}
// If recovery is enabled, add the
// Admin UID to list of users to share to
if ( $recoveryEnabled ) {
-
- // FIXME: Create a separate admin user purely for recovery, and create method in util for fetching this id from DB?
- $adminUid = 'recoveryAdmin';
-
- $userIds[] = $adminUid;
+
+ // Find recoveryAdmin user ID
+ $recoveryKeyId = \OC_Appconfig::getValue( 'files_encryption', 'recoveryKeyId' );
+
+ // Add recoveryAdmin to list of users sharing
+ $userIds[] = $recoveryKeyId;
}
- // add current user if given
- if($currentUserId != false) {
- $userIds[] = $currentUserId;
- }
+ // add current user if given
+ if ( $currentUserId != false ) {
+
+ $userIds[] = $currentUserId;
+
+ }
// Remove duplicate UIDs
$uniqueUserIds = array_unique ( $userIds );
@@ -832,57 +1016,138 @@ class Util {
return $uniqueUserIds;
}
-
+
/**
- * @brief get uid of the owners of the file and the path to the file
- * @param $path Path of the file to check
- * @note $shareFilePath must be relative to data/UID/files. Files
- * relative to /Shared are also acceptable
- * @return array
+ * @brief Set file migration status for user
+ * @return bool
*/
- public function getUidAndFilename( $path ) {
-
- $fileOwnerUid = \OC\Files\Filesystem::getOwner( $path );
+ public function setMigrationStatus( $status ) {
+
+ $sql = 'UPDATE
+ *PREFIX*encryption
+ SET
+ migrationStatus = ?
+ WHERE
+ uid = ?';
- // Check that UID is valid
- if ( ! \OCP\User::userExists( $fileOwnerUid ) ) {
+ $args = array( $status, $this->userId );
- throw new \Exception( 'Could not find owner (UID = "' . var_export( $fileOwnerUid, 1 ) . '") of file "' . $path . '"' );
-
- }
-
- // NOTE: Bah, this dependency should be elsewhere
- \OC\Files\Filesystem::initMountPoints( $fileOwnerUid );
+ $query = \OCP\DB::prepare( $sql );
- // If the file owner is the currently logged in user
- if ( $fileOwnerUid == $this->userId ) {
+ if ( $query->execute( $args ) ) {
- // Assume the path supplied is correct
- $filename = $path;
+ return true;
} else {
- $info = \OC\Files\Filesystem::getFileInfo( $path );
- $ownerView = new \OC\Files\View( '/' . $fileOwnerUid . '/files' );
+ return false;
- // Fetch real file path from DB
- $filename = $ownerView->getPath( $info['fileid'] ); // TODO: Check that this returns a path without including the user data dir
-
}
+
+ }
+
+ /**
+ * @brief Check whether pwd recovery is enabled for a given user
+ * @return 1 = yes, 0 = no, false = no record
+ * @note If records are not being returned, check for a hidden space
+ * at the start of the uid in db
+ */
+ public function getMigrationStatus() {
+
+ $sql = 'SELECT
+ migrationStatus
+ FROM
+ `*PREFIX*encryption`
+ WHERE
+ uid = ?';
+
+ $args = array( $this->userId );
+
+ $query = \OCP\DB::prepare( $sql );
- // Make path relative for use by $view
- $relpath = $fileOwnerUid . '/' . $this->fileFolderName . '/' . $filename;
+ $result = $query->execute( $args );
- // Check that the filename we're using is working
- if ( $this->view->file_exists( $relpath ) ) {
+ $migrationStatus = array();
- return array ( $fileOwnerUid, $filename );
+ while( $row = $result->fetchRow() ) {
+
+ $migrationStatus[] = $row['migrationStatus'];
- } else {
+ }
+
+ // If no record is found
+ if ( empty( $migrationStatus ) ) {
return false;
+
+ // If a record is found
+ } else {
+
+ return $migrationStatus[0];
}
+
+ }
+
+ /**
+ * @brief get uid of the owners of the file and the path to the file
+ * @param $path Path of the file to check
+ * @note $shareFilePath must be relative to data/UID/files. Files
+ * relative to /Shared are also acceptable
+ * @return array
+ */
+ public function getUidAndFilename( $path ) {
+
+ $view = new \OC\Files\View($this->userFilesDir);
+ $fileOwnerUid = $view->getOwner( $path );
+
+ // handle public access
+ if($fileOwnerUid === false && $this->isPublic) {
+ $filename = $path;
+ $fileOwnerUid = $GLOBALS['fileOwner'];
+
+ return array ( $fileOwnerUid, $filename );
+ } else {
+
+ // Check that UID is valid
+ if ( ! \OCP\User::userExists( $fileOwnerUid ) ) {
+ throw new \Exception( 'Could not find owner (UID = "' . var_export( $fileOwnerUid, 1 ) . '") of file "' . $path . '"' );
+ }
+
+ // NOTE: Bah, this dependency should be elsewhere
+ \OC\Files\Filesystem::initMountPoints( $fileOwnerUid );
+
+ // If the file owner is the currently logged in user
+ if ( $fileOwnerUid == $this->userId ) {
+
+ // Assume the path supplied is correct
+ $filename = $path;
+
+ } else {
+
+ $info = $view->getFileInfo( $path );
+ $ownerView = new \OC\Files\View( '/' . $fileOwnerUid . '/files' );
+
+ // Fetch real file path from DB
+ $filename = $ownerView->getPath( $info['fileid'] ); // TODO: Check that this returns a path without including the user data dir
+
+ }
+
+ // Make path relative for use by $view
+ $relpath = \OC\Files\Filesystem::normalizePath($fileOwnerUid . '/' . $this->fileFolderName . '/' . $filename);
+
+ // Check that the filename we're using is working
+ if ( $this->view->file_exists( $relpath ) ) {
+
+ return array ( $fileOwnerUid, $filename );
+
+ } else {
+
+ return false;
+
+ }
+ }
+
}
@@ -891,19 +1156,130 @@ class Util {
* @param type $dir relative to the users files folder
* @return array with list of files relative to the users files folder
*/
- public function getAllFiles($dir) {
+ public function getAllFiles( $dir ) {
+
$result = array();
+
+ $content = $this->view->getDirectoryContent( $this->userFilesDir . $dir );
+
+ // handling for re shared folders
+ $path_split = explode( '/', $dir );
+ $shared = '';
+
+ if( $path_split[1] === 'Shared' ) {
- $content = $this->view->getDirectoryContent($this->userFilesDir.$dir);
+ $shared = '/Shared';
+
+ }
+
+ foreach ( $content as $c ) {
+
+ $sharedPart = $path_split[sizeof( $path_split )-1];
+ $targetPathSplit = array_reverse( explode( '/', $c['path'] ) );
+
+ $path = '';
+
+ // rebuild path
+ foreach ( $targetPathSplit as $pathPart ) {
+
+ if ( $pathPart !== $sharedPart ) {
+
+ $path = '/' . $pathPart . $path;
+
+ } else {
+
+ break;
+
+ }
+
+ }
+
+ $path = $dir.$path;
- foreach ($content as $c) {
if ($c['type'] === "dir" ) {
- $result = array_merge($result, $this->getAllFiles(substr($c['path'],5)));
+
+ $result = array_merge( $result, $this->getAllFiles( $path ) );
+
} else {
- $result[] = substr($c['path'], 5);
+
+ $result[] = $path;
+
}
}
+
return $result;
+
}
+ /**
+ * @brief get shares parent.
+ * @param int $id of the current share
+ * @return array of the parent
+ */
+ public static function getShareParent( $id ) {
+
+ $query = \OC_DB::prepare( 'SELECT `file_target`, `item_type`'
+ .' FROM `*PREFIX*share`'
+ .' WHERE `id` = ?' );
+
+ $result = $query->execute( array( $id ) );
+
+ $row = $result->fetchRow();
+
+ return $row;
+
+ }
+
+ /**
+ * @brief get owner of the shared files.
+ * @param int $Id of a share
+ * @return owner
+ */
+ public function getOwnerFromSharedFile( $id ) {
+
+ $query = \OC_DB::prepare( 'SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1 );
+ $source = $query->execute( array( $id ) )->fetchRow();
+
+ if ( isset($source['parent'] ) ) {
+
+ $parent = $source['parent'];
+
+ while ( isset( $parent ) ) {
+
+ $query = \OC_DB::prepare( 'SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1 );
+ $item = $query->execute( array( $parent ) )->fetchRow();
+
+ if ( isset( $item['parent'] ) ) {
+
+ $parent = $item['parent'];
+
+ } else {
+
+ $fileOwner = $item['uid_owner'];
+
+ break;
+
+ }
+ }
+
+ } else {
+
+ $fileOwner = $source['uid_owner'];
+
+ }
+
+ return $fileOwner;
+
+ }
+
+ public function getUserId()
+ {
+ return $this->userId;
+ }
+
+ public function getUserFilesDir()
+ {
+ return $this->userFilesDir;
+ }
+
}
diff --git a/apps/files_encryption/settings.php b/apps/files_encryption/settings-admin.php
index 71d47f061af..ae9a85643ef 100644
--- a/apps/files_encryption/settings.php
+++ b/apps/files_encryption/settings-admin.php
@@ -8,20 +8,22 @@
\OC_Util::checkAdminUser();
-$tmpl = new OCP\Template( 'files_encryption', 'settings' );
+$tmpl = new OCP\Template( 'files_encryption', 'settings-admin' );
$blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) );
// Check if an adminRecovery account is enabled for recovering files after lost pwd
$view = new OC_FilesystemView( '' );
-$util = new \OCA\Encryption\Util( $view, \OCP\USER::getUser() );
-$recoveryEnabled = $util->recoveryEnabled();
+
+$recoveryAdminEnabled = OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' );
+$recoveryAdminUid = OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminUid' );
$tmpl->assign( 'blacklist', $blackList );
$tmpl->assign( 'encryption_mode', \OC_Appconfig::getValue( 'files_encryption', 'mode', 'none' ) );
-$tmpl->assign( 'recoveryEnabled', $recoveryEnabled );
+$tmpl->assign( 'recoveryEnabled', $recoveryAdminEnabled );
+$tmpl->assign( 'recoveryAdminUid', $recoveryAdminUid );
-\OCP\Util::addscript( 'files_encryption', 'settings' );
+\OCP\Util::addscript( 'files_encryption', 'settings-admin' );
\OCP\Util::addscript( 'core', 'multiselect' );
return $tmpl->fetchPage();
diff --git a/apps/files_encryption/settings-personal.php b/apps/files_encryption/settings-personal.php
index c001bb0d725..46efb61b029 100644
--- a/apps/files_encryption/settings-personal.php
+++ b/apps/files_encryption/settings-personal.php
@@ -6,10 +6,35 @@
* See the COPYING-README file.
*/
+// Add CSS stylesheet
+\OC_Util::addStyle( 'files_encryption', 'settings-personal' );
+
$tmpl = new OCP\Template( 'files_encryption', 'settings-personal');
$blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', '' ) );
+// Add human readable message in case nothing is blacklisted
+if (
+ 1 == count( $blackList )
+ && $blackList[0] == ''
+) {
+
+ // FIXME: Make this string translatable
+ $blackList[0] = "(None - all filetypes will be encrypted)";
+
+}
+
+$user = \OCP\USER::getUser();
+$view = new \OC_FilesystemView( '/' );
+$util = new \OCA\Encryption\Util( $view, $user );
+
+$recoveryAdminEnabled = OC_Appconfig::getValue( 'files_encryption', 'recoveryAdminEnabled' );
+$recoveryEnabledForUser = $util->recoveryEnabledForUser();
+
+\OCP\Util::addscript( 'files_encryption', 'settings-personal' );
+
+$tmpl->assign( 'recoveryEnabled', $recoveryAdminEnabled );
+$tmpl->assign( 'recoveryEnabledForUser', $recoveryEnabledForUser );
$tmpl->assign( 'blacklist', $blackList );
return $tmpl->fetchPage();
diff --git a/apps/files_encryption/templates/settings.php b/apps/files_encryption/templates/settings-admin.php
index 6499d0c8e80..be7beecf696 100644
--- a/apps/files_encryption/templates/settings.php
+++ b/apps/files_encryption/templates/settings-admin.php
@@ -4,22 +4,16 @@
<p>
<strong><?php p($l->t( 'Encryption' )); ?></strong>
<br />
-
- <?php p($l->t( "Exclude the following file types from encryption:" )); ?>
- <br />
-
- <select
- id='encryption_blacklist'
- title="<?php p($l->t( 'None' ))?>"
- multiple="multiple">
- <?php foreach($_["blacklist"] as $type): ?>
- <option selected="selected" value="<?php p($type); ?>"> <?php p($type); ?> </option>
- <?php endforeach;?>
- </select>
</p>
<p>
- <?php p($l->t( "Enable encryption passwords recovery account (allow sharing to recovery account):" )); ?>
+ <?php p($l->t( "Enable encryption passwords recovery key (allow sharing to recovery key):" )); ?>
+ <br />
<br />
+ <?php if ( empty( $_['recoveryAdminUid'] ) ): ?>
+ <input type="password" name="recoveryPassword" id="recoveryPassword" />
+ <label for="recoveryPassword">Recovery account password</label>
+ <br />
+ <?php endif; ?>
<input
type='radio'
name='adminEnableRecovery'
diff --git a/apps/files_encryption/templates/settings-personal.php b/apps/files_encryption/templates/settings-personal.php
index 5f0accaed5f..00f567ecb26 100644
--- a/apps/files_encryption/templates/settings-personal.php
+++ b/apps/files_encryption/templates/settings-personal.php
@@ -1,15 +1,19 @@
<form id="encryption">
<fieldset class="personalblock">
<legend>
- <?php p($l->t( 'Encryption' )); ?>
+ <?php p( $l->t( 'Encryption' ) ); ?>
</legend>
+
<p>
- <?php p($l->t( 'File encryption is enabled.' )); ?>
+<!-- <?php p( $l->t( 'File encryption is enabled.' ) ); ?> -->
</p>
<?php if ( ! empty( $_["blacklist"] ) ): ?>
<p>
- <?php p($l->t( 'The following file types will not be encrypted:' )); ?>
+ <strong>File types</strong>
+ <br />
+ <?php p( $l->t( 'The following file types will not be encrypted:' ) ); ?>
</p>
+
<ul>
<?php foreach( $_["blacklist"] as $type ): ?>
<li>
@@ -18,5 +22,43 @@
<?php endforeach; ?>
</ul>
<?php endif; ?>
+ <br />
+ <?php if ( $_["recoveryEnabled"] ): ?>
+ <p>
+ <label for="userEnableRecovery"><?php p( $l->t( "Enable password recovery by sharing all files with administrator:" ) ); ?></label>
+ <br />
+ <em><?php p( $l->t( "Enabling this option will allow you to reobtain access to your encrypted files if your password is lost" ) ); ?></em>
+ <br />
+ <input
+ type='radio'
+ name='userEnableRecovery'
+ value='1'
+ <?php echo ( $_["recoveryEnabledForUser"] == 1 ? 'checked="checked"' : '' ); ?> />
+ <?php p( $l->t( "Enabled" ) ); ?>
+ <br />
+
+ <input
+ type='radio'
+ name='userEnableRecovery'
+ value='0'
+ <?php echo ( $_["recoveryEnabledForUser"] == 0 ? 'checked="checked"' : '' ); ?> />
+ <?php p( $l->t( "Disabled" ) ); ?>
+ <div id="recoveryEnabledSuccess"><?php p( $l->t( 'File recovery settings updated' ) ); ?></div>
+ <div id="recoveryEnabledError"><?php p( $l->t( 'Could not update file recovery' ) ); ?></div>
+ </p>
+ <?php endif; ?>
+ <br />
+ <p>
+ <label for="encryptAll"><?php p( $l->t( "Scan for unencrypted files and encrypt them" ) ); ?></label>
+ <br />
+ <em><?php p( $l->t( "Use this if you suspect that you still have files which are unencrypted, or encrypted using ownCloud 4 or older." ) ); ?></em>
+ <br />
+ <input type="submit" id="encryptAll" name="encryptAll" value="<?php p( $l->t( 'Scan and encrypt files' ) ); ?>" />
+ <input type="password" name="userPassword" id="userPassword" />
+ <label for="encryptAll"><?php p( $l->t( "Account password" ) ); ?></label>
+ <div id="encryptAllSuccess"><?php p( $l->t( 'Scan complete' ) );?></div>
+ <div id="encryptAllError"><?php p( $l->t( 'Unable to scan and encrypt files' ) );?></div>
+ </p>
+
</fieldset>
</form>
diff --git a/apps/files_encryption/test/binary b/apps/files_encryption/tests/binary
index 79bc99479da..79bc99479da 100644
--- a/apps/files_encryption/test/binary
+++ b/apps/files_encryption/tests/binary
Binary files differ
diff --git a/apps/files_encryption/test/crypt.php b/apps/files_encryption/tests/crypt.php
index b02e63b2ffc..de7ae38b173 100755
--- a/apps/files_encryption/test/crypt.php
+++ b/apps/files_encryption/tests/crypt.php
@@ -15,13 +15,13 @@ require_once realpath( dirname(__FILE__).'/../lib/keymanager.php' );
require_once realpath( dirname(__FILE__).'/../lib/proxy.php' );
require_once realpath( dirname(__FILE__).'/../lib/stream.php' );
require_once realpath( dirname(__FILE__).'/../lib/util.php' );
+require_once realpath( dirname(__FILE__).'/../lib/helper.php' );
require_once realpath( dirname(__FILE__).'/../appinfo/app.php' );
use OCA\Encryption;
// This has to go here because otherwise session errors arise, and the private
// encryption key needs to be saved in the session
-\OC_User::login( 'admin', 'admin' );
/**
* @note It would be better to use Mockery here for mocking out the session
@@ -34,8 +34,11 @@ use OCA\Encryption;
class Test_Crypt extends \PHPUnit_Framework_TestCase {
function setUp() {
-
- // set content for encrypting / decrypting in tests
+ // reset backend
+ \OC_User::clearBackends();
+ \OC_User::useBackend('database');
+
+ // set content for encrypting / decrypting in tests
$this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) );
$this->dataShort = 'hats';
$this->dataUrl = realpath( dirname(__FILE__).'/../lib/crypt.php' );
@@ -52,17 +55,32 @@ class Test_Crypt extends \PHPUnit_Framework_TestCase {
\OC_User::setUserId( 'admin' );
$this->userId = 'admin';
$this->pass = 'admin';
-
- \OC_Filesystem::init( '/' );
- \OC_Filesystem::mount( 'OC_Filestorage_Local', array('datadir' => \OC_User::getHome($this->userId)), '/' );
-
+
+ $userHome = \OC_User::getHome($this->userId);
+ $this->dataDir = str_replace('/'.$this->userId, '', $userHome);
+
+ // Filesystem related hooks
+ \OCA\Encryption\Helper::registerFilesystemHooks();
+
+ \OC_FileProxy::register(new OCA\Encryption\Proxy());
+
+ \OC_Util::tearDownFS();
+ \OC_User::setUserId('');
+ \OC\Files\Filesystem::setView(false);
+ \OC_Util::setupFS($this->userId);
+ \OC_User::setUserId($this->userId);
+
+ $params['uid'] = $this->userId;
+ $params['password'] = $this->pass;
+ OCA\Encryption\Hooks::login($params);
+
}
function tearDown() {
-
- }
- function testGenerateKey() {
+ }
+
+ function testGenerateKey() {
# TODO: use more accurate (larger) string length for test confirmation
@@ -220,40 +238,53 @@ class Test_Crypt extends \PHPUnit_Framework_TestCase {
//
// }
- function testSymmetricStreamEncryptShortFileContent() {
-
- $filename = 'tmp-'.time();
+ function testSymmetricStreamEncryptShortFileContent() {
+ $filename = 'tmp-'.time().'.test';
+
$cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataShort );
// Test that data was successfully written
$this->assertTrue( is_int( $cryptedFile ) );
-
-
- // 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 );
-
+
+ // 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;
+
// Check that the file was encrypted before being written to disk
$this->assertNotEquals( $this->dataShort, $retreivedCryptedFile );
-
- // Get private key
- $encryptedPrivateKey = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId );
-
- $decryptedPrivateKey = Encryption\Crypt::symmetricDecryptFileContent( $encryptedPrivateKey, $this->pass );
-
-
- // Get keyfile
- $encryptedKeyfile = Encryption\Keymanager::getFileKey( $this->view, $this->userId, $filename );
-
- $decryptedKeyfile = Encryption\Crypt::keyDecrypt( $encryptedKeyfile, $decryptedPrivateKey );
-
-
- // Manually decrypt
- $manualDecrypt = Encryption\Crypt::symmetricBlockDecryptFileContent( $retreivedCryptedFile, $decryptedKeyfile );
-
+
+ // Get the encrypted keyfile
+ $encKeyfile = Encryption\Keymanager::getFileKey( $this->view, $this->userId, $filename );
+
+ // Attempt to fetch the user's shareKey
+ $shareKey = Encryption\Keymanager::getShareKey( $this->view, $this->userId, $filename );
+
+ // get session
+ $session = new Encryption\Session( $this->view );
+
+ // get private key
+ $privateKey = $session->getPrivateKey( $this->userId );
+
+ // Decrypt keyfile with shareKey
+ $plainKeyfile = Encryption\Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey );
+
+ // Manually decrypt
+ $manualDecrypt = Encryption\Crypt::symmetricDecryptFileContent( $retreivedCryptedFile, $plainKeyfile );
+
// Check that decrypted data matches
$this->assertEquals( $this->dataShort, $manualDecrypt );
-
+
+ // Teardown
+ $this->view->unlink( $this->userId . '/files/' . $filename );
+
+ Encryption\Keymanager::deleteFileKey( $this->view, $this->userId, $filename );
}
/**
@@ -265,7 +296,7 @@ class Test_Crypt extends \PHPUnit_Framework_TestCase {
function testSymmetricStreamEncryptLongFileContent() {
// Generate a a random filename
- $filename = 'tmp-'.time();
+ $filename = 'tmp-'.time().'.test';
// Save long data as encrypted file using stream wrapper
$cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong.$this->dataLong );
@@ -273,12 +304,18 @@ class Test_Crypt extends \PHPUnit_Framework_TestCase {
// Test that data was successfully written
$this->assertTrue( is_int( $cryptedFile ) );
- // 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 );
-
-// echo "\n\n\$retreivedCryptedFile = $retreivedCryptedFile\n\n";
-
- // Check that the file was encrypted before being written to disk
+ // 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;
+
+
+ // 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
@@ -290,46 +327,42 @@ class Test_Crypt extends \PHPUnit_Framework_TestCase {
$e = array( $r[0].$r[1], $r[2].$r[3], $r[4].$r[5], $r[6].$r[7], $r[8].$r[9], $r[10].$r[11], $r[12].$r[13] );//.$r[11], $r[12].$r[13], $r[14] );
//print_r($e);
-
-
- // Get private key
- $encryptedPrivateKey = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId );
-
- $decryptedPrivateKey = Encryption\Crypt::symmetricDecryptFileContent( $encryptedPrivateKey, $this->pass );
-
-
- // Get keyfile
- $encryptedKeyfile = Encryption\Keymanager::getFileKey( $this->view, $this->userId, $filename );
-
- $decryptedKeyfile = Encryption\Crypt::keyDecrypt( $encryptedKeyfile, $decryptedPrivateKey );
-
-
+
+ // Get the encrypted keyfile
+ $encKeyfile = Encryption\Keymanager::getFileKey( $this->view, $this->userId, $filename );
+
+ // Attempt to fetch the user's shareKey
+ $shareKey = Encryption\Keymanager::getShareKey( $this->view, $this->userId, $filename );
+
+ // get session
+ $session = new Encryption\Session( $this->view );
+
+ // get private key
+ $privateKey = $session->getPrivateKey( $this->userId );
+
+ // Decrypt keyfile with shareKey
+ $plainKeyfile = Encryption\Crypt::multiKeyDecrypt( $encKeyfile, $shareKey, $privateKey );
+
// Set var for reassembling decrypted content
$decrypt = '';
// Manually decrypt chunk
foreach ($e as $e) {
-
-// echo "\n\$e = $e";
- $chunkDecrypt = Encryption\Crypt::symmetricDecryptFileContent( $e, $decryptedKeyfile );
+ $chunkDecrypt = Encryption\Crypt::symmetricDecryptFileContent( $e, $plainKeyfile );
// Assemble decrypted chunks
$decrypt .= $chunkDecrypt;
-// echo "\n\$chunkDecrypt = $chunkDecrypt";
-
}
-// echo "\n\$decrypt = $decrypt";
-
$this->assertEquals( $this->dataLong.$this->dataLong, $decrypt );
// Teardown
- $this->view->unlink( $filename );
+ $this->view->unlink( $this->userId . '/files/' . $filename );
- Encryption\Keymanager::deleteFileKey( $filename );
+ Encryption\Keymanager::deleteFileKey( $this->view, $this->userId, $filename );
}
@@ -345,15 +378,14 @@ class Test_Crypt extends \PHPUnit_Framework_TestCase {
// Test that data was successfully written
$this->assertTrue( is_int( $cryptedFile ) );
-
-
- // 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 );
-
- $decrypt = file_get_contents( 'crypt://' . $filename );
+
+ // Get file decrypted contents
+ $decrypt = file_get_contents( 'crypt://' . $filename );
$this->assertEquals( $this->dataShort, $decrypt );
-
+
+ // tear down
+ $this->view->unlink( $this->userId . '/files/' . $filename );
}
function testSymmetricStreamDecryptLongFileContent() {
@@ -365,15 +397,14 @@ class Test_Crypt extends \PHPUnit_Framework_TestCase {
// Test that data was successfully written
$this->assertTrue( is_int( $cryptedFile ) );
-
-
- // 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://' . $filename );
-
+
$this->assertEquals( $this->dataLong, $decrypt );
-
+
+ // tear down
+ $this->view->unlink( $this->userId . '/files/' . $filename );
}
// Is this test still necessary?
@@ -600,6 +631,65 @@ class Test_Crypt extends \PHPUnit_Framework_TestCase {
}
+ function testRenameFile() {
+
+ $filename = 'tmp-'.time();
+
+ // Save long data as encrypted file using stream wrapper
+ $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong );
+
+ // Test that data was successfully written
+ $this->assertTrue( is_int( $cryptedFile ) );
+
+ // Get file decrypted contents
+ $decrypt = file_get_contents( 'crypt://' . $filename );
+
+ $this->assertEquals( $this->dataLong, $decrypt );
+
+ $newFilename = 'tmp-new-'.time();
+ $view = new \OC\Files\View('/' . $this->userId . '/files');
+ $view->rename( $filename, $newFilename );
+
+ // Get file decrypted contents
+ $newDecrypt = file_get_contents( 'crypt://' . $newFilename );
+
+ $this->assertEquals( $this->dataLong, $newDecrypt );
+
+ // tear down
+ $view->unlink( $newFilename );
+ }
+
+ function testMoveFileIntoFolder() {
+
+ $filename = 'tmp-'.time();
+
+ // Save long data as encrypted file using stream wrapper
+ $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong );
+
+ // Test that data was successfully written
+ $this->assertTrue( is_int( $cryptedFile ) );
+
+ // Get file decrypted contents
+ $decrypt = file_get_contents( 'crypt://' . $filename );
+
+ $this->assertEquals( $this->dataLong, $decrypt );
+
+ $newFolder = '/newfolder1';
+ $newFilename = 'tmp-new-'.time();
+ $view = new \OC\Files\View('/' . $this->userId . '/files');
+ $view->mkdir($newFolder);
+ $view->rename( $filename, $newFolder . '/' . $newFilename );
+
+ // Get file decrypted contents
+ $newDecrypt = file_get_contents( 'crypt://' . $newFolder . '/' . $newFilename );
+
+ $this->assertEquals( $this->dataLong, $newDecrypt );
+
+ // tear down
+ $view->unlink( $newFolder . '/' . $newFilename );
+ $view->unlink( $newFolder );
+ }
+
// function testEncryption(){
//
// $key=uniqid();
diff --git a/apps/files_encryption/test/keymanager.php b/apps/files_encryption/tests/keymanager.php
index bf453fe3163..d24dcaa0360 100644
--- a/apps/files_encryption/test/keymanager.php
+++ b/apps/files_encryption/tests/keymanager.php
@@ -13,18 +13,22 @@ require_once realpath( dirname(__FILE__).'/../lib/keymanager.php' );
require_once realpath( dirname(__FILE__).'/../lib/proxy.php' );
require_once realpath( dirname(__FILE__).'/../lib/stream.php' );
require_once realpath( dirname(__FILE__).'/../lib/util.php' );
+require_once realpath( dirname(__FILE__).'/../lib/helper.php' );
require_once realpath( dirname(__FILE__).'/../appinfo/app.php' );
use OCA\Encryption;
// This has to go here because otherwise session errors arise, and the private
// encryption key needs to be saved in the session
-\OC_User::login( 'admin', 'admin' );
+//\OC_User::login( 'admin', 'admin' );
class Test_Keymanager extends \PHPUnit_Framework_TestCase {
function setUp() {
-
+ // reset backend
+ \OC_User::clearBackends();
+ \OC_User::useBackend('database');
+
\OC_FileProxy::$enabled = false;
// set content for encrypting / decrypting in tests
@@ -38,16 +42,30 @@ class Test_Keymanager extends \PHPUnit_Framework_TestCase {
$keypair = Encryption\Crypt::createKeypair();
$this->genPublicKey = $keypair['publicKey'];
$this->genPrivateKey = $keypair['privateKey'];
-
- $this->view = new \OC_FilesystemView( '/' );
-
- \OC_User::setUserId( 'admin' );
- $this->userId = 'admin';
- $this->pass = 'admin';
-
- \OC_Filesystem::init( '/' );
- \OC_Filesystem::mount( 'OC_Filestorage_Local', array('datadir' => \OC_User::getHome($this->userId)), '/' );
-
+
+ $this->view = new \OC_FilesystemView( '/' );
+
+ \OC_User::setUserId( 'admin' );
+ $this->userId = 'admin';
+ $this->pass = 'admin';
+
+ $userHome = \OC_User::getHome($this->userId);
+ $this->dataDir = str_replace('/'.$this->userId, '', $userHome);
+
+ // Filesystem related hooks
+ \OCA\Encryption\Helper::registerFilesystemHooks();
+
+ \OC_FileProxy::register(new OCA\Encryption\Proxy());
+
+ \OC_Util::tearDownFS();
+ \OC_User::setUserId('');
+ \OC\Files\Filesystem::setView(false);
+ \OC_Util::setupFS($this->userId);
+ \OC_User::setUserId($this->userId);
+
+ $params['uid'] = $this->userId;
+ $params['password'] = $this->pass;
+ OCA\Encryption\Hooks::login($params);
}
function tearDown(){
@@ -59,9 +77,13 @@ class Test_Keymanager extends \PHPUnit_Framework_TestCase {
function testGetPrivateKey() {
$key = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId );
-
+
+ $privateKey = Encryption\Crypt::symmetricDecryptFileContent( $key, $this->pass);
+
// Will this length vary? Perhaps we should use a range instead
- $this->assertEquals( 2296, strlen( $key ) );
+ $this->assertGreaterThan( 27, strlen( $privateKey ) );
+
+ $this->assertEquals( '-----BEGIN PRIVATE KEY-----', substr( $privateKey, 0, 27 ) );
}
@@ -69,7 +91,7 @@ class Test_Keymanager extends \PHPUnit_Framework_TestCase {
$key = Encryption\Keymanager::getPublicKey( $this->view, $this->userId );
- $this->assertEquals( 451, strlen( $key ) );
+ $this->assertGreaterThan( 26, strlen( $key ) );
$this->assertEquals( '-----BEGIN PUBLIC KEY-----', substr( $key, 0, 26 ) );
}
@@ -81,11 +103,19 @@ class Test_Keymanager extends \PHPUnit_Framework_TestCase {
$key = Encryption\Crypt::symmetricEncryptFileContentKeyfile( $this->randomKey, 'hat' );
- $path = 'unittest-'.time().'txt';
-
+ $file = 'unittest-'.time().'.txt';
+
+ // Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ $this->view->file_put_contents($this->userId . '/files/' . $file, $key['encrypted']);
+
+ // Re-enable proxy - our work is done
+ \OC_FileProxy::$enabled = $proxyStatus;
+
//$view = new \OC_FilesystemView( '/' . $this->userId . '/files_encryption/keyfiles' );
-
- Encryption\Keymanager::setFileKey( $this->view, $path, $this->userId, $key['key'] );
+ Encryption\Keymanager::setFileKey( $this->view, $file, $this->userId, $key['key'] );
}
@@ -109,9 +139,15 @@ class Test_Keymanager extends \PHPUnit_Framework_TestCase {
$keys = Encryption\Keymanager::getUserKeys( $this->view, $this->userId );
- $this->assertEquals( 451, strlen( $keys['publicKey'] ) );
+ $this->assertGreaterThan( 26, strlen( $keys['publicKey'] ) );
+
$this->assertEquals( '-----BEGIN PUBLIC KEY-----', substr( $keys['publicKey'], 0, 26 ) );
- $this->assertEquals( 2296, strlen( $keys['privateKey'] ) );
+
+ $privateKey = Encryption\Crypt::symmetricDecryptFileContent( $keys['privateKey'], $this->pass);
+
+ $this->assertGreaterThan( 27, strlen( $keys['privateKey'] ) );
+
+ $this->assertEquals( '-----BEGIN PRIVATE KEY-----', substr( $privateKey, 0, 27 ) );
}
diff --git a/apps/files_encryption/test/legacy-encrypted-text.txt b/apps/files_encryption/tests/legacy-encrypted-text.txt
index cb5bf50550d..cb5bf50550d 100644
--- a/apps/files_encryption/test/legacy-encrypted-text.txt
+++ b/apps/files_encryption/tests/legacy-encrypted-text.txt
Binary files differ
diff --git a/apps/files_encryption/test/proxy.php b/apps/files_encryption/tests/proxy.php
index 5a2d851ff7c..5a2d851ff7c 100644
--- a/apps/files_encryption/test/proxy.php
+++ b/apps/files_encryption/tests/proxy.php
diff --git a/apps/files_encryption/tests/share.php b/apps/files_encryption/tests/share.php
new file mode 100755
index 00000000000..e2e26aa75b5
--- /dev/null
+++ b/apps/files_encryption/tests/share.php
@@ -0,0 +1,473 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Florin Peter
+ * @copyright 2013 Florin Peter <owncloud@florin-peter.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library 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 along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+require_once realpath(dirname(__FILE__) . '/../../../3rdparty/Crypt_Blowfish/Blowfish.php');
+require_once realpath(dirname(__FILE__) . '/../../../lib/base.php');
+require_once realpath(dirname(__FILE__) . '/../lib/crypt.php');
+require_once realpath(dirname(__FILE__) . '/../lib/keymanager.php');
+require_once realpath(dirname(__FILE__) . '/../lib/proxy.php');
+require_once realpath(dirname(__FILE__) . '/../lib/stream.php');
+require_once realpath(dirname(__FILE__) . '/../lib/util.php');
+require_once realpath(dirname(__FILE__) . '/../lib/helper.php');
+require_once realpath(dirname(__FILE__) . '/../appinfo/app.php');
+
+use OCA\Encryption;
+
+class Test_Encryption_Share extends \PHPUnit_Framework_TestCase
+{
+
+ function setUp()
+ {
+ // reset backend
+ \OC_User::clearBackends();
+ \OC_User::useBackend('database');
+
+ $this->dataShort = 'hats';
+ $this->view = new \OC_FilesystemView('/');
+
+ $userHome = \OC_User::getHome('admin');
+ $this->dataDir = str_replace('/admin', '', $userHome);
+
+ $this->folder1 = '/folder1';
+ $this->subfolder = '/subfolder1';
+ $this->subsubfolder = '/subsubfolder1';
+
+ $this->filename = 'share-tmp.test';
+
+ // enable resharing
+ \OC_Appconfig::setValue('core', 'shareapi_allow_resharing', 'yes');
+
+ // clear share hooks
+ \OC_Hook::clear('OCP\\Share');
+ \OC::registerShareHooks();
+ \OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup');
+
+ // Sharing related hooks
+ \OCA\Encryption\Helper::registerShareHooks();
+
+ // Filesystem related hooks
+ \OCA\Encryption\Helper::registerFilesystemHooks();
+
+ \OC_FileProxy::register(new OCA\Encryption\Proxy());
+
+ // remember files_trashbin state
+ $this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
+
+ // we don't want to tests with app files_trashbin enabled
+ \OC_App::disable('files_trashbin');
+
+ // create users
+ $this->loginHelper('user1', true);
+ $this->loginHelper('user2', true);
+ $this->loginHelper('user3', true);
+ }
+
+ function tearDown()
+ {
+ // reset app files_trashbin
+ if ($this->stateFilesTrashbin) {
+ OC_App::enable('files_trashbin');
+ } else {
+ OC_App::disable('files_trashbin');
+ }
+
+ // cleanup users
+ \OC_User::deleteUser('user1');
+ \OC_User::deleteUser('user2');
+ \OC_User::deleteUser('user3');
+ }
+
+ function testShareFile($withTeardown = true)
+ {
+ // login as admin
+ $this->loginHelper('admin');
+
+ // save file with content
+ $cryptedFile = file_put_contents('crypt://' . $this->filename, $this->dataShort);
+
+ // test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile));
+
+ // disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ // get the file info from previous created file
+ $fileInfo = $this->view->getFileInfo('/admin/files/' . $this->filename);
+
+ // check if we have a valid file info
+ $this->assertTrue(is_array($fileInfo));
+
+ // check if the unencrypted file size is stored
+ $this->assertGreaterThan(0, $fileInfo['unencrypted_size']);
+
+ // re-enable the file proxy
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ // share the file
+ \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1', OCP\PERMISSION_ALL);
+
+ // login as admin
+ $this->loginHelper('admin');
+
+ // check if share key for user1 exists
+ $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey'));
+
+ // login as user1
+ $this->loginHelper('user1');
+
+ // get file contents
+ $retrievedCryptedFile = $this->view->file_get_contents('/user1/files/Shared/' . $this->filename);
+
+ // check if data is the same as we previously written
+ $this->assertEquals($this->dataShort, $retrievedCryptedFile);
+
+ // cleanup
+ if ($withTeardown) {
+
+ // login as admin
+ $this->loginHelper('admin');
+
+ // unshare the file
+ \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1');
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey'));
+
+ // cleanup
+ $this->view->unlink('/admin/files/' . $this->filename);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey'));
+ }
+ }
+
+ function testReShareFile($withTeardown = true)
+ {
+ $this->testShareFile(false);
+
+ // login as user1
+ $this->loginHelper('user1');
+
+ // get the file info
+ $fileInfo = $this->view->getFileInfo('/user1/files/Shared/' . $this->filename);
+
+ // share the file with user2
+ \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2', OCP\PERMISSION_ALL);
+
+ // login as admin
+ $this->loginHelper('admin');
+
+ // check if share key for user2 exists
+ $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user2.shareKey'));
+
+ // login as user2
+ $this->loginHelper('user2');
+
+ // get file contents
+ $retrievedCryptedFile = $this->view->file_get_contents('/user2/files/Shared/' . $this->filename);
+
+ // check if data is the same as previously written
+ $this->assertEquals($this->dataShort, $retrievedCryptedFile);
+
+ // cleanup
+ if ($withTeardown) {
+
+ // login as user1
+ $this->loginHelper('user1');
+
+ // unshare the file with user2
+ \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2');
+
+ // login as admin
+ $this->loginHelper('admin');
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user2.shareKey'));
+
+ // unshare the file with user1
+ \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1');
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.user1.shareKey'));
+
+ // cleanup
+ $this->view->unlink('/admin/files/' . $this->filename);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey'));
+ }
+ }
+
+ function testShareFolder($withTeardown = true)
+ {
+ // login as admin
+ $this->loginHelper('admin');
+
+ // create folder structure
+ $this->view->mkdir('/admin/files' . $this->folder1);
+ $this->view->mkdir('/admin/files' . $this->folder1 . $this->subfolder);
+ $this->view->mkdir('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder);
+
+ // save file with content
+ $cryptedFile = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename, $this->dataShort);
+
+ // test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile));
+
+ // disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ // get the file info from previous created folder
+ $fileInfo = $this->view->getFileInfo('/admin/files' . $this->folder1);
+
+ // check if we have a valid file info
+ $this->assertTrue(is_array($fileInfo));
+
+ // re-enable the file proxy
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ // share the folder with user1
+ \OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1', OCP\PERMISSION_ALL);
+
+ // login as admin
+ $this->loginHelper('admin');
+
+ // check if share key for user1 exists
+ $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey'));
+
+ // login as user1
+ $this->loginHelper('user1');
+
+ // get file contents
+ $retrievedCryptedFile = $this->view->file_get_contents('/user1/files/Shared' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
+
+ // check if data is the same
+ $this->assertEquals($this->dataShort, $retrievedCryptedFile);
+
+ // cleanup
+ if ($withTeardown) {
+
+ // login as admin
+ $this->loginHelper('admin');
+
+ // unshare the folder with user1
+ \OCP\Share::unshare('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1');
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey'));
+
+ // cleanup
+ $this->view->unlink('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey'));
+ }
+
+ return $fileInfo;
+ }
+
+ function testReShareFolder($withTeardown = true)
+ {
+ $fileInfoFolder1 = $this->testShareFolder(false);
+
+ // login as user1
+ $this->loginHelper('user1');
+
+ // disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ // get the file info from previous created folder
+ $fileInfoSubFolder = $this->view->getFileInfo('/user1/files/Shared' . $this->folder1 . $this->subfolder);
+
+ // check if we have a valid file info
+ $this->assertTrue(is_array($fileInfoSubFolder));
+
+ // re-enable the file proxy
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ // share the file with user2
+ \OCP\Share::shareItem('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2', OCP\PERMISSION_ALL);
+
+ // login as admin
+ $this->loginHelper('admin');
+
+ // check if share key for user2 exists
+ $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user2.shareKey'));
+
+ // login as user2
+ $this->loginHelper('user2');
+
+ // get file contents
+ $retrievedCryptedFile = $this->view->file_get_contents('/user2/files/Shared' . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
+
+ // check if data is the same
+ $this->assertEquals($this->dataShort, $retrievedCryptedFile);
+
+ // get the file info
+ $fileInfo = $this->view->getFileInfo('/user2/files/Shared' . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
+
+ // check if we have fileInfos
+ $this->assertTrue(is_array($fileInfo));
+
+ // share the file with user3
+ \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user3', OCP\PERMISSION_ALL);
+
+ // login as admin
+ $this->loginHelper('admin');
+
+ // check if share key for user3 exists
+ $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user3.shareKey'));
+
+ // login as user3
+ $this->loginHelper('user3');
+
+ // get file contents
+ $retrievedCryptedFile = $this->view->file_get_contents('/user3/files/Shared/' . $this->filename);
+
+ // check if data is the same
+ $this->assertEquals($this->dataShort, $retrievedCryptedFile);
+
+ // cleanup
+ if ($withTeardown) {
+
+ // login as user2
+ $this->loginHelper('user2');
+
+ // unshare the file with user3
+ \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user3');
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user3.shareKey'));
+
+ // login as user1
+ $this->loginHelper('user1');
+
+ // unshare the folder with user2
+ \OCP\Share::unshare('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user2');
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user2.shareKey'));
+
+ // login as admin
+ $this->loginHelper('admin');
+
+ // unshare the folder1 with user1
+ \OCP\Share::unshare('folder', $fileInfoFolder1['fileid'], \OCP\Share::SHARE_TYPE_USER, 'user1');
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.user1.shareKey'));
+
+ // cleanup
+ $this->view->unlink('/admin/files' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename . '.admin.shareKey'));
+ }
+ }
+
+ function testPublicShareFile()
+ {
+ // login as admin
+ $this->loginHelper('admin');
+
+ // save file with content
+ $cryptedFile = file_put_contents('crypt://' . $this->filename, $this->dataShort);
+
+ // test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile));
+
+ // disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ // get the file info from previous created file
+ $fileInfo = $this->view->getFileInfo('/admin/files/' . $this->filename);
+
+ // check if we have a valid file info
+ $this->assertTrue(is_array($fileInfo));
+
+ // check if the unencrypted file size is stored
+ $this->assertGreaterThan(0, $fileInfo['unencrypted_size']);
+
+ // re-enable the file proxy
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ // share the file
+ \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null, false);
+
+ // login as admin
+ $this->loginHelper('admin');
+
+ $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId');
+
+ // check if share key for public exists
+ $this->assertTrue($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $publicShareKeyId . '.shareKey'));
+
+ // some hacking to simulate public link
+ $GLOBALS['app'] = 'files_sharing';
+ $GLOBALS['fileOwner'] = 'admin';
+ \OC_User::setUserId('');
+
+ // get file contents
+ $retrievedCryptedFile = file_get_contents('crypt://' . $this->filename);
+
+ // check if data is the same as we previously written
+ $this->assertEquals($this->dataShort, $retrievedCryptedFile);
+
+ // tear down
+
+ // login as admin
+ $this->loginHelper('admin');
+
+ // unshare the file
+ \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.' . $publicShareKeyId . '.shareKey'));
+
+ // cleanup
+ $this->view->unlink('/admin/files/' . $this->filename);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists('/admin/files_encryption/share-keys/' . $this->filename . '.admin.shareKey'));
+ }
+
+ function loginHelper($user, $create = false)
+ {
+ if ($create) {
+ \OC_User::createUser($user, $user);
+ }
+
+ \OC_Util::tearDownFS();
+ \OC_User::setUserId('');
+ \OC\Files\Filesystem::setView(false);
+ \OC_Util::setupFS($user);
+ \OC_User::setUserId($user);
+
+ $params['uid'] = $user;
+ $params['password'] = $user;
+ OCA\Encryption\Hooks::login($params);
+ }
+}
diff --git a/apps/files_encryption/test/stream.php b/apps/files_encryption/tests/stream.php
index ba82ac80eab..633cc9e4fce 100644
--- a/apps/files_encryption/test/stream.php
+++ b/apps/files_encryption/tests/stream.php
@@ -1,4 +1,4 @@
-// <?php
+<?php
// /**
// * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
// * This file is licensed under the Affero General Public License version 3 or
diff --git a/apps/files_encryption/test/util.php b/apps/files_encryption/tests/util.php
index 3ebc484809b..2abf4096902 100755
--- a/apps/files_encryption/test/util.php
+++ b/apps/files_encryption/tests/util.php
@@ -24,24 +24,23 @@ $loader->register();
use \Mockery as m;
use OCA\Encryption;
-\OC_User::login( 'admin', 'admin' );
-
class Test_Enc_Util extends \PHPUnit_Framework_TestCase {
function setUp() {
-
- \OC_Filesystem::mount( 'OC_Filestorage_Local', array(), '/' );
-
- // set content for encrypting / decrypting in tests
+ // reset backend
+ \OC_User::useBackend('database');
+
+ \OC_User::setUserId( 'admin' );
+ $this->userId = 'admin';
+ $this->pass = 'admin';
+
+ // set content for encrypting / decrypting in tests
$this->dataUrl = realpath( dirname(__FILE__).'/../lib/crypt.php' );
$this->dataShort = 'hats';
$this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) );
$this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' );
$this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' );
-
- $this->userId = 'admin';
- $this->pass = 'admin';
-
+
$keypair = Encryption\Crypt::createKeypair();
$this->genPublicKey = $keypair['publicKey'];
@@ -52,11 +51,29 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase {
$this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles';
$this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key
$this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key
-
- $this->view = new \OC_FilesystemView( '/' );
-
- $this->mockView = m::mock('OC_FilesystemView');
- $this->util = new Encryption\Util( $this->mockView, $this->userId );
+
+ $this->view = new \OC_FilesystemView( '/' );
+
+ $userHome = \OC_User::getHome($this->userId);
+ $this->dataDir = str_replace('/'.$this->userId, '', $userHome);
+
+ // Filesystem related hooks
+ \OCA\Encryption\Helper::registerFilesystemHooks();
+
+ \OC_FileProxy::register(new OCA\Encryption\Proxy());
+
+ \OC_Util::tearDownFS();
+ \OC_User::setUserId('');
+ \OC\Files\Filesystem::setView(false);
+ \OC_Util::setupFS($this->userId);
+ \OC_User::setUserId($this->userId);
+
+ $params['uid'] = $this->userId;
+ $params['password'] = $this->pass;
+ OCA\Encryption\Hooks::login($params);
+
+ $mockView = m::mock('OC_FilesystemView');
+ $this->util = new Encryption\Util( $mockView, $this->userId );
}
@@ -68,6 +85,9 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase {
/**
* @brief test that paths set during User construction are correct
+ *
+ *
+ *
*/
function testKeyPaths() {
@@ -90,8 +110,8 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase {
$mockView = m::mock('OC_FilesystemView');
- $mockView->shouldReceive( 'file_exists' )->times(5)->andReturn( false );
- $mockView->shouldReceive( 'mkdir' )->times(4)->andReturn( true );
+ $mockView->shouldReceive( 'file_exists' )->times(7)->andReturn( false );
+ $mockView->shouldReceive( 'mkdir' )->times(6)->andReturn( true );
$mockView->shouldReceive( 'file_put_contents' )->withAnyArgs();
$util = new Encryption\Util( $mockView, $this->userId );
@@ -107,7 +127,7 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase {
$mockView = m::mock('OC_FilesystemView');
- $mockView->shouldReceive( 'file_exists' )->times(6)->andReturn( true );
+ $mockView->shouldReceive( 'file_exists' )->times(8)->andReturn( true );
$mockView->shouldReceive( 'file_put_contents' )->withAnyArgs();
$util = new Encryption\Util( $mockView, $this->userId );
@@ -141,7 +161,7 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase {
$mockView = m::mock('OC_FilesystemView');
- $mockView->shouldReceive( 'file_exists' )->times(3)->andReturn( true );
+ $mockView->shouldReceive( 'file_exists' )->times(5)->andReturn( true );
$util = new Encryption\Util( $mockView, $this->userId );
@@ -158,43 +178,57 @@ class Test_Enc_Util extends \PHPUnit_Framework_TestCase {
$util = new Encryption\Util( $this->view, $this->userId );
- $files = $util->findEncFiles( '/', 'encrypted' );
+ $files = $util->findEncFiles( '/'.$this->userId.'/');
- var_dump( $files );
+ //var_dump( $files );
# TODO: Add more tests here to check that if any of the dirs are
# then false will be returned. Use strict ordering?
}
- function testRecoveryEnabled() {
+ function testRecoveryEnabledForUser() {
$util = new Encryption\Util( $this->view, $this->userId );
// Record the value so we can return it to it's original state later
- $enabled = $util->recoveryEnabled();
+ $enabled = $util->recoveryEnabledForUser();
- $this->assertTrue( $util->setRecovery( 1 ) );
+ $this->assertTrue( $util->setRecoveryForUser( 1 ) );
- $this->assertEquals( 1, $util->recoveryEnabled() );
+ $this->assertEquals( 1, $util->recoveryEnabledForUser() );
- $this->assertTrue( $util->setRecovery( 0 ) );
+ $this->assertTrue( $util->setRecoveryForUser( 0 ) );
- $this->assertEquals( 0, $util->recoveryEnabled() );
+ $this->assertEquals( 0, $util->recoveryEnabledForUser() );
// Return the setting to it's previous state
- $this->assertTrue( $util->setRecovery( $enabled ) );
+ $this->assertTrue( $util->setRecoveryForUser( $enabled ) );
}
function testGetUidAndFilename() {
\OC_User::setUserId( 'admin' );
-
- $this->util->getUidAndFilename( 'test1.txt' );
-
-
-
+
+ $filename = 'tmp-'.time().'.test';
+
+ // Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ $this->view->file_put_contents($this->userId . '/files/' . $filename, $this->dataShort);
+
+ // Re-enable proxy - our work is done
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ $util = new Encryption\Util( $this->view, $this->userId );
+
+ list($fileOwnerUid, $file) = $util->getUidAndFilename( $filename );
+
+ $this->assertEquals('admin', $fileOwnerUid);
+
+ $this->assertEquals($file, $filename);
}
// /**
diff --git a/apps/files_encryption/test/zeros b/apps/files_encryption/tests/zeros
index ff982acf423..ff982acf423 100644
--- a/apps/files_encryption/test/zeros
+++ b/apps/files_encryption/tests/zeros
Binary files differ
diff --git a/apps/files_trashbin/l10n/bg_BG.php b/apps/files_trashbin/l10n/bg_BG.php
index 288518e1a41..31c5dcb4ef1 100644
--- a/apps/files_trashbin/l10n/bg_BG.php
+++ b/apps/files_trashbin/l10n/bg_BG.php
@@ -13,6 +13,5 @@
"{count} files" => "{count} файла",
"Nothing in here. Your trash bin is empty!" => "Няма нищо. Кофата е празна!",
"Restore" => "Възтановяване",
-"Delete" => "Изтриване",
-"Deleted Files" => "Изтрити файлове"
+"Delete" => "Изтриване"
);
diff --git a/apps/files_trashbin/l10n/id.php b/apps/files_trashbin/l10n/id.php
index 62a63d515a3..e06c66784f2 100644
--- a/apps/files_trashbin/l10n/id.php
+++ b/apps/files_trashbin/l10n/id.php
@@ -2,13 +2,13 @@
"Couldn't delete %s permanently" => "Tidak dapat menghapus permanen %s",
"Couldn't restore %s" => "Tidak dapat memulihkan %s",
"perform restore operation" => "jalankan operasi pemulihan",
-"Error" => "Galat",
+"Error" => "kesalahan",
"delete file permanently" => "hapus berkas secara permanen",
-"Delete permanently" => "Hapus secara permanen",
+"Delete permanently" => "hapus secara permanen",
"Name" => "Nama",
"Deleted" => "Dihapus",
-"1 folder" => "1 folder",
-"{count} folders" => "{count} folder",
+"1 folder" => "1 map",
+"{count} folders" => "{count} map",
"1 file" => "1 berkas",
"{count} files" => "{count} berkas",
"Nothing in here. Your trash bin is empty!" => "Tempat sampah anda kosong!",
diff --git a/apps/files_trashbin/l10n/nn_NO.php b/apps/files_trashbin/l10n/nn_NO.php
index 8166a024e58..14345ddcc4d 100644
--- a/apps/files_trashbin/l10n/nn_NO.php
+++ b/apps/files_trashbin/l10n/nn_NO.php
@@ -1,10 +1,5 @@
<?php $TRANSLATIONS = array(
"Error" => "Feil",
-"Delete permanently" => "Slett for godt",
"Name" => "Namn",
-"1 folder" => "1 mappe",
-"{count} folders" => "{count} mapper",
-"1 file" => "1 fil",
-"{count} files" => "{count} filer",
"Delete" => "Slett"
);
diff --git a/apps/files_trashbin/l10n/pl.php b/apps/files_trashbin/l10n/pl.php
index 5c9f558f11f..7fd1ab21ecd 100644
--- a/apps/files_trashbin/l10n/pl.php
+++ b/apps/files_trashbin/l10n/pl.php
@@ -8,9 +8,9 @@
"Name" => "Nazwa",
"Deleted" => "Usunięte",
"1 folder" => "1 folder",
-"{count} folders" => "Ilość folderów: {count}",
+"{count} folders" => "{count} foldery",
"1 file" => "1 plik",
-"{count} files" => "Ilość plików: {count}",
+"{count} files" => "{count} pliki",
"Nothing in here. Your trash bin is empty!" => "Nic tu nie ma. Twój kosz jest pusty!",
"Restore" => "Przywróć",
"Delete" => "Usuń",
diff --git a/apps/files_trashbin/l10n/pt_PT.php b/apps/files_trashbin/l10n/pt_PT.php
index ba85158b70e..7dfe610466b 100644
--- a/apps/files_trashbin/l10n/pt_PT.php
+++ b/apps/files_trashbin/l10n/pt_PT.php
@@ -13,6 +13,6 @@
"{count} files" => "{count} ficheiros",
"Nothing in here. Your trash bin is empty!" => "Não hà ficheiros. O lixo está vazio!",
"Restore" => "Restaurar",
-"Delete" => "Eliminar",
+"Delete" => "Apagar",
"Deleted Files" => "Ficheiros Apagados"
);
diff --git a/apps/files_trashbin/l10n/ro.php b/apps/files_trashbin/l10n/ro.php
index 3af21b7e3f3..c03ef600f35 100644
--- a/apps/files_trashbin/l10n/ro.php
+++ b/apps/files_trashbin/l10n/ro.php
@@ -1,6 +1,5 @@
<?php $TRANSLATIONS = array(
"Error" => "Eroare",
-"Delete permanently" => "Stergere permanenta",
"Name" => "Nume",
"1 folder" => "1 folder",
"{count} folders" => "{count} foldare",
diff --git a/apps/files_trashbin/l10n/sk_SK.php b/apps/files_trashbin/l10n/sk_SK.php
index 7cef36ef1c0..7203f4c75fc 100644
--- a/apps/files_trashbin/l10n/sk_SK.php
+++ b/apps/files_trashbin/l10n/sk_SK.php
@@ -5,7 +5,7 @@
"Error" => "Chyba",
"delete file permanently" => "trvalo zmazať súbor",
"Delete permanently" => "Zmazať trvalo",
-"Name" => "Názov",
+"Name" => "Meno",
"Deleted" => "Zmazané",
"1 folder" => "1 priečinok",
"{count} folders" => "{count} priečinkov",
diff --git a/apps/files_trashbin/lib/trash.php b/apps/files_trashbin/lib/trash.php
index 7fda855d0c2..70df9e2426a 100644
--- a/apps/files_trashbin/lib/trash.php
+++ b/apps/files_trashbin/lib/trash.php
@@ -29,6 +29,17 @@ class Trashbin {
// unit: percentage; 50% of available disk space/quota
const DEFAULTMAXSIZE=50;
+ public static function getUidAndFilename($filename) {
+ $uid = \OC\Files\Filesystem::getOwner($filename);
+ \OC\Files\Filesystem::initMountPoints($uid);
+ if ( $uid != \OCP\User::getUser() ) {
+ $info = \OC\Files\Filesystem::getFileInfo($filename);
+ $ownerView = new \OC\Files\View('/'.$uid.'/files');
+ $filename = $ownerView->getPath($info['fileid']);
+ }
+ return array($uid, $filename);
+ }
+
/**
* move file to the trash bin
*
@@ -62,8 +73,12 @@ class Trashbin {
if ( $trashbinSize === false || $trashbinSize < 0 ) {
$trashbinSize = self::calculateSize(new \OC\Files\View('/'. $user.'/files_trashbin'));
}
-
+
+ // disable proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
$sizeOfAddedFiles = self::copy_recursive($file_path, 'files_trashbin/files/'.$filename.'.d'.$timestamp, $view);
+ \OC_FileProxy::$enabled = $proxyStatus;
if ( $view->file_exists('files_trashbin/files/'.$filename.'.d'.$timestamp) ) {
$trashbinSize += $sizeOfAddedFiles;
@@ -110,13 +125,17 @@ class Trashbin {
\OC_FileProxy::$enabled = false;
$user = \OCP\User::getUser();
- if ($view->is_dir('files_versions/' . $file_path)) {
- $size += self::calculateSize(new \OC\Files\View('/' . $user . '/files_versions/' . $file_path));
- $view->rename('files_versions/' . $file_path, 'files_trashbin/versions/' . $filename . '.d' . $timestamp);
- } else if ($versions = \OCA\Files_Versions\Storage::getVersions($user, $file_path)) {
+ $rootView = new \OC\Files\View('/');
+
+ list($owner, $ownerPath) = self::getUidAndFilename($file_path);
+
+ if ($rootView->is_dir($owner.'/files_versions/' . $ownerPath)) {
+ $size += self::calculateSize(new \OC\Files\View('/' . $owner . '/files_versions/' . $ownerPath));
+ $rootView->rename($owner.'/files_versions/' . $ownerPath, $user.'/files_trashbin/versions/' . $filename . '.d' . $timestamp);
+ } else if ($versions = \OCA\Files_Versions\Storage::getVersions($owner, $ownerPath)) {
foreach ($versions as $v) {
- $size += $view->filesize('files_versions' . $v['path'] . '.v' . $v['version']);
- $view->rename('files_versions' . $v['path'] . '.v' . $v['version'], 'files_trashbin/versions/' . $filename . '.v' . $v['version'] . '.d' . $timestamp);
+ $size += $rootView->filesize($owner.'/files_versions' . $v['path'] . '.v' . $v['version']);
+ $rootView->rename($owner.'/files_versions' . $v['path'] . '.v' . $v['version'], $user.'/files_trashbin/versions/' . $filename . '.v' . $v['version'] . '.d' . $timestamp);
}
}
@@ -143,35 +162,38 @@ class Trashbin {
if (\OCP\App::isEnabled('files_encryption')) {
$user = \OCP\User::getUser();
+ $rootView = new \OC\Files\View('/');
+
+ list($owner, $ownerPath) = self::getUidAndFilename($file_path);
+
// disable proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
// retain key files
- $keyfile = \OC\Files\Filesystem::normalizePath('files_encryption/keyfiles/' . $file_path);
+ $keyfile = \OC\Files\Filesystem::normalizePath($owner.'/files_encryption/keyfiles/' . $ownerPath);
- if ($view->is_dir($keyfile) || $view->file_exists($keyfile . '.key')) {
- $user = \OCP\User::getUser();
+ if ($rootView->is_dir($keyfile) || $rootView->file_exists($keyfile . '.key')) {
// move keyfiles
- if ($view->is_dir($keyfile)) {
- $size += self::calculateSize(new \OC\Files\View('/' . $user . '/' . $keyfile));
- $view->rename($keyfile, 'files_trashbin/keyfiles/' . $filename . '.d' . $timestamp);
+ if ($rootView->is_dir($keyfile)) {
+ $size += self::calculateSize(new \OC\Files\View($keyfile));
+ $rootView->rename($keyfile, $user.'/files_trashbin/keyfiles/' . $filename . '.d' . $timestamp);
} else {
- $size += $view->filesize($keyfile . '.key');
- $view->rename($keyfile . '.key', 'files_trashbin/keyfiles/' . $filename . '.key.d' . $timestamp);
+ $size += $rootView->filesize($keyfile . '.key');
+ $rootView->rename($keyfile . '.key', $user.'/files_trashbin/keyfiles/' . $filename . '.key.d' . $timestamp);
}
}
// retain share keys
- $sharekeys = \OC\Files\Filesystem::normalizePath('files_encryption/share-keys/' . $file_path);
+ $sharekeys = \OC\Files\Filesystem::normalizePath($owner.'/files_encryption/share-keys/' . $ownerPath);
- if ($view->is_dir($sharekeys)) {
- $size += self::calculateSize(new \OC\Files\View('/' . $user . '/' . $sharekeys));
- $view->rename($sharekeys, 'files_trashbin/share-keys/' . $filename . '.d' . $timestamp);
+ if ($rootView->is_dir($sharekeys)) {
+ $size += self::calculateSize(new \OC\Files\View($sharekeys));
+ $rootView->rename($sharekeys, $user.'/files_trashbin/share-keys/' . $filename . '.d' . $timestamp);
} else {
// get local path to share-keys
- $localShareKeysPath = $view->getLocalFile($sharekeys);
+ $localShareKeysPath = $rootView->getLocalFile($sharekeys);
// handle share-keys
$matches = glob(preg_quote($localShareKeysPath).'*.shareKey');
@@ -186,10 +208,10 @@ class Trashbin {
if($pathinfo['basename'] == $ownerShareKey) {
// calculate size
- $size += $view->filesize($sharekeys. '.' . $user. '.shareKey');
+ $size += $rootView->filesize($sharekeys. '.' . $user. '.shareKey');
// move file
- $view->rename($sharekeys. '.' . $user. '.shareKey', 'files_trashbin/share-keys/' . $ownerShareKey . '.d' . $timestamp);
+ $rootView->rename($sharekeys. '.' . $user. '.shareKey', $user.'/files_trashbin/share-keys/' . $ownerShareKey . '.d' . $timestamp);
} else {
// calculate size
@@ -321,6 +343,12 @@ class Trashbin {
\OC_FileProxy::$enabled = false;
$user = \OCP\User::getUser();
+ $rootView = new \OC\Files\View('/');
+
+ $target = \OC\Files\Filesystem::normalizePath('/'.$location.'/'.$filename.$ext);
+
+ list($owner, $ownerPath) = self::getUidAndFilename($target);
+
if ($timestamp) {
$versionedFile = $filename;
} else {
@@ -329,15 +357,15 @@ class Trashbin {
if ($view->is_dir('/files_trashbin/versions/'.$file)) {
$size += self::calculateSize(new \OC\Files\View('/' . $user . '/' . 'files_trashbin/versions/' . $file));
- $view->rename(\OC\Files\Filesystem::normalizePath('files_trashbin/versions/' . $file), \OC\Files\Filesystem::normalizePath('files_versions/' . $location . '/' . $filename . $ext));
+ $rootView->rename(\OC\Files\Filesystem::normalizePath($user.'/files_trashbin/versions/' . $file), \OC\Files\Filesystem::normalizePath($owner.'/files_versions/' . $ownerPath));
} else if ($versions = self::getVersionsFromTrash($versionedFile, $timestamp)) {
foreach ($versions as $v) {
if ($timestamp) {
$size += $view->filesize('files_trashbin/versions/' . $versionedFile . '.v' . $v . '.d' . $timestamp);
- $view->rename('files_trashbin/versions/' . $versionedFile . '.v' . $v . '.d' . $timestamp, 'files_versions/' . $location . '/' . $filename . $ext . '.v' . $v);
+ $rootView->rename($user.'/files_trashbin/versions/' . $versionedFile . '.v' . $v . '.d' . $timestamp, $owner.'/files_versions/' . $ownerPath . '.v' . $v);
} else {
$size += $view->filesize('files_trashbin/versions/' . $versionedFile . '.v' . $v);
- $view->rename('files_trashbin/versions/' . $versionedFile . '.v' . $v, 'files_versions/' . $location . '/' . $filename . $ext . '.v' . $v);
+ $rootView->rename($user.'/files_trashbin/versions/' . $versionedFile . '.v' . $v, $owner.'/files_versions/' . $ownerPath . '.v' . $v);
}
}
}
@@ -356,7 +384,7 @@ class Trashbin {
* @param $file complete path to file
* @param $filename name of file
* @param $ext file extension in case a file with the same $filename already exists
- * @param $location location if file
+ * @param $location location of file
* @param $timestamp deleteion time
*
* @return size of restored encrypted file
@@ -366,20 +394,25 @@ class Trashbin {
$size = 0;
if (\OCP\App::isEnabled('files_encryption')) {
$user = \OCP\User::getUser();
+ $rootView = new \OC\Files\View('/');
+
+ $target = \OC\Files\Filesystem::normalizePath('/'.$location.'/'.$filename.$ext);
+
+ list($owner, $ownerPath) = self::getUidAndFilename($target);
$path_parts = pathinfo($file);
$source_location = $path_parts['dirname'];
if ($view->is_dir('/files_trashbin/keyfiles/'.$file)) {
if($source_location != '.') {
- $keyfile = \OC\Files\Filesystem::normalizePath('files_trashbin/keyfiles/' . $source_location . '/' . $filename);
- $sharekey = \OC\Files\Filesystem::normalizePath('files_trashbin/share-keys/' . $source_location . '/' . $filename);
+ $keyfile = \OC\Files\Filesystem::normalizePath($user.'/files_trashbin/keyfiles/' . $source_location . '/' . $filename);
+ $sharekey = \OC\Files\Filesystem::normalizePath($user.'/files_trashbin/share-keys/' . $source_location . '/' . $filename);
} else {
- $keyfile = \OC\Files\Filesystem::normalizePath('files_trashbin/keyfiles/' . $filename);
- $sharekey = \OC\Files\Filesystem::normalizePath('files_trashbin/share-keys/' . $filename);
+ $keyfile = \OC\Files\Filesystem::normalizePath($user.'/files_trashbin/keyfiles/' . $filename);
+ $sharekey = \OC\Files\Filesystem::normalizePath($user.'/files_trashbin/share-keys/' . $filename);
}
} else {
- $keyfile = \OC\Files\Filesystem::normalizePath('files_trashbin/keyfiles/' . $source_location . '/' . $filename . '.key');
+ $keyfile = \OC\Files\Filesystem::normalizePath($user.'/files_trashbin/keyfiles/' . $source_location . '/' . $filename . '.key');
}
if ($timestamp) {
@@ -390,35 +423,36 @@ class Trashbin {
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
- if ($view->file_exists($keyfile)) {
+ if ($rootView->file_exists($keyfile)) {
// handle directory
- if ($view->is_dir($keyfile)) {
+ if ($rootView->is_dir($keyfile)) {
// handle keyfiles
- $size += self::calculateSize(new \OC\Files\View('/' . $user . '/' . $keyfile));
- $view->rename($keyfile, 'files_encryption/keyfiles/' . $location . '/' . $filename . $ext);
+ $size += self::calculateSize(new \OC\Files\View($keyfile));
+ $rootView->rename($keyfile, $owner.'/files_encryption/keyfiles/' . $ownerPath);
// handle share-keys
if ($timestamp) {
$sharekey .= '.d' . $timestamp;
}
- $view->rename($sharekey, 'files_encryption/share-keys/' . $location . '/' . $filename . $ext);
+ $size += self::calculateSize(new \OC\Files\View($sharekey));
+ $rootView->rename($sharekey, $owner.'/files_encryption/share-keys/' . $ownerPath);
} else {
// handle keyfiles
- $size += $view->filesize($keyfile);
- $view->rename($keyfile, 'files_encryption/keyfiles/' . $location . '/' . $filename . $ext . '.key');
+ $size += $rootView->filesize($keyfile);
+ $rootView->rename($keyfile, $owner.'/files_encryption/keyfiles/' . $ownerPath . '.key');
// handle share-keys
- $ownerShareKey = \OC\Files\Filesystem::normalizePath('files_trashbin/share-keys/' . $source_location . '/' . $filename . '.' . $user. '.shareKey');
+ $ownerShareKey = \OC\Files\Filesystem::normalizePath($user.'/files_trashbin/share-keys/' . $source_location . '/' . $filename . '.' . $user. '.shareKey');
if ($timestamp) {
$ownerShareKey .= '.d' . $timestamp;
}
- $size += $view->filesize($ownerShareKey);
+ $size += $rootView->filesize($ownerShareKey);
// move only owners key
- $view->rename($ownerShareKey, 'files_encryption/share-keys/' . $location . '/' . $filename . $ext . '.' . $user. '.shareKey');
+ $rootView->rename($ownerShareKey, $owner.'/files_encryption/share-keys/' . $ownerPath . '.' . $user. '.shareKey');
// try to re-share if file is shared
$filesystemView = new \OC_FilesystemView('/');
@@ -426,7 +460,7 @@ class Trashbin {
$util = new \OCA\Encryption\Util($filesystemView, $user);
// fix the file size
- $absolutePath = \OC\Files\Filesystem::normalizePath('/' . $user . '/files/'. $location. '/' .$filename);
+ $absolutePath = \OC\Files\Filesystem::normalizePath('/' . $owner . '/files/'. $ownerPath);
$util->fixFileSize($absolutePath);
// get current sharing state
@@ -475,7 +509,25 @@ class Trashbin {
$file = $filename;
}
+ $size += self::deleteVersions($view, $file, $filename, $timestamp);
+ $size += self::deleteEncryptionKeys($view, $file, $filename, $timestamp);
+
+ if ($view->is_dir('/files_trashbin/files/'.$file)) {
+ $size += self::calculateSize(new \OC\Files\View('/'.$user.'/files_trashbin/files/'.$file));
+ } else {
+ $size += $view->filesize('/files_trashbin/files/'.$file);
+ }
+ $view->unlink('/files_trashbin/files/'.$file);
+ $trashbinSize -= $size;
+ self::setTrashbinSize($user, $trashbinSize);
+
+ return $size;
+ }
+
+ private static function deleteVersions($view, $file, $filename, $timestamp) {
+ $size = 0;
if ( \OCP\App::isEnabled('files_versions') ) {
+ $user = \OCP\User::getUser();
if ($view->is_dir('files_trashbin/versions/'.$file)) {
$size += self::calculateSize(new \OC\Files\view('/'.$user.'/files_trashbin/versions/'.$file));
$view->unlink('files_trashbin/versions/'.$file);
@@ -491,35 +543,37 @@ class Trashbin {
}
}
}
-
- // Take care of encryption keys
- $parts = pathinfo($file);
- if ( $view->is_dir('/files_trashbin/files/'.$file) ) {
- $keyfile = \OC\Files\Filesystem::normalizePath('files_trashbin/keyfiles/'.$filename);
- } else {
- $keyfile = \OC\Files\Filesystem::normalizePath('files_trashbin/keyfiles/'.$filename.'.key');
- }
- if ($timestamp) {
- $keyfile .= '.d'.$timestamp;
- }
- if ( \OCP\App::isEnabled('files_encryption') && $view->file_exists($keyfile) ) {
- if ( $view->is_dir($keyfile) ) {
- $size += self::calculateSize(new \OC\Files\View('/'.$user.'/'.$keyfile));
+ return $size;
+ }
+
+ private static function deleteEncryptionKeys($view, $file, $filename, $timestamp) {
+ $size = 0;
+ if (\OCP\App::isEnabled('files_encryption')) {
+ $user = \OCP\User::getUser();
+
+ if ($view->is_dir('/files_trashbin/files/' . $file)) {
+ $keyfile = \OC\Files\Filesystem::normalizePath('files_trashbin/keyfiles/' . $filename);
+ $sharekeys = \OC\Files\Filesystem::normalizePath('files_trashbin/share-keys/' . $filename);
} else {
- $size += $view->filesize($keyfile);
+ $keyfile = \OC\Files\Filesystem::normalizePath('files_trashbin/keyfiles/' . $filename . '.key');
+ $sharekeys = \OC\Files\Filesystem::normalizePath('files_trashbin/share-keys/' . $filename . '.' . $user . '.shareKey');
+ }
+ if ($timestamp) {
+ $keyfile .= '.d' . $timestamp;
+ $sharekeys .= '.d' . $timestamp;
+ }
+ if ($view->file_exists($keyfile)) {
+ if ($view->is_dir($keyfile)) {
+ $size += self::calculateSize(new \OC\Files\View('/' . $user . '/' . $keyfile));
+ $size += self::calculateSize(new \OC\Files\View('/' . $user . '/' . $sharekeys));
+ } else {
+ $size += $view->filesize($keyfile);
+ $size += $view->filesize($sharekeys);
+ }
+ $view->unlink($keyfile);
+ $view->unlink($sharekeys);
}
- $view->unlink($keyfile);
- }
-
- if ($view->is_dir('/files_trashbin/files/'.$file)) {
- $size += self::calculateSize(new \OC\Files\View('/'.$user.'/files_trashbin/files/'.$file));
- } else {
- $size += $view->filesize('/files_trashbin/files/'.$file);
}
- $view->unlink('/files_trashbin/files/'.$file);
- $trashbinSize -= $size;
- self::setTrashbinSize($user, $trashbinSize);
-
return $size;
}
diff --git a/tests/enable_all.php b/tests/enable_all.php
index 44af0115650..111ed0e1357 100644
--- a/tests/enable_all.php
+++ b/tests/enable_all.php
@@ -8,6 +8,7 @@
require_once __DIR__.'/../lib/base.php';
+OC_App::enable('files_encryption');
OC_App::enable('calendar');
OC_App::enable('contacts');
OC_App::enable('apptemplateadvanced');