summaryrefslogtreecommitdiffstats
path: root/apps/files_encryption
diff options
context:
space:
mode:
authorRobin Appelman <icewind@owncloud.com>2013-06-02 20:12:44 +0200
committerRobin Appelman <icewind@owncloud.com>2013-06-02 20:12:44 +0200
commit251527c6e65a5f88b56c2dbcfebb7d8dbe38d8fb (patch)
treeedcdac4b814573dad6fb8d47ce4af6f93bd7836d /apps/files_encryption
parentb7585050b565ac8f42c3afa625037adaf1a8d92c (diff)
parentcf71a54f5d6e08020a1a574d43f7fca6642776c9 (diff)
downloadnextcloud-server-251527c6e65a5f88b56c2dbcfebb7d8dbe38d8fb.tar.gz
nextcloud-server-251527c6e65a5f88b56c2dbcfebb7d8dbe38d8fb.zip
merge master into backgroundjob
Diffstat (limited to 'apps/files_encryption')
-rw-r--r--apps/files_encryption/3rdparty/Crypt_Blowfish/Blowfish.php317
-rw-r--r--apps/files_encryption/3rdparty/Crypt_Blowfish/Blowfish/DefaultKey.php327
-rw-r--r--apps/files_encryption/ajax/adminrecovery.php59
-rw-r--r--apps/files_encryption/ajax/changeRecoveryPassword.php52
-rw-r--r--apps/files_encryption/ajax/userrecovery.php41
-rw-r--r--apps/files_encryption/appinfo/app.php62
-rw-r--r--apps/files_encryption/appinfo/database.xml15
-rw-r--r--apps/files_encryption/appinfo/info.xml4
-rw-r--r--apps/files_encryption/appinfo/spec.txt60
-rw-r--r--apps/files_encryption/appinfo/version2
-rw-r--r--apps/files_encryption/css/settings-personal.css10
-rw-r--r--apps/files_encryption/hooks/hooks.php574
-rw-r--r--apps/files_encryption/js/settings-admin.js102
-rw-r--r--apps/files_encryption/js/settings-personal.js60
-rw-r--r--apps/files_encryption/js/settings.js19
-rw-r--r--apps/files_encryption/l10n/ar.php7
-rw-r--r--apps/files_encryption/l10n/bg_BG.php4
-rw-r--r--apps/files_encryption/l10n/bn_BD.php4
-rw-r--r--apps/files_encryption/l10n/ca.php7
-rw-r--r--apps/files_encryption/l10n/cs_CZ.php7
-rw-r--r--apps/files_encryption/l10n/cy_GB.php4
-rw-r--r--apps/files_encryption/l10n/da.php7
-rw-r--r--apps/files_encryption/l10n/de.php7
-rw-r--r--apps/files_encryption/l10n/de_DE.php20
-rw-r--r--apps/files_encryption/l10n/el.php7
-rw-r--r--apps/files_encryption/l10n/eo.php4
-rw-r--r--apps/files_encryption/l10n/es.php23
-rw-r--r--apps/files_encryption/l10n/es_AR.php7
-rw-r--r--apps/files_encryption/l10n/et_EE.php23
-rw-r--r--apps/files_encryption/l10n/eu.php7
-rw-r--r--apps/files_encryption/l10n/fa.php7
-rw-r--r--apps/files_encryption/l10n/fi_FI.php10
-rw-r--r--apps/files_encryption/l10n/fr.php7
-rw-r--r--apps/files_encryption/l10n/gl.php23
-rw-r--r--apps/files_encryption/l10n/he.php4
-rw-r--r--apps/files_encryption/l10n/hr.php3
-rw-r--r--apps/files_encryption/l10n/hu_HU.php7
-rw-r--r--apps/files_encryption/l10n/id.php7
-rw-r--r--apps/files_encryption/l10n/is.php4
-rw-r--r--apps/files_encryption/l10n/it.php23
-rw-r--r--apps/files_encryption/l10n/ja_JP.php23
-rw-r--r--apps/files_encryption/l10n/ka_GE.php7
-rw-r--r--apps/files_encryption/l10n/ko.php4
-rw-r--r--apps/files_encryption/l10n/ku_IQ.php4
-rw-r--r--apps/files_encryption/l10n/lb.php3
-rw-r--r--apps/files_encryption/l10n/lt_LT.php4
-rw-r--r--apps/files_encryption/l10n/lv.php7
-rw-r--r--apps/files_encryption/l10n/mk.php4
-rw-r--r--apps/files_encryption/l10n/ms_MY.php3
-rw-r--r--apps/files_encryption/l10n/nb_NO.php7
-rw-r--r--apps/files_encryption/l10n/nl.php23
-rw-r--r--apps/files_encryption/l10n/nn_NO.php3
-rw-r--r--apps/files_encryption/l10n/oc.php3
-rw-r--r--apps/files_encryption/l10n/pl.php19
-rw-r--r--apps/files_encryption/l10n/pt_BR.php23
-rw-r--r--apps/files_encryption/l10n/pt_PT.php10
-rw-r--r--apps/files_encryption/l10n/ro.php4
-rw-r--r--apps/files_encryption/l10n/ru.php19
-rw-r--r--apps/files_encryption/l10n/ru_RU.php3
-rw-r--r--apps/files_encryption/l10n/si_LK.php4
-rw-r--r--apps/files_encryption/l10n/sk_SK.php12
-rw-r--r--apps/files_encryption/l10n/sl.php7
-rw-r--r--apps/files_encryption/l10n/sr.php4
-rw-r--r--apps/files_encryption/l10n/sv.php7
-rw-r--r--apps/files_encryption/l10n/ta_LK.php4
-rw-r--r--apps/files_encryption/l10n/th_TH.php4
-rw-r--r--apps/files_encryption/l10n/tr.php7
-rw-r--r--apps/files_encryption/l10n/ug.php4
-rw-r--r--apps/files_encryption/l10n/uk.php7
-rw-r--r--apps/files_encryption/l10n/vi.php7
-rw-r--r--apps/files_encryption/l10n/zh_CN.GB2312.php4
-rw-r--r--apps/files_encryption/l10n/zh_CN.php7
-rw-r--r--apps/files_encryption/l10n/zh_HK.php5
-rw-r--r--apps/files_encryption/l10n/zh_TW.php15
-rwxr-xr-xapps/files_encryption/lib/crypt.php445
-rwxr-xr-xapps/files_encryption/lib/helper.php203
-rwxr-xr-xapps/files_encryption/lib/keymanager.php642
-rw-r--r--apps/files_encryption/lib/proxy.php648
-rw-r--r--apps/files_encryption/lib/session.php170
-rw-r--r--apps/files_encryption/lib/stream.php552
-rw-r--r--apps/files_encryption/lib/util.php1639
-rw-r--r--apps/files_encryption/settings-admin.php23
-rw-r--r--apps/files_encryption/settings-personal.php19
-rw-r--r--apps/files_encryption/settings.php21
-rw-r--r--apps/files_encryption/templates/settings-admin.php56
-rw-r--r--apps/files_encryption/templates/settings-personal.php41
-rw-r--r--apps/files_encryption/templates/settings.php20
-rwxr-xr-xapps/files_encryption/test/crypt.php667
-rw-r--r--apps/files_encryption/test/keymanager.php130
-rw-r--r--apps/files_encryption/test/legacy-encrypted-text.txtbin3360 -> 0 bytes
-rw-r--r--apps/files_encryption/test/stream.php226
-rwxr-xr-xapps/files_encryption/test/util.php225
-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.php809
-rw-r--r--apps/files_encryption/tests/encryption.keybin0 -> 24 bytes
-rw-r--r--apps/files_encryption/tests/keymanager.php245
-rw-r--r--apps/files_encryption/tests/legacy-encrypted-text.txt1
-rw-r--r--apps/files_encryption/tests/proxy.php (renamed from apps/files_encryption/test/proxy.php)2
-rwxr-xr-xapps/files_encryption/tests/share.php911
-rw-r--r--apps/files_encryption/tests/stream.php180
-rwxr-xr-xapps/files_encryption/tests/trashbin.php300
-rwxr-xr-xapps/files_encryption/tests/util.php317
-rwxr-xr-xapps/files_encryption/tests/webdav.php262
-rw-r--r--apps/files_encryption/tests/zeros (renamed from apps/files_encryption/test/zeros)bin10238 -> 10238 bytes
104 files changed, 7940 insertions, 3022 deletions
diff --git a/apps/files_encryption/3rdparty/Crypt_Blowfish/Blowfish.php b/apps/files_encryption/3rdparty/Crypt_Blowfish/Blowfish.php
new file mode 100644
index 00000000000..4ccacb963e3
--- /dev/null
+++ b/apps/files_encryption/3rdparty/Crypt_Blowfish/Blowfish.php
@@ -0,0 +1,317 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Crypt_Blowfish allows for encryption and decryption on the fly using
+ * the Blowfish algorithm. Crypt_Blowfish does not require the mcrypt
+ * PHP extension, it uses only PHP.
+ * Crypt_Blowfish support encryption/decryption with or without a secret key.
+ *
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * http://www.php.net/license/3_0.txt. If you did not receive a copy of
+ * the PHP License and are unable to obtain it through the web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category Encryption
+ * @package Crypt_Blowfish
+ * @author Matthew Fonda <mfonda@php.net>
+ * @copyright 2005 Matthew Fonda
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: Blowfish.php,v 1.81 2005/05/30 18:40:36 mfonda Exp $
+ * @link http://pear.php.net/package/Crypt_Blowfish
+ */
+
+
+require_once 'PEAR.php';
+
+
+/**
+ *
+ * Example usage:
+ * $bf = new Crypt_Blowfish('some secret key!');
+ * $encrypted = $bf->encrypt('this is some example plain text');
+ * $plaintext = $bf->decrypt($encrypted);
+ * echo "plain text: $plaintext";
+ *
+ *
+ * @category Encryption
+ * @package Crypt_Blowfish
+ * @author Matthew Fonda <mfonda@php.net>
+ * @copyright 2005 Matthew Fonda
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @link http://pear.php.net/package/Crypt_Blowfish
+ * @version @package_version@
+ * @access public
+ */
+class Crypt_Blowfish
+{
+ /**
+ * P-Array contains 18 32-bit subkeys
+ *
+ * @var array
+ * @access private
+ */
+ var $_P = array();
+
+
+ /**
+ * Array of four S-Blocks each containing 256 32-bit entries
+ *
+ * @var array
+ * @access private
+ */
+ var $_S = array();
+
+ /**
+ * Mcrypt td resource
+ *
+ * @var resource
+ * @access private
+ */
+ var $_td = null;
+
+ /**
+ * Initialization vector
+ *
+ * @var string
+ * @access private
+ */
+ var $_iv = null;
+
+
+ /**
+ * Crypt_Blowfish Constructor
+ * Initializes the Crypt_Blowfish object, and gives a sets
+ * the secret key
+ *
+ * @param string $key
+ * @access public
+ */
+ function Crypt_Blowfish($key)
+ {
+ if (extension_loaded('mcrypt')) {
+ $this->_td = mcrypt_module_open(MCRYPT_BLOWFISH, '', 'ecb', '');
+ $this->_iv = mcrypt_create_iv(8, MCRYPT_RAND);
+ }
+ $this->setKey($key);
+ }
+
+ /**
+ * Deprecated isReady method
+ *
+ * @return bool
+ * @access public
+ * @deprecated
+ */
+ function isReady()
+ {
+ return true;
+ }
+
+ /**
+ * Deprecated init method - init is now a private
+ * method and has been replaced with _init
+ *
+ * @return bool
+ * @access public
+ * @deprecated
+ * @see Crypt_Blowfish::_init()
+ */
+ function init()
+ {
+ $this->_init();
+ }
+
+ /**
+ * Initializes the Crypt_Blowfish object
+ *
+ * @access private
+ */
+ function _init()
+ {
+ $defaults = new Crypt_Blowfish_DefaultKey();
+ $this->_P = $defaults->P;
+ $this->_S = $defaults->S;
+ }
+
+ /**
+ * Enciphers a single 64 bit block
+ *
+ * @param int &$Xl
+ * @param int &$Xr
+ * @access private
+ */
+ function _encipher(&$Xl, &$Xr)
+ {
+ for ($i = 0; $i < 16; $i++) {
+ $temp = $Xl ^ $this->_P[$i];
+ $Xl = ((($this->_S[0][($temp>>24) & 255] +
+ $this->_S[1][($temp>>16) & 255]) ^
+ $this->_S[2][($temp>>8) & 255]) +
+ $this->_S[3][$temp & 255]) ^ $Xr;
+ $Xr = $temp;
+ }
+ $Xr = $Xl ^ $this->_P[16];
+ $Xl = $temp ^ $this->_P[17];
+ }
+
+
+ /**
+ * Deciphers a single 64 bit block
+ *
+ * @param int &$Xl
+ * @param int &$Xr
+ * @access private
+ */
+ function _decipher(&$Xl, &$Xr)
+ {
+ for ($i = 17; $i > 1; $i--) {
+ $temp = $Xl ^ $this->_P[$i];
+ $Xl = ((($this->_S[0][($temp>>24) & 255] +
+ $this->_S[1][($temp>>16) & 255]) ^
+ $this->_S[2][($temp>>8) & 255]) +
+ $this->_S[3][$temp & 255]) ^ $Xr;
+ $Xr = $temp;
+ }
+ $Xr = $Xl ^ $this->_P[1];
+ $Xl = $temp ^ $this->_P[0];
+ }
+
+
+ /**
+ * Encrypts a string
+ *
+ * @param string $plainText
+ * @return string Returns cipher text on success, PEAR_Error on failure
+ * @access public
+ */
+ function encrypt($plainText)
+ {
+ if (!is_string($plainText)) {
+ PEAR::raiseError('Plain text must be a string', 0, PEAR_ERROR_DIE);
+ }
+
+ if (extension_loaded('mcrypt')) {
+ return mcrypt_generic($this->_td, $plainText);
+ }
+
+ $cipherText = '';
+ $len = strlen($plainText);
+ $plainText .= str_repeat(chr(0),(8 - ($len%8))%8);
+ for ($i = 0; $i < $len; $i += 8) {
+ list(,$Xl,$Xr) = unpack("N2",substr($plainText,$i,8));
+ $this->_encipher($Xl, $Xr);
+ $cipherText .= pack("N2", $Xl, $Xr);
+ }
+ return $cipherText;
+ }
+
+
+ /**
+ * Decrypts an encrypted string
+ *
+ * @param string $cipherText
+ * @return string Returns plain text on success, PEAR_Error on failure
+ * @access public
+ */
+ function decrypt($cipherText)
+ {
+ if (!is_string($cipherText)) {
+ PEAR::raiseError('Cipher text must be a string', 1, PEAR_ERROR_DIE);
+ }
+
+ if (extension_loaded('mcrypt')) {
+ return mdecrypt_generic($this->_td, $cipherText);
+ }
+
+ $plainText = '';
+ $len = strlen($cipherText);
+ $cipherText .= str_repeat(chr(0),(8 - ($len%8))%8);
+ for ($i = 0; $i < $len; $i += 8) {
+ list(,$Xl,$Xr) = unpack("N2",substr($cipherText,$i,8));
+ $this->_decipher($Xl, $Xr);
+ $plainText .= pack("N2", $Xl, $Xr);
+ }
+ return $plainText;
+ }
+
+
+ /**
+ * Sets the secret key
+ * The key must be non-zero, and less than or equal to
+ * 56 characters in length.
+ *
+ * @param string $key
+ * @return bool Returns true on success, PEAR_Error on failure
+ * @access public
+ */
+ function setKey($key)
+ {
+ if (!is_string($key)) {
+ PEAR::raiseError('Key must be a string', 2, PEAR_ERROR_DIE);
+ }
+
+ $len = strlen($key);
+
+ if ($len > 56 || $len == 0) {
+ PEAR::raiseError('Key must be less than 56 characters and non-zero. Supplied key length: ' . $len, 3, PEAR_ERROR_DIE);
+ }
+
+ if (extension_loaded('mcrypt')) {
+ mcrypt_generic_init($this->_td, $key, $this->_iv);
+ return true;
+ }
+
+ require_once 'Blowfish/DefaultKey.php';
+ $this->_init();
+
+ $k = 0;
+ $data = 0;
+ $datal = 0;
+ $datar = 0;
+
+ for ($i = 0; $i < 18; $i++) {
+ $data = 0;
+ for ($j = 4; $j > 0; $j--) {
+ $data = $data << 8 | ord($key{$k});
+ $k = ($k+1) % $len;
+ }
+ $this->_P[$i] ^= $data;
+ }
+
+ for ($i = 0; $i <= 16; $i += 2) {
+ $this->_encipher($datal, $datar);
+ $this->_P[$i] = $datal;
+ $this->_P[$i+1] = $datar;
+ }
+ for ($i = 0; $i < 256; $i += 2) {
+ $this->_encipher($datal, $datar);
+ $this->_S[0][$i] = $datal;
+ $this->_S[0][$i+1] = $datar;
+ }
+ for ($i = 0; $i < 256; $i += 2) {
+ $this->_encipher($datal, $datar);
+ $this->_S[1][$i] = $datal;
+ $this->_S[1][$i+1] = $datar;
+ }
+ for ($i = 0; $i < 256; $i += 2) {
+ $this->_encipher($datal, $datar);
+ $this->_S[2][$i] = $datal;
+ $this->_S[2][$i+1] = $datar;
+ }
+ for ($i = 0; $i < 256; $i += 2) {
+ $this->_encipher($datal, $datar);
+ $this->_S[3][$i] = $datal;
+ $this->_S[3][$i+1] = $datar;
+ }
+
+ return true;
+ }
+
+}
+
+?>
diff --git a/apps/files_encryption/3rdparty/Crypt_Blowfish/Blowfish/DefaultKey.php b/apps/files_encryption/3rdparty/Crypt_Blowfish/Blowfish/DefaultKey.php
new file mode 100644
index 00000000000..2ff8ac788a6
--- /dev/null
+++ b/apps/files_encryption/3rdparty/Crypt_Blowfish/Blowfish/DefaultKey.php
@@ -0,0 +1,327 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Crypt_Blowfish allows for encryption and decryption on the fly using
+ * the Blowfish algorithm. Crypt_Blowfish does not require the mcrypt
+ * PHP extension, it uses only PHP.
+ * Crypt_Blowfish support encryption/decryption with or without a secret key.
+ *
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.0 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * http://www.php.net/license/3_0.txt. If you did not receive a copy of
+ * the PHP License and are unable to obtain it through the web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category Encryption
+ * @package Crypt_Blowfish
+ * @author Matthew Fonda <mfonda@php.net>
+ * @copyright 2005 Matthew Fonda
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @version CVS: $Id: DefaultKey.php,v 1.81 2005/05/30 18:40:37 mfonda Exp $
+ * @link http://pear.php.net/package/Crypt_Blowfish
+ */
+
+
+/**
+ * Class containing default key
+ *
+ * @category Encryption
+ * @package Crypt_Blowfish
+ * @author Matthew Fonda <mfonda@php.net>
+ * @copyright 2005 Matthew Fonda
+ * @license http://www.php.net/license/3_0.txt PHP License 3.0
+ * @link http://pear.php.net/package/Crypt_Blowfish
+ * @version @package_version@
+ * @access public
+ */
+class Crypt_Blowfish_DefaultKey
+{
+ var $P = array();
+
+ var $S = array();
+
+ function Crypt_Blowfish_DefaultKey()
+ {
+ $this->P = array(
+ 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344,
+ 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89,
+ 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
+ 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917,
+ 0x9216D5D9, 0x8979FB1B
+ );
+
+ $this->S = array(
+ array(
+ 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7,
+ 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99,
+ 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16,
+ 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E,
+ 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE,
+ 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013,
+ 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF,
+ 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E,
+ 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60,
+ 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440,
+ 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE,
+ 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A,
+ 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E,
+ 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677,
+ 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193,
+ 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032,
+ 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88,
+ 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239,
+ 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E,
+ 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0,
+ 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3,
+ 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98,
+ 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88,
+ 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE,
+ 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6,
+ 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D,
+ 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B,
+ 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7,
+ 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA,
+ 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463,
+ 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F,
+ 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09,
+ 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3,
+ 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB,
+ 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279,
+ 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8,
+ 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB,
+ 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82,
+ 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB,
+ 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573,
+ 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0,
+ 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B,
+ 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790,
+ 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8,
+ 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4,
+ 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0,
+ 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7,
+ 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C,
+ 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD,
+ 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1,
+ 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299,
+ 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9,
+ 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477,
+ 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF,
+ 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49,
+ 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF,
+ 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA,
+ 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5,
+ 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41,
+ 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915,
+ 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400,
+ 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915,
+ 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664,
+ 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A
+ ),
+ array(
+ 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623,
+ 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266,
+ 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1,
+ 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E,
+ 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6,
+ 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1,
+ 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E,
+ 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1,
+ 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737,
+ 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8,
+ 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF,
+ 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD,
+ 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701,
+ 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7,
+ 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41,
+ 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331,
+ 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF,
+ 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF,
+ 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E,
+ 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87,
+ 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C,
+ 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2,
+ 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16,
+ 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD,
+ 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B,
+ 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509,
+ 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E,
+ 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3,
+ 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F,
+ 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A,
+ 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4,
+ 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960,
+ 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66,
+ 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28,
+ 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802,
+ 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84,
+ 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510,
+ 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF,
+ 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14,
+ 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E,
+ 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50,
+ 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7,
+ 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8,
+ 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281,
+ 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99,
+ 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696,
+ 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128,
+ 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73,
+ 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0,
+ 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0,
+ 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105,
+ 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250,
+ 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3,
+ 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285,
+ 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00,
+ 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061,
+ 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB,
+ 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E,
+ 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735,
+ 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC,
+ 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9,
+ 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340,
+ 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20,
+ 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7
+ ),
+ array(
+ 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934,
+ 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068,
+ 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF,
+ 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840,
+ 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45,
+ 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504,
+ 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A,
+ 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB,
+ 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE,
+ 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6,
+ 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42,
+ 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B,
+ 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2,
+ 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB,
+ 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527,
+ 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B,
+ 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33,
+ 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C,
+ 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3,
+ 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC,
+ 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17,
+ 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564,
+ 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B,
+ 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115,
+ 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922,
+ 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728,
+ 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0,
+ 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E,
+ 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37,
+ 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D,
+ 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804,
+ 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B,
+ 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3,
+ 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB,
+ 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D,
+ 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C,
+ 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350,
+ 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9,
+ 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A,
+ 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE,
+ 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D,
+ 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC,
+ 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F,
+ 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61,
+ 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2,
+ 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9,
+ 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2,
+ 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C,
+ 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E,
+ 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633,
+ 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10,
+ 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169,
+ 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52,
+ 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027,
+ 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5,
+ 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62,
+ 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634,
+ 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76,
+ 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24,
+ 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC,
+ 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4,
+ 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C,
+ 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837,
+ 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0
+ ),
+ array(
+ 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B,
+ 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE,
+ 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B,
+ 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4,
+ 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8,
+ 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6,
+ 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304,
+ 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22,
+ 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4,
+ 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6,
+ 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9,
+ 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59,
+ 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593,
+ 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51,
+ 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28,
+ 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C,
+ 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B,
+ 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28,
+ 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C,
+ 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD,
+ 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A,
+ 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319,
+ 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB,
+ 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F,
+ 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991,
+ 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32,
+ 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680,
+ 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166,
+ 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE,
+ 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB,
+ 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5,
+ 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47,
+ 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370,
+ 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D,
+ 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84,
+ 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048,
+ 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8,
+ 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD,
+ 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9,
+ 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7,
+ 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38,
+ 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F,
+ 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C,
+ 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525,
+ 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1,
+ 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442,
+ 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964,
+ 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E,
+ 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8,
+ 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D,
+ 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F,
+ 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299,
+ 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02,
+ 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC,
+ 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614,
+ 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A,
+ 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6,
+ 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B,
+ 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0,
+ 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060,
+ 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E,
+ 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9,
+ 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F,
+ 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6
+ )
+ );
+ }
+
+}
+
+?>
diff --git a/apps/files_encryption/ajax/adminrecovery.php b/apps/files_encryption/ajax/adminrecovery.php
new file mode 100644
index 00000000000..6a0186d5a9b
--- /dev/null
+++ b/apps/files_encryption/ajax/adminrecovery.php
@@ -0,0 +1,59 @@
+<?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 admin settings for encrypted key recovery
+ */
+use OCA\Encryption;
+
+\OCP\JSON::checkAdminUser();
+\OCP\JSON::checkAppEnabled('files_encryption');
+\OCP\JSON::callCheck();
+
+$l = OC_L10N::get('files_encryption');
+
+$return = false;
+// Enable recoveryAdmin
+
+$recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId');
+
+if (isset($_POST['adminEnableRecovery']) && $_POST['adminEnableRecovery'] === '1') {
+
+ $return = \OCA\Encryption\Helper::adminEnableRecovery($recoveryKeyId, $_POST['recoveryPassword']);
+
+ // Return success or failure
+ if ($return) {
+ \OCP\JSON::success(array('data' => array('message' => $l->t('Recovery key successfully enabled'))));
+ } else {
+ \OCP\JSON::error(array(
+ 'data' => array(
+ 'message' => $l->t(
+ 'Could not enable recovery key. Please check your recovery key password!')
+ )
+ ));
+ }
+
+// Disable recoveryAdmin
+} elseif (
+ isset($_POST['adminEnableRecovery'])
+ && '0' === $_POST['adminEnableRecovery']
+) {
+ $return = \OCA\Encryption\Helper::adminDisableRecovery($_POST['recoveryPassword']);
+
+ // Return success or failure
+ if ($return) {
+ \OCP\JSON::success(array('data' => array('message' => $l->t('Recovery key successfully disabled'))));
+ } else {
+ \OCP\JSON::error(array(
+ 'data' => array(
+ 'message' => $l->t(
+ 'Could not disable recovery key. Please check your recovery key password!')
+ )
+ ));
+ }
+}
+
+
diff --git a/apps/files_encryption/ajax/changeRecoveryPassword.php b/apps/files_encryption/ajax/changeRecoveryPassword.php
new file mode 100644
index 00000000000..b0594f967ba
--- /dev/null
+++ b/apps/files_encryption/ajax/changeRecoveryPassword.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * Copyright (c) 2013, Bjoern Schiessle <schiessle@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or later.
+ * See the COPYING-README file.
+ *
+ * @brief Script to change recovery key password
+ *
+ */
+
+use OCA\Encryption;
+
+\OCP\JSON::checkAdminUser();
+\OCP\JSON::checkAppEnabled('files_encryption');
+\OCP\JSON::callCheck();
+
+$l = OC_L10N::get('core');
+
+$return = false;
+
+$oldPassword = $_POST['oldPassword'];
+$newPassword = $_POST['newPassword'];
+
+$util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \OCP\User::getUser());
+
+$result = $util->checkRecoveryPassword($oldPassword);
+
+if ($result) {
+ $keyId = $util->getRecoveryKeyId();
+ $keyPath = '/owncloud_private_key/' . $keyId . '.private.key';
+ $view = new \OC\Files\View('/');
+
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ $encryptedRecoveryKey = $view->file_get_contents($keyPath);
+ $decryptedRecoveryKey = \OCA\Encryption\Crypt::symmetricDecryptFileContent($encryptedRecoveryKey, $oldPassword);
+ $encryptedRecoveryKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($decryptedRecoveryKey, $newPassword);
+ $view->file_put_contents($keyPath, $encryptedRecoveryKey);
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ $return = true;
+}
+
+// success or failure
+if ($return) {
+ \OCP\JSON::success(array('data' => array('message' => $l->t('Password successfully changed.'))));
+} else {
+ \OCP\JSON::error(array('data' => array('message' => $l->t('Could not change the password. Maybe the old password was not correct.'))));
+} \ No newline at end of file
diff --git a/apps/files_encryption/ajax/userrecovery.php b/apps/files_encryption/ajax/userrecovery.php
new file mode 100644
index 00000000000..1d0f1ac2d17
--- /dev/null
+++ b/apps/files_encryption/ajax/userrecovery.php
@@ -0,0 +1,41 @@
+<?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 admin settings for encrypted key recovery
+ */
+
+use OCA\Encryption;
+
+\OCP\JSON::checkLoggedIn();
+\OCP\JSON::checkAppEnabled('files_encryption');
+\OCP\JSON::callCheck();
+
+if (
+ isset($_POST['userEnableRecovery'])
+ && (0 == $_POST['userEnableRecovery'] || '1' === $_POST['userEnableRecovery'])
+) {
+
+ $userId = \OCP\USER::getUser();
+ $view = new \OC_FilesystemView('/');
+ $util = new \OCA\Encryption\Util($view, $userId);
+
+ // Save recovery preference to DB
+ $return = $util->setRecoveryForUser($_POST['userEnableRecovery']);
+
+ if ($_POST['userEnableRecovery'] === '1') {
+ $util->addRecoveryKeys();
+ } else {
+ $util->removeRecoveryKeys();
+ }
+
+} 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/appinfo/app.php b/apps/files_encryption/appinfo/app.php
index bf16fec3aea..99bdc2c2470 100644
--- a/apps/files_encryption/appinfo/app.php
+++ b/apps/files_encryption/appinfo/app.php
@@ -8,42 +8,50 @@ 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() );
+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', 'pre_unshare', 'OCA\Encryption\Hooks', 'preUnshare' );
-OCP\Util::connectHook( 'OCP\Share', 'pre_unshareAll', 'OCA\Encryption\Hooks', 'preUnshareAll' );
+// Sharing related hooks
+OCA\Encryption\Helper::registerShareHooks();
-// Webdav-related hooks
-OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfile' );
+// Filesystem related hooks
+OCA\Encryption\Helper::registerFilesystemHooks();
-stream_wrapper_register( 'crypt', 'OCA\Encryption\Stream' );
+stream_wrapper_register('crypt', 'OCA\Encryption\Stream');
-$session = new OCA\Encryption\Session();
+// check if we are logged in
+if (OCP\User::isLoggedIn()) {
-if (
- ! $session->getPrivateKey( \OCP\USER::getUser() )
- && OCP\User::isLoggedIn()
- && OCA\Encryption\Crypt::mode() == 'server'
-) {
+ // ensure filesystem is loaded
+ if(!\OC\Files\Filesystem::$loaded) {
+ \OC_Util::setupFS();
+ }
- // Force the user to log-in again if the encryption key isn't unlocked
- // (happens when a user is logged in before the encryption app is
- // enabled)
- OCP\User::logout();
-
- header( "Location: " . OC::$WEBROOT.'/' );
-
- exit();
+ $view = new OC_FilesystemView('/');
+ $session = new \OCA\Encryption\Session($view);
+ // check if user has a private key
+ if (
+ !$session->getPrivateKey(\OCP\USER::getUser())
+ && OCA\Encryption\Crypt::mode() === 'server'
+ ) {
+
+ // Force the user to log-in again if the encryption key isn't unlocked
+ // (happens when a user is logged in before the encryption app is
+ // enabled)
+ OCP\User::logout();
+
+ header("Location: " . OC::$WEBROOT . '/');
+
+ exit();
+ }
}
// Register settings scripts
-OCP\App::registerAdmin( 'files_encryption', 'settings' );
-OCP\App::registerPersonal( 'files_encryption', 'settings-personal' );
+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 d294c35d63d..4587930da0a 100644
--- a/apps/files_encryption/appinfo/database.xml
+++ b/apps/files_encryption/appinfo/database.xml
@@ -18,6 +18,21 @@
<type>text</type>
<notnull>true</notnull>
<length>64</length>
+ <comments>What client-side / server-side configuration is used</comments>
+ </field>
+ <field>
+ <name>recovery_enabled</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ <default>0</default>
+ <comments>Whether encryption key recovery is enabled</comments>
+ </field>
+ <field>
+ <name>migration_status</name>
+ <type>integer</type>
+ <notnull>true</notnull>
+ <default>0</default>
+ <comments>Whether encryption migration has been performed</comments>
</field>
</declaration>
</table>
diff --git a/apps/files_encryption/appinfo/info.xml b/apps/files_encryption/appinfo/info.xml
index 39ea155488f..ea8f6cf6f31 100644
--- a/apps/files_encryption/appinfo/info.xml
+++ b/apps/files_encryption/appinfo/info.xml
@@ -2,9 +2,9 @@
<info>
<id>files_encryption</id>
<name>Encryption</name>
- <description>Server side encryption of files. Warning: You will lose your data if you enable this App and forget your password. Encryption is not yet compatible with LDAP.</description>
+ <description>WARNING: This is a preview release of the new ownCloud 5 encryption system. Testing and feedback is very welcome but don't use this in production yet. Encryption is not yet compatible with LDAP.</description>
<licence>AGPL</licence>
- <author>Sam Tuke</author>
+ <author>Sam Tuke, Bjoern Schiessle, Florin Peter</author>
<require>4</require>
<shipped>true</shipped>
<types>
diff --git a/apps/files_encryption/appinfo/spec.txt b/apps/files_encryption/appinfo/spec.txt
index 2d22dffe08d..ddd3983a9eb 100644
--- a/apps/files_encryption/appinfo/spec.txt
+++ b/apps/files_encryption/appinfo/spec.txt
@@ -9,6 +9,57 @@ Encrypted files
[encrypted data string][delimiter][IV][padding]
[anhAAjAmcGXqj1X9g==][00iv00][MSHU5N5gECP7aAg7][xx] (square braces added)
+
+- Directory structure:
+ - Encrypted user data (catfiles) are stored in the usual /data/user/files dir
+ - Keyfiles are stored in /data/user/files_encryption/keyfiles
+ - Sharekey are stored in /data/user/files_encryption/share-files
+
+- File extensions:
+ - Catfiles have to keep the file extension of the original file, pre-encryption
+ - Keyfiles use .keyfile
+ - Sharekeys have .shareKey
+
+Shared files
+------------
+
+Shared files have a centrally stored catfile and keyfile, and one sharekey for
+each user that shares it.
+
+When sharing is used, a different encryption method is used to encrypt the
+keyfile (openssl_seal). Although shared files have a keyfile, its contents
+use a different format therefore.
+
+Each time a shared file is edited or deleted, all sharekeys for users sharing
+that file must have their sharekeys changed also. The keyfile and catfile
+however need only changing in the owners files, as there is only one copy of
+these.
+
+Publicly shared files (public links)
+------------------------------------
+
+Files shared via public links use a separate system user account called 'ownCloud'. All public files are shared to that user's public key, and the private key is used to access the files when the public link is used in browser.
+
+This means that files shared via public links are accessible only to users who know the shared URL, or to admins who know the 'ownCloud' user password.
+
+Lost password recovery
+----------------------
+
+In order to enable users to read their encrypted files in the event of a password loss/reset scenario, administrators can choose to enable a 'recoveryAdmin' account. This is a user that all user files will automatically be shared to of the option is enabled. This allows the recoveryAdmin user to generate new keyfiles for the user. By default the UID of the recoveryAdmin is 'recoveryAdmin'.
+
+OC_FilesystemView
+-----------------
+
+files_encryption deals extensively with paths and the filesystem. In order to minimise bugs, it makes calls to filesystem methods in a consistent way: OC_FilesystemView{} objects always use '/' as their root, and specify paths each time particular methods are called. e.g. do this:
+
+$view->file_exists( 'path/to/file' );
+
+Not:
+
+$view->chroot( 'path/to' );
+$view->file_exists( 'file' );
+
+Using this convention means that $view objects are more predictable and less likely to break. Problems with paths are the #1 cause of bugs in this app, and consistent $view handling is an important way to prevent them.
Notes
-----
@@ -16,4 +67,11 @@ Notes
- The user passphrase is required in order to set up or upgrade the app. New
keypair generation, and the re-encryption of legacy encrypted files requires
it. Therefore an appinfo/update.php script cannot be used, and upgrade logic
- is handled in the login hook listener. \ No newline at end of file
+ is handled in the login hook listener. Therefore each time the user logs in
+ their files are scanned to detect unencrypted and legacy encrypted files, and
+ they are (re)encrypted as necessary. This may present a performance issue; we
+ need to monitor this.
+- When files are saved to ownCloud via WebDAV, a .part file extension is used so
+ that the file isn't cached before the upload has been completed. .part files
+ are not compatible with files_encrytion's key management system however, so
+ we have to always sanitise such paths manually before using them. \ No newline at end of file
diff --git a/apps/files_encryption/appinfo/version b/apps/files_encryption/appinfo/version
index 1d71ef97443..bd73f47072b 100644
--- a/apps/files_encryption/appinfo/version
+++ b/apps/files_encryption/appinfo/version
@@ -1 +1 @@
-0.3 \ No newline at end of file
+0.4
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 2731d5a92f7..d1b08a0b978 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
@@ -36,156 +37,489 @@ class Hooks {
* @brief Startup encryption backend upon user login
* @note This method should never be called for users using client side encryption
*/
- public static function login( $params ) {
-
+ public static function login($params) {
+
// Manually initialise Filesystem{} singleton with correct
// fake root path, in order to avoid fatal webdav errors
- \OC\Files\Filesystem::init( $params['uid'], $params['uid'] . '/' . 'files' . '/' );
-
- $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'] );
+ // NOTE: disabled because this give errors on webdav!
+ //\OC\Files\Filesystem::init( $params['uid'], '/' . 'files' . '/' );
+ $view = new \OC_FilesystemView('/');
+
+ // ensure filesystem is loaded
+ if(!\OC\Files\Filesystem::$loaded) {
+ \OC_Util::setupFS($params['uid']);
}
-
- \OC_FileProxy::$enabled = false;
-
- $encryptedKey = Keymanager::getPrivateKey( $view, $params['uid'] );
-
- \OC_FileProxy::$enabled = true;
-
- $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $params['password'] );
-
- $session = new Session();
-
- $session->setPrivateKey( $privateKey, $params['uid'] );
-
- $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 );
-
+
+ $util = new Util($view, $params['uid']);
+
+ // setup user, if user not ready force relogin
+ if (Helper::setupUser($util, $params['password']) === false) {
+ return false;
}
-
- $publicKey = Keymanager::getPublicKey( $view, $params['uid'] );
-
- // 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'] . '" started at login'
- , \OC_Log::INFO
- );
-
+
+ $encryptedKey = Keymanager::getPrivateKey($view, $params['uid']);
+
+ $privateKey = Crypt::symmetricDecryptFileContent($encryptedKey, $params['password']);
+
+ $session = new \OCA\Encryption\Session($view);
+
+ $session->setPrivateKey($privateKey, $params['uid']);
+
+ // Check if first-run file migration has already been performed
+ $migrationCompleted = $util->getMigrationStatus();
+
+ // If migration not yet done
+ if (!$migrationCompleted) {
+
+ $userView = new \OC_FilesystemView('/' . $params['uid']);
+
+ // Set legacy encryption key if it exists, to support
+ // depreciated encryption system
+ if (
+ $userView->file_exists('encryption.key')
+ && $encLegacyKey = $userView->file_get_contents('encryption.key')
+ ) {
+
+ $plainLegacyKey = Crypt::legacyBlockDecrypt($encLegacyKey, $params['password']);
+
+ $session->setLegacyKey($plainLegacyKey);
+
+ }
+
+ // Encrypt existing user files:
+ // This serves to upgrade old versions of the encryption
+ // app (see appinfo/spec.txt)
+ if (
+ $util->encryptAll('/' . $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
*/
- public static function setPassphrase( $params ) {
-
+ public static function setPassphrase($params) {
+
// Only attempt to change passphrase if server-side encryption
// is in use (client-side encryption does not have access to
// the necessary keys)
- if ( Crypt::mode() == 'server' ) {
-
- $session = new Session();
-
- // Get existing decrypted private key
- $privateKey = $session->getPrivateKey();
-
- // Encrypt private key with new user pwd as passphrase
- $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $privateKey, $params['password'] );
-
- // Save private key
- Keymanager::setPrivateKey( $encryptedPrivateKey );
-
- // NOTE: Session does not need to be updated as the
- // private key has not changed, only the passphrase
- // used to decrypt it has changed
-
+ if (Crypt::mode() === 'server') {
+
+ if ($params['uid'] === \OCP\User::getUser()) {
+
+ $view = new \OC_FilesystemView('/');
+
+ $session = new \OCA\Encryption\Session($view);
+
+ // Get existing decrypted private key
+ $privateKey = $session->getPrivateKey();
+
+ // Encrypt private key with new user pwd as passphrase
+ $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($privateKey, $params['password']);
+
+ // Save private key
+ Keymanager::setPrivateKey($encryptedPrivateKey);
+
+ // NOTE: Session does not need to be updated as the
+ // private key has not changed, only the passphrase
+ // used to decrypt it has changed
+
+
+ } else { // admin changed the password for a different user, create new keys and reencrypt file keys
+
+ $user = $params['uid'];
+ $recoveryPassword = $params['recoveryPassword'];
+ $newUserPassword = $params['password'];
+
+ $view = new \OC_FilesystemView('/');
+
+ // make sure that the users home is mounted
+ \OC\Files\Filesystem::initMountPoints($user);
+
+ $keypair = Crypt::createKeypair();
+
+ // Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ // Save public key
+ $view->file_put_contents('/public-keys/' . $user . '.public.key', $keypair['publicKey']);
+
+ // Encrypt private key empty passphrase
+ $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $newUserPassword);
+
+ // Save private key
+ $view->file_put_contents(
+ '/' . $user . '/files_encryption/' . $user . '.private.key', $encryptedPrivateKey);
+
+ if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files
+ $util = new Util($view, $user);
+ $util->recoverUsersFiles($recoveryPassword);
+ }
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+ }
}
-
}
-
+
+ /*
+ * @brief check if files can be encrypted to every user.
+ */
/**
- * @brief update the encryption key of the file uploaded by the client
+ * @param $params
*/
- public static function updateKeyfile( $params ) {
-
- if ( Crypt::mode() == 'client' ) {
-
- if ( isset( $params['properties']['key'] ) ) {
-
- $view = new \OC_FilesystemView( '/' );
- $userId = \OCP\User::getUser();
-
- Keymanager::setFileKey( $view, $params['path'], $userId, $params['properties']['key'] );
-
- } else {
-
- \OC_Log::write(
- 'Encryption library', "Client side encryption is enabled but the client doesn't provide a encryption key for the file!"
- , \OC_Log::ERROR
- );
-
- error_log( "Client side encryption is enabled but the client doesn't provide an encryption key for the file!" );
-
+ 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;
+ }
+
+ $error = false;
+ foreach ($users as $user) {
+ if (!$view->file_exists($user . '.public.key')) {
+ $error = true;
+ break;
}
-
}
-
+
+ if ($error) // 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
}
-
+
/**
- * @brief
+ * @brief
*/
- public static function postShared( $params ) {
+ public static function postShared($params) {
+
+ // NOTE: $params has keys:
+ // [itemType] => file
+ // itemSource -> int, filecache file ID
+ // [parent] =>
+ // [itemTarget] => /13
+ // shareWith -> string, uid of user being shared to
+ // fileTarget -> path of file being shared
+ // uidOwner -> owner of the original file being shared
+ // [shareType] => 0
+ // [shareWith] => test1
+ // [uidOwner] => admin
+ // [permissions] => 17
+ // [fileSource] => 13
+ // [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('/');
+ $session = new \OCA\Encryption\Session($view);
+ $userId = \OCP\User::getUser();
+ $util = new Util($view, $userId);
+ $path = $util->fileIdToPath($params['itemSource']);
+
+ $share = $util->getParentFromShare($params['id']);
+ //if parent is set, then this is a re-share action
+ if ($share['parent'] !== null) {
+
+ // 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();
+
+ // get the path including mount point only if not a shared folder
+ if(strncmp($path, '/Shared' , strlen('/Shared') !== 0)) {
+ // get path including the the storage mount point
+ $path = $util->getPathWithMountPoint($params['itemSource']);
+ }
+
+ // if a folder was shared, get a list of all (sub-)folders
+ if ($params['itemType'] === 'folder') {
+ $allFiles = $util->getAllFiles($path);
+ } else {
+ $allFiles = array($path);
+ }
+
+ foreach ($allFiles as $path) {
+ $usersSharing = $util->getSharingUsersArray($sharingEnabled, $path);
+ $util->setSharedFileKeyfiles($session, $usersSharing, $path);
+ }
+ }
}
-
+
/**
- * @brief
+ * @brief
*/
- public static function preUnshare( $params ) {
-
- // Delete existing catfile
-
- // Generate new catfile and env keys
-
- // Save env keys to user folders
+ public static function postUnshare($params) {
+
+ // NOTE: $params has keys:
+ // [itemType] => file
+ // [itemSource] => 13
+ // [shareType] => 0
+ // [shareWith] => test1
+ // [itemParent] =>
+
+ if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
+
+ $view = new \OC_FilesystemView('/');
+ $userId = \OCP\User::getUser();
+ $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) {
+ $userIds = \OC_Group::usersInGroup($params['shareWith']);
+ } else {
+ if ($params['shareType'] === \OCP\Share::SHARE_TYPE_LINK) {
+ $userIds = array($util->getPublicShareKeyId());
+ } else {
+ $userIds = array($params['shareWith']);
+ }
+ }
+
+ // get the path including mount point only if not a shared folder
+ if(strncmp($path, '/Shared' , strlen('/Shared') !== 0)) {
+ // get path including the the storage mount point
+ $path = $util->getPathWithMountPoint($params['itemSource']);
+ }
+
+ // if we unshare a folder we need a list of all (sub-)files
+ if ($params['itemType'] === 'folder') {
+ $allFiles = $util->getAllFiles( $path );
+ } else {
+ $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);
+
+ // Unshare every user who no longer has access to the file
+ $delUsers = array_diff($userIds, $sharingUsers);
+
+ // delete share key
+ Keymanager::delShareKey($view, $delUsers, $path);
+ }
+
+ }
}
-
+
/**
- * @brief
+ * @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 preUnshareAll( $params ) {
-
- trigger_error( "preUnshareAll" );
-
+ 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 \OCA\Encryption\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..7c1866445ee
--- /dev/null
+++ b/apps/files_encryption/js/settings-admin.js
@@ -0,0 +1,102 @@
+/**
+ * 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.
+ */
+
+OC.msg={
+ startSaving:function(selector){
+ $(selector)
+ .html( t('settings', 'Saving...') )
+ .removeClass('success')
+ .removeClass('error')
+ .stop(true, true)
+ .show();
+ },
+ finishedSaving:function(selector, data){
+ if( data.status === "success" ){
+ $(selector).html( data.data.message )
+ .addClass('success')
+ .stop(true, true)
+ .delay(3000)
+ .fadeOut(900);
+ }else{
+ $(selector).html( data.data.message ).addClass('error');
+ }
+ }
+};
+
+$(document).ready(function(){
+ // Trigger ajax on recoveryAdmin status change
+ var enabledStatus = $('#adminEnableRecovery').val();
+
+ $('input:password[name="recoveryPassword"]').keyup(function(event) {
+ var recoveryPassword = $( '#recoveryPassword' ).val();
+ var checkedButton = $('input:radio[name="adminEnableRecovery"]:checked').val();
+ var uncheckedValue = (1+parseInt(checkedButton)) % 2;
+ if (recoveryPassword != '' ) {
+ $('input:radio[name="adminEnableRecovery"][value="'+uncheckedValue.toString()+'"]').removeAttr("disabled");
+ } else {
+ $('input:radio[name="adminEnableRecovery"][value="'+uncheckedValue.toString()+'"]').attr("disabled", "true");
+ }
+ });
+
+ $( 'input:radio[name="adminEnableRecovery"]' ).change(
+ function() {
+ var recoveryStatus = $( this ).val();
+ var oldStatus = (1+parseInt(recoveryStatus)) % 2;
+ var recoveryPassword = $( '#recoveryPassword' ).val();
+ $.post(
+ OC.filePath( 'files_encryption', 'ajax', 'adminrecovery.php' )
+ , { adminEnableRecovery: recoveryStatus, recoveryPassword: recoveryPassword }
+ , function( result ) {
+ if (result.status === "error") {
+ OC.Notification.show(t('admin', result.data.message));
+ $('input:radio[name="adminEnableRecovery"][value="'+oldStatus.toString()+'"]').attr("checked", "true");
+ } else {
+ OC.Notification.hide();
+ if (recoveryStatus === "0") {
+ $('button:button[name="submitChangeRecoveryKey"]').attr("disabled", "true");
+ $('input:password[name="changeRecoveryPassword"]').attr("disabled", "true");
+ $('input:password[name="changeRecoveryPassword"]').val("");
+ } else {
+ $('input:password[name="changeRecoveryPassword"]').removeAttr("disabled");
+ }
+ }
+ }
+ );
+ }
+ );
+
+ // change recovery password
+
+ $('input:password[name="changeRecoveryPassword"]').keyup(function(event) {
+ var oldRecoveryPassword = $('input:password[id="oldRecoveryPassword"]').val();
+ var newRecoveryPassword = $('input:password[id="newRecoveryPassword"]').val();
+ if (newRecoveryPassword != '' && oldRecoveryPassword != '' ) {
+ $('button:button[name="submitChangeRecoveryKey"]').removeAttr("disabled");
+ } else {
+ $('button:button[name="submitChangeRecoveryKey"]').attr("disabled", "true");
+ }
+ });
+
+
+ $('button:button[name="submitChangeRecoveryKey"]').click(function() {
+ var oldRecoveryPassword = $('input:password[id="oldRecoveryPassword"]').val();
+ var newRecoveryPassword = $('input:password[id="newRecoveryPassword"]').val();
+ OC.msg.startSaving('#encryption .msg');
+ $.post(
+ OC.filePath( 'files_encryption', 'ajax', 'changeRecoveryPassword.php' )
+ , { oldPassword: oldRecoveryPassword, newPassword: newRecoveryPassword }
+ , function( data ) {
+ if (data.status == "error") {
+ OC.msg.finishedSaving('#encryption .msg', data);
+ } else {
+ OC.msg.finishedSaving('#encryption .msg', data);
+ }
+ }
+ );
+ });
+
+}); \ 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..312b672ad46
--- /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 0be857bb73e..00000000000
--- a/apps/files_encryption/js/settings.js
+++ /dev/null
@@ -1,19 +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(){
- $('#encryption_blacklist').multiSelect({
- oncheck:blackListChange,
- onuncheck:blackListChange,
- createText:'...'
- });
-
- 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/ar.php b/apps/files_encryption/l10n/ar.php
index c8a475afd67..1adc158c6b8 100644
--- a/apps/files_encryption/l10n/ar.php
+++ b/apps/files_encryption/l10n/ar.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "التشÙير",
-"File encryption is enabled." => "تشÙير الملÙات Ùعال.",
-"The following file types will not be encrypted:" => "الملÙات الاتية لن يتم تشÙيرها:",
-"Exclude the following file types from encryption:" => "إستثناء أنواع الملÙات الاتية من التشÙير: ",
-"None" => "لا شيء"
+"Saving..." => "جاري الحÙظ...",
+"Encryption" => "التشÙير"
);
diff --git a/apps/files_encryption/l10n/bg_BG.php b/apps/files_encryption/l10n/bg_BG.php
index 07a97f5f8a6..f21f7641c1a 100644
--- a/apps/files_encryption/l10n/bg_BG.php
+++ b/apps/files_encryption/l10n/bg_BG.php
@@ -1,4 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Криптиране",
-"None" => "ÐÑма"
+"Saving..." => "ЗапиÑване...",
+"Encryption" => "Криптиране"
);
diff --git a/apps/files_encryption/l10n/bn_BD.php b/apps/files_encryption/l10n/bn_BD.php
index 43767d56518..068de46e7a1 100644
--- a/apps/files_encryption/l10n/bn_BD.php
+++ b/apps/files_encryption/l10n/bn_BD.php
@@ -1,4 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "সংকেতায়ন",
-"None" => "কোনটিই নয়"
+"Saving..." => "সংরকà§à¦·à¦£ করা হচà§à¦›à§‡..",
+"Encryption" => "সংকেতায়ন"
);
diff --git a/apps/files_encryption/l10n/ca.php b/apps/files_encryption/l10n/ca.php
index 0c661353a77..46e91d1f070 100644
--- a/apps/files_encryption/l10n/ca.php
+++ b/apps/files_encryption/l10n/ca.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Encriptatge",
-"File encryption is enabled." => "L'encriptació de fitxers està activada.",
-"The following file types will not be encrypted:" => "Els tipus de fitxers següents no s'encriptaran:",
-"Exclude the following file types from encryption:" => "Exclou els tipus de fitxers següents de l'encriptatge:",
-"None" => "Cap"
+"Saving..." => "Desant...",
+"Encryption" => "Xifrat"
);
diff --git a/apps/files_encryption/l10n/cs_CZ.php b/apps/files_encryption/l10n/cs_CZ.php
index d225688a079..f9b2dd06b6f 100644
--- a/apps/files_encryption/l10n/cs_CZ.php
+++ b/apps/files_encryption/l10n/cs_CZ.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Šifrování",
-"File encryption is enabled." => "Šifrování je povoleno.",
-"The following file types will not be encrypted:" => "Následující typy souborů nebudou šifrovány:",
-"Exclude the following file types from encryption:" => "Vyjmout následující typy souborů ze šifrování:",
-"None" => "Žádné"
+"Saving..." => "Ukládám...",
+"Encryption" => "Šifrování"
);
diff --git a/apps/files_encryption/l10n/cy_GB.php b/apps/files_encryption/l10n/cy_GB.php
new file mode 100644
index 00000000000..6e18a7913c8
--- /dev/null
+++ b/apps/files_encryption/l10n/cy_GB.php
@@ -0,0 +1,4 @@
+<?php $TRANSLATIONS = array(
+"Saving..." => "Yn cadw...",
+"Encryption" => "Amgryptiad"
+);
diff --git a/apps/files_encryption/l10n/da.php b/apps/files_encryption/l10n/da.php
index b085381ea7b..1cd43390aa3 100644
--- a/apps/files_encryption/l10n/da.php
+++ b/apps/files_encryption/l10n/da.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Kryptering",
-"File encryption is enabled." => "Fil kryptering aktiveret.",
-"The following file types will not be encrypted:" => "De følgende filtyper vil ikke blive krypteret:",
-"Exclude the following file types from encryption:" => "Ekskluder de følgende fil typer fra kryptering:",
-"None" => "Ingen"
+"Saving..." => "Gemmer...",
+"Encryption" => "Kryptering"
);
diff --git a/apps/files_encryption/l10n/de.php b/apps/files_encryption/l10n/de.php
index cdcd8a40b23..2ab77f480cf 100644
--- a/apps/files_encryption/l10n/de.php
+++ b/apps/files_encryption/l10n/de.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Verschlüsselung",
-"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" => "Keine"
+"Saving..." => "Speichern...",
+"Encryption" => "Verschlüsselung"
);
diff --git a/apps/files_encryption/l10n/de_DE.php b/apps/files_encryption/l10n/de_DE.php
index 4f08b98eb29..884ed3c50b0 100644
--- a/apps/files_encryption/l10n/de_DE.php
+++ b/apps/files_encryption/l10n/de_DE.php
@@ -1,7 +1,19 @@
<?php $TRANSLATIONS = array(
+"Recovery key successfully enabled" => "Der Wiederherstellungsschlüssel wurde erfolgreich aktiviert.",
+"Could not enable recovery key. Please check your recovery key password!" => "Der Wiederherstellungsschlüssel konnte nicht aktiviert werden. Bitte überprüfen Sie das Passwort für den Wiederherstellungsschlüssel!",
+"Recovery key successfully disabled" => "Der Wiederherstellungsschlüssel wurde erfolgreich deaktiviert.",
+"Could not disable recovery key. Please check your recovery key password!" => "Der Wiederherstellungsschlüssel konnte nicht deaktiviert werden. Bitte überprüfen Sie das Passwort für den Wiederherstellungsschlüssel!",
+"Password successfully changed." => "Das Passwort wurde erfolgreich geändert.",
+"Could not change the password. Maybe the old password was not correct." => "Das Passwort konnte nicht geändert werden. Vielleicht war das alte Passwort nicht richtig.",
+"Saving..." => "Speichern...",
"Encryption" => "Verschlüsselung",
-"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" => "Keine"
+"Recovery account password" => "Account-Passwort wiederherstellen",
+"Enabled" => "Aktiviert",
+"Disabled" => "Deaktiviert",
+"Old Recovery account password" => "Altes Passwort für die Account-Wiederherstellung",
+"New Recovery account password" => "Neues Passwort für die Account-Wiederherstellung",
+"Change Password" => "Passwort ändern",
+"Enabling this option will allow you to reobtain access to your encrypted files if your password is lost" => "Durch die Aktivierung dieser Option haben Sie die Möglichkeit, wieder auf Ihre verschlüsselten Dateien zugreifen zu können, wenn Sie Ihr Passwort verloren haben.",
+"File recovery settings updated" => "Die Einstellungen für die Dateiwiederherstellung wurden aktualisiert.",
+"Could not update file recovery" => "Die Dateiwiederherstellung konnte nicht aktualisiert werden."
);
diff --git a/apps/files_encryption/l10n/el.php b/apps/files_encryption/l10n/el.php
index 0031a731944..7067799cd2e 100644
--- a/apps/files_encryption/l10n/el.php
+++ b/apps/files_encryption/l10n/el.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "ΚÏυπτογÏάφηση",
-"File encryption is enabled." => "Η κÏυπτογÏάφηση αÏχείων είναι ενεÏγή.",
-"The following file types will not be encrypted:" => "Οι παÏακάτω Ï„Ïποι αÏχείων δεν θα κÏυπτογÏαφηθοÏν:",
-"Exclude the following file types from encryption:" => "ΕξαίÏεση των παÏακάτω Ï„Ïπων αÏχείων από την κÏυπτογÏάφηση:",
-"None" => "Καμία"
+"Saving..." => "Γίνεται αποθήκευση...",
+"Encryption" => "ΚÏυπτογÏάφηση"
);
diff --git a/apps/files_encryption/l10n/eo.php b/apps/files_encryption/l10n/eo.php
index 50847062c3b..ea405fda1ab 100644
--- a/apps/files_encryption/l10n/eo.php
+++ b/apps/files_encryption/l10n/eo.php
@@ -1,4 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Ĉifrado",
-"None" => "Nenio"
+"Saving..." => "Konservante...",
+"Encryption" => "Ĉifrado"
);
diff --git a/apps/files_encryption/l10n/es.php b/apps/files_encryption/l10n/es.php
index 4ea87b92e7c..58adbd716a8 100644
--- a/apps/files_encryption/l10n/es.php
+++ b/apps/files_encryption/l10n/es.php
@@ -1,7 +1,22 @@
<?php $TRANSLATIONS = array(
+"Recovery key successfully enabled" => "Se ha habilitado la recuperación de archivos",
+"Could not enable recovery key. Please check your recovery key password!" => "No se pudo habilitar la clave de recuperación. Por favor compruebe su contraseña.",
+"Recovery key successfully disabled" => "Clave de recuperación deshabilitada",
+"Could not disable recovery key. Please check your recovery key password!" => "No se pudo deshabilitar la clave de recuperación. Por favor compruebe su contraseña!",
+"Password successfully changed." => "Su contraseña ha sido cambiada",
+"Could not change the password. Maybe the old password was not correct." => "No se pudo cambiar la contraseña. Compruebe que la contraseña actual sea correcta.",
+"Saving..." => "Guardando...",
"Encryption" => "Cifrado",
-"File encryption is enabled." => "La encriptacion de archivo esta activada.",
-"The following file types will not be encrypted:" => "Los siguientes tipos de archivo no seran encriptados:",
-"Exclude the following file types from encryption:" => "Excluir los siguientes tipos de archivo de la encriptacion:",
-"None" => "Ninguno"
+"Enable encryption passwords recovery key (allow sharing to recovery key):" => "Habilitar clave de recuperación de contraseñas ():",
+"Recovery account password" => "Recuperar contraseña",
+"Enabled" => "Habilitar",
+"Disabled" => "Deshabilitado",
+"Change encryption passwords recovery key:" => "Cambiar clave de cifrado de contraseñas:",
+"Old Recovery account password" => "Contraseña de recuperación actual",
+"New Recovery account password" => "Contraseña de recuperación nueva",
+"Change Password" => "Cambiar contraseña",
+"Enable password recovery by sharing all files with your administrator:" => "Habilitar recuperación de contraseña compartiendo todos los archivos con su administrador",
+"Enabling this option will allow you to reobtain access to your encrypted files if your password is lost" => "Habilitar esta opción para poder acceder a sus archivos cifrados si pierde su contraseña",
+"File recovery settings updated" => "Opciones de recuperación de archivos actualizada",
+"Could not update file recovery" => "No se pudo actualizar la recuperación de archivos"
);
diff --git a/apps/files_encryption/l10n/es_AR.php b/apps/files_encryption/l10n/es_AR.php
index af522879e16..857186a55fa 100644
--- a/apps/files_encryption/l10n/es_AR.php
+++ b/apps/files_encryption/l10n/es_AR.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Encriptación",
-"File encryption is enabled." => "La encriptación de archivos no está habilitada",
-"The following file types will not be encrypted:" => "Los siguientes tipos de archivos no serán encriptados",
-"Exclude the following file types from encryption:" => "Excluir los siguientes tipos de archivos de encriptación:",
-"None" => "Ninguno"
+"Saving..." => "Guardando...",
+"Encryption" => "Encriptación"
);
diff --git a/apps/files_encryption/l10n/et_EE.php b/apps/files_encryption/l10n/et_EE.php
index 0d189ac062e..e762647f782 100644
--- a/apps/files_encryption/l10n/et_EE.php
+++ b/apps/files_encryption/l10n/et_EE.php
@@ -1,7 +1,22 @@
<?php $TRANSLATIONS = array(
+"Recovery key successfully enabled" => "Taastevõtme lubamine õnnestus",
+"Could not enable recovery key. Please check your recovery key password!" => "Ei suutnud lubada taastevõtit. Palun kontrolli oma taastevõtme parooli!",
+"Recovery key successfully disabled" => "Taastevõtme keelamine õnnestus",
+"Could not disable recovery key. Please check your recovery key password!" => "Ei suuda keelata taastevõtit. Palun kontrolli oma taastevõtme parooli!",
+"Password successfully changed." => "Parool edukalt vahetatud.",
+"Could not change the password. Maybe the old password was not correct." => "Ei suutnud vahetada parooli. Võib-olla on vana parool valesti sisestatud.",
+"Saving..." => "Salvestamine...",
"Encryption" => "Krüpteerimine",
-"File encryption is enabled." => "Faili krüpteerimine on sisse lülitatud.",
-"The following file types will not be encrypted:" => "Järgnevaid failitüüpe ei krüpteerita:",
-"Exclude the following file types from encryption:" => "Järgnevaid failitüüpe ei krüpteerita:",
-"None" => "Pole"
+"Enable encryption passwords recovery key (allow sharing to recovery key):" => "Luba krüpteerimise paroolide taastevõti (võimalda parooli jagamine taastevõtmesse):",
+"Recovery account password" => "Konto taasteparool",
+"Enabled" => "Sisse lülitatud",
+"Disabled" => "Väljalülitatud",
+"Change encryption passwords recovery key:" => "Muuda taaste võtme krüpteerimise paroole:",
+"Old Recovery account password" => "Konto vana taaste parool",
+"New Recovery account password" => "Konto uus taasteparool",
+"Change Password" => "Muuda parooli",
+"Enable password recovery by sharing all files with your administrator:" => "Luba parooli taaste jagades kõik failid administraatoriga:",
+"Enabling this option will allow you to reobtain access to your encrypted files if your password is lost" => "Valiku lubamine võimaldab taastada ligipääsu krüpteeritud failidele kui parool on kadunud",
+"File recovery settings updated" => "Faili taaste seaded uuendatud",
+"Could not update file recovery" => "Ei suuda uuendada taastefaili"
);
diff --git a/apps/files_encryption/l10n/eu.php b/apps/files_encryption/l10n/eu.php
index 5a22b65728e..253953e5c52 100644
--- a/apps/files_encryption/l10n/eu.php
+++ b/apps/files_encryption/l10n/eu.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Enkriptazioa",
-"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" => "Bat ere ez"
+"Saving..." => "Gordetzen...",
+"Encryption" => "Enkriptazioa"
);
diff --git a/apps/files_encryption/l10n/fa.php b/apps/files_encryption/l10n/fa.php
index 7acf196b791..af2e36b2a83 100644
--- a/apps/files_encryption/l10n/fa.php
+++ b/apps/files_encryption/l10n/fa.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "رمزگذاری",
-"File encryption is enabled." => "رمزنگاری Ùایلها Ùعال شد.",
-"The following file types will not be encrypted:" => "Ùایلهای زیر رمزنگاری نخواهند شد:",
-"Exclude the following file types from encryption:" => "Ùایلهای زیر از رمزنگاری نادیده گرÙته Ù…ÛŒ شوند:",
-"None" => "هیچ‌کدام"
+"Saving..." => "در حال ذخیره سازی...",
+"Encryption" => "رمزگذاری"
);
diff --git a/apps/files_encryption/l10n/fi_FI.php b/apps/files_encryption/l10n/fi_FI.php
index 6352d396b3c..a00cc8ab96e 100644
--- a/apps/files_encryption/l10n/fi_FI.php
+++ b/apps/files_encryption/l10n/fi_FI.php
@@ -1,7 +1,9 @@
<?php $TRANSLATIONS = array(
+"Password successfully changed." => "Salasana vaihdettiin onnistuneesti.",
+"Could not change the password. Maybe the old password was not correct." => "Salasanan vaihto epäonnistui. Kenties vanha salasana oli väärin.",
+"Saving..." => "Tallennetaan...",
"Encryption" => "Salaus",
-"File encryption is enabled." => "Tiedostojen salaus on käytössä.",
-"The following file types will not be encrypted:" => "Seuraavia tiedostotyyppejä ei salata:",
-"Exclude the following file types from encryption:" => "Älä salaa seuravia tiedostotyyppejä:",
-"None" => "Ei mitään"
+"Enabled" => "Käytössä",
+"Disabled" => "Ei käytössä",
+"Change Password" => "Vaihda salasana"
);
diff --git a/apps/files_encryption/l10n/fr.php b/apps/files_encryption/l10n/fr.php
index 88f1e4a393f..98fb70691df 100644
--- a/apps/files_encryption/l10n/fr.php
+++ b/apps/files_encryption/l10n/fr.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Chiffrement",
-"File encryption is enabled." => "Le chiffrement des fichiers est activé",
-"The following file types will not be encrypted:" => "Les fichiers de types suivants ne seront pas chiffrés :",
-"Exclude the following file types from encryption:" => "Ne pas chiffrer les fichiers dont les types sont les suivants :",
-"None" => "Aucun"
+"Saving..." => "Enregistrement...",
+"Encryption" => "Chiffrement"
);
diff --git a/apps/files_encryption/l10n/gl.php b/apps/files_encryption/l10n/gl.php
index 3210f715453..ca93efba9aa 100644
--- a/apps/files_encryption/l10n/gl.php
+++ b/apps/files_encryption/l10n/gl.php
@@ -1,7 +1,22 @@
<?php $TRANSLATIONS = array(
+"Recovery key successfully enabled" => "Activada satisfactoriamente a chave de recuperación",
+"Could not enable recovery key. Please check your recovery key password!" => "Non foi posíbel activar a chave de recuperación. Comprobe o contrasinal da chave de recuperación!",
+"Recovery key successfully disabled" => "Desactivada satisfactoriamente a chave de recuperación",
+"Could not disable recovery key. Please check your recovery key password!" => "Non foi posíbel desactivar a chave de recuperación. Comprobe o contrasinal da chave de recuperación!",
+"Password successfully changed." => "O contrasinal foi cambiado satisfactoriamente",
+"Could not change the password. Maybe the old password was not correct." => "Non foi posíbel cambiar o contrasinal. Probabelmente o contrasinal antigo non é o correcto.",
+"Saving..." => "Gardando...",
"Encryption" => "Cifrado",
-"File encryption is enabled." => "O cifrado de ficheiros está activado",
-"The following file types will not be encrypted:" => "Os seguintes tipos de ficheiros non van seren cifrados:",
-"Exclude the following file types from encryption:" => "Excluír os seguintes tipos de ficheiros do cifrado:",
-"None" => "Ningún"
+"Enable encryption passwords recovery key (allow sharing to recovery key):" => "Activar a chave de recuperación do cifrado de contrasinais (permite compartir a chave de recuperación):",
+"Recovery account password" => "Recuperación do contrasinal da conta",
+"Enabled" => "Activado",
+"Disabled" => "Desactivado",
+"Change encryption passwords recovery key:" => "Cambiar a chave de la recuperación do cifrado de contrasinais:",
+"Old Recovery account password" => "Antigo contrasinal de recuperación da conta",
+"New Recovery account password" => "Novo contrasinal de recuperación da conta",
+"Change Password" => "Cambiar o contrasinal",
+"Enable password recovery by sharing all files with your administrator:" => "Activar a recuperación de contrasinais compartindo todos os ficheiros co administrador:",
+"Enabling this option will allow you to reobtain access to your encrypted files if your password is lost" => "Ao activar esta opción permitiráselle volver a obter acceso aos ficheiros cifrados se perde o contrasinal",
+"File recovery settings updated" => "Actualizouse o ficheiro de axustes de recuperación",
+"Could not update file recovery" => "Non foi posíbel actualizar o ficheiro de recuperación"
);
diff --git a/apps/files_encryption/l10n/he.php b/apps/files_encryption/l10n/he.php
index cbb74bfee9a..7a80cfa2f9f 100644
--- a/apps/files_encryption/l10n/he.php
+++ b/apps/files_encryption/l10n/he.php
@@ -1,4 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "הצפנה",
-"None" => "כלו×"
+"Saving..." => "שמירה…",
+"Encryption" => "הצפנה"
);
diff --git a/apps/files_encryption/l10n/hr.php b/apps/files_encryption/l10n/hr.php
new file mode 100644
index 00000000000..9b9284ddc5e
--- /dev/null
+++ b/apps/files_encryption/l10n/hr.php
@@ -0,0 +1,3 @@
+<?php $TRANSLATIONS = array(
+"Saving..." => "Spremanje..."
+);
diff --git a/apps/files_encryption/l10n/hu_HU.php b/apps/files_encryption/l10n/hu_HU.php
index 4043da108c0..bf95c31f2c5 100644
--- a/apps/files_encryption/l10n/hu_HU.php
+++ b/apps/files_encryption/l10n/hu_HU.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Titkosítás",
-"File encryption is enabled." => "Az állományok titkosítása be van kapcsolva.",
-"The following file types will not be encrypted:" => "A következő fájltípusok nem kerülnek titkosításra:",
-"Exclude the following file types from encryption:" => "Zárjuk ki a titkosításból a következő fájltípusokat:",
-"None" => "Egyik sem"
+"Saving..." => "Mentés...",
+"Encryption" => "Titkosítás"
);
diff --git a/apps/files_encryption/l10n/id.php b/apps/files_encryption/l10n/id.php
index 6044348e72e..ad827b53791 100644
--- a/apps/files_encryption/l10n/id.php
+++ b/apps/files_encryption/l10n/id.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Enkripsi",
-"File encryption is enabled." => "Enkripsi berkas aktif.",
-"The following file types will not be encrypted:" => "Tipe berkas berikut tidak akan dienkripsi:",
-"Exclude the following file types from encryption:" => "Kecualikan tipe berkas berikut dari enkripsi:",
-"None" => "Tidak ada"
+"Saving..." => "Menyimpan...",
+"Encryption" => "Enkripsi"
);
diff --git a/apps/files_encryption/l10n/is.php b/apps/files_encryption/l10n/is.php
index bd964185c45..0f98c6bd3bf 100644
--- a/apps/files_encryption/l10n/is.php
+++ b/apps/files_encryption/l10n/is.php
@@ -1,4 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Dulkóðun",
-"None" => "Ekkert"
+"Saving..." => "Er að vista ...",
+"Encryption" => "Dulkóðun"
);
diff --git a/apps/files_encryption/l10n/it.php b/apps/files_encryption/l10n/it.php
index 9ab9bc492a0..63ae4b70b44 100644
--- a/apps/files_encryption/l10n/it.php
+++ b/apps/files_encryption/l10n/it.php
@@ -1,7 +1,22 @@
<?php $TRANSLATIONS = array(
+"Recovery key successfully enabled" => "Chiave di ripristino abilitata correttamente",
+"Could not enable recovery key. Please check your recovery key password!" => "Impossibile abilitare la chiave di ripristino. Verifica la password della chiave di ripristino.",
+"Recovery key successfully disabled" => "Chiave di ripristinata disabilitata correttamente",
+"Could not disable recovery key. Please check your recovery key password!" => "Impossibile disabilitare la chiave di ripristino. Verifica la password della chiave di ripristino.",
+"Password successfully changed." => "Password modificata correttamente.",
+"Could not change the password. Maybe the old password was not correct." => "Impossibile cambiare la password. Forse la vecchia password non era corretta.",
+"Saving..." => "Salvataggio in corso...",
"Encryption" => "Cifratura",
-"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" => "Nessuna"
+"Enable encryption passwords recovery key (allow sharing to recovery key):" => "Abilita la chiave di ripristino delle password di cifratura (consente di condividere la chiave di ripristino):",
+"Recovery account password" => "Password di ripristino dell'account",
+"Enabled" => "Abilitata",
+"Disabled" => "Disabilitata",
+"Change encryption passwords recovery key:" => "Cambia la chiave di ripristino delle password di cifratura:",
+"Old Recovery account password" => "Vecchia password di ripristino dell'account",
+"New Recovery account password" => "Nuova password di ripristino dell'account",
+"Change Password" => "Modifica password",
+"Enable password recovery by sharing all files with your administrator:" => "Abilita il ripristino della password condividendo tutti i file con l'amministratore:",
+"Enabling this option will allow you to reobtain access to your encrypted files if your password is lost" => "L'abilitazione di questa opzione ti consentirà di ottenere nuovamente accesso ai tuoi file cifrati in caso di smarrimento della password",
+"File recovery settings updated" => "Impostazioni di ripristino dei file aggiornate",
+"Could not update file recovery" => "Impossibile aggiornare il ripristino dei file"
);
diff --git a/apps/files_encryption/l10n/ja_JP.php b/apps/files_encryption/l10n/ja_JP.php
index 35fba615aec..6d2d3e249c0 100644
--- a/apps/files_encryption/l10n/ja_JP.php
+++ b/apps/files_encryption/l10n/ja_JP.php
@@ -1,7 +1,22 @@
<?php $TRANSLATIONS = array(
+"Recovery key successfully enabled" => "リカãƒãƒªç”¨ã®ã‚­ãƒ¼ã¯æ­£å¸¸ã«æœ‰åŠ¹åŒ–ã•ã‚Œã¾ã—ãŸ",
+"Could not enable recovery key. Please check your recovery key password!" => "リカãƒãƒªç”¨ã®ã‚­ãƒ¼ã‚’有効ã«ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚リカãƒãƒªç”¨ã®ã‚­ãƒ¼ã®ãƒ‘スワードを確èªã—ã¦ä¸‹ã•ã„ï¼",
+"Recovery key successfully disabled" => "リカãƒãƒªç”¨ã®ã‚­ãƒ¼ã‚’正常ã«ç„¡åŠ¹åŒ–ã—ã¾ã—ãŸ",
+"Could not disable recovery key. Please check your recovery key password!" => "リカãƒãƒªç”¨ã®ã‚­ãƒ¼ã‚’無効化ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚リカãƒãƒªç”¨ã®ã‚­ãƒ¼ã®ãƒ‘スワードを確èªã—ã¦ä¸‹ã•ã„ï¼",
+"Password successfully changed." => "パスワードを変更ã§ãã¾ã—ãŸã€‚",
+"Could not change the password. Maybe the old password was not correct." => "パスワードを変更ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚å¤ã„パスワードãŒé–“é•ã£ã¦ã„ã‚‹ã‹ã‚‚ã—ã‚Œã¾ã›ã‚“。",
+"Saving..." => "ä¿å­˜ä¸­...",
"Encryption" => "æš—å·åŒ–",
-"File encryption is enabled." => "ファイルã®æš—å·åŒ–ã¯æœ‰åŠ¹ã§ã™ã€‚",
-"The following file types will not be encrypted:" => "次ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚¿ã‚¤ãƒ—ã¯æš—å·åŒ–ã•ã‚Œã¾ã›ã‚“:",
-"Exclude the following file types from encryption:" => "次ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚¿ã‚¤ãƒ—ã‚’æš—å·åŒ–ã‹ã‚‰é™¤å¤–:",
-"None" => "ãªã—"
+"Enable encryption passwords recovery key (allow sharing to recovery key):" => "æš—å·åŒ–パスワードã®å¾©æ—§ã‚­ãƒ¼ã‚’有効ã«ã™ã‚‹(復旧キーを共有ã™ã‚‹ã“ã¨ã‚’許å¯):",
+"Recovery account password" => "復旧アカウントã®ãƒ‘スワード",
+"Enabled" => "有効",
+"Disabled" => "無効",
+"Change encryption passwords recovery key:" => "復旧キーã®æš—å·åŒ–パスワードを変更:",
+"Old Recovery account password" => "å¤ã„復旧アカウントã®ãƒ‘スワード",
+"New Recovery account password" => "æ–°ã—ã„復旧アカウントã®ãƒ‘スワード",
+"Change Password" => "パスワードを変更",
+"Enable password recovery by sharing all files with your administrator:" => "管ç†è€…ãŒå…¨ã¦ã®å…±æœ‰ãƒ•ã‚¡ã‚¤ãƒ«ã«å¯¾ã—ã¦ãƒ‘スワードã«ã‚ˆã‚‹å¾©æ—§ã‚’有効ã«ã™ã‚‹:",
+"Enabling this option will allow you to reobtain access to your encrypted files if your password is lost" => "ã“ã®ã‚ªãƒ—ションを有効ã«ã™ã‚‹ã¨ã€ã‚‚ã—パスワードãŒåˆ†ã‹ã‚‰ãªããªã£ãŸã¨ã—ã¦ã‚‚ã€æš—å·åŒ–ã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ã«å†åº¦ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã“ã¨ãŒå‡ºæ¥ã‚‹ã‚ˆã†ã«ãªã‚Šã¾ã™ã€‚",
+"File recovery settings updated" => "ファイル復旧設定ãŒæ›´æ–°ã•ã‚Œã¾ã—ãŸ",
+"Could not update file recovery" => "ファイル復旧を更新ã§ãã¾ã›ã‚“ã§ã—ãŸ"
);
diff --git a/apps/files_encryption/l10n/ka_GE.php b/apps/files_encryption/l10n/ka_GE.php
index 0362c676f00..55a59f44341 100644
--- a/apps/files_encryption/l10n/ka_GE.php
+++ b/apps/files_encryption/l10n/ka_GE.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "ენკრიპციáƒ",
-"File encryption is enabled." => "ფáƒáƒ˜áƒšáƒ˜áƒ¡ ენკრიპცირჩáƒáƒ áƒ—ულიáƒ.",
-"The following file types will not be encrypted:" => "შემდეგი ფáƒáƒ˜áƒšáƒ£áƒ áƒ˜ ტიპების ენკრიპცირáƒáƒ  მáƒáƒ®áƒ“ებáƒ:",
-"Exclude the following file types from encryption:" => "áƒáƒ›áƒáƒ˜áƒ¦áƒ” შემდეგი ფáƒáƒ˜áƒšáƒ˜áƒ¡ ტიპები ენკრიპციიდáƒáƒœ:",
-"None" => "áƒáƒ áƒ"
+"Saving..." => "შენáƒáƒ®áƒ•áƒ...",
+"Encryption" => "ენკრიპციáƒ"
);
diff --git a/apps/files_encryption/l10n/ko.php b/apps/files_encryption/l10n/ko.php
index bd1580578c4..cf8149da3ab 100644
--- a/apps/files_encryption/l10n/ko.php
+++ b/apps/files_encryption/l10n/ko.php
@@ -1,4 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "암호화",
-"None" => "ì—†ìŒ"
+"Saving..." => "저장 중...",
+"Encryption" => "암호화"
);
diff --git a/apps/files_encryption/l10n/ku_IQ.php b/apps/files_encryption/l10n/ku_IQ.php
index 02c030014fa..61b720372ec 100644
--- a/apps/files_encryption/l10n/ku_IQ.php
+++ b/apps/files_encryption/l10n/ku_IQ.php
@@ -1,4 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "نهێنیکردن",
-"None" => "هیچ"
+"Saving..." => "پاشکه‌وتده‌کات...",
+"Encryption" => "نهێنیکردن"
);
diff --git a/apps/files_encryption/l10n/lb.php b/apps/files_encryption/l10n/lb.php
new file mode 100644
index 00000000000..77bad681732
--- /dev/null
+++ b/apps/files_encryption/l10n/lb.php
@@ -0,0 +1,3 @@
+<?php $TRANSLATIONS = array(
+"Saving..." => "Speicheren..."
+);
diff --git a/apps/files_encryption/l10n/lt_LT.php b/apps/files_encryption/l10n/lt_LT.php
index 67769c8f365..6bc80ff44ab 100644
--- a/apps/files_encryption/l10n/lt_LT.php
+++ b/apps/files_encryption/l10n/lt_LT.php
@@ -1,4 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Å ifravimas",
-"None" => "Nieko"
+"Saving..." => "Saugoma...",
+"Encryption" => "Å ifravimas"
);
diff --git a/apps/files_encryption/l10n/lv.php b/apps/files_encryption/l10n/lv.php
index fc31ccdb92d..04922854ceb 100644
--- a/apps/files_encryption/l10n/lv.php
+++ b/apps/files_encryption/l10n/lv.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Šifrēšana",
-"File encryption is enabled." => "Datņu šifrēšana ir aktivēta.",
-"The following file types will not be encrypted:" => "SekojoÅ¡Äs datnes netiks Å¡ifrÄ“tas:",
-"Exclude the following file types from encryption:" => "Sekojošos datņu tipus izslēgt no šifrēšanas:",
-"None" => "Nav"
+"Saving..." => "SaglabÄ...",
+"Encryption" => "Šifrēšana"
);
diff --git a/apps/files_encryption/l10n/mk.php b/apps/files_encryption/l10n/mk.php
index 513606fadc3..a7216f205ad 100644
--- a/apps/files_encryption/l10n/mk.php
+++ b/apps/files_encryption/l10n/mk.php
@@ -1,4 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Енкрипција",
-"None" => "Ðишто"
+"Saving..." => "Снимам...",
+"Encryption" => "Енкрипција"
);
diff --git a/apps/files_encryption/l10n/ms_MY.php b/apps/files_encryption/l10n/ms_MY.php
new file mode 100644
index 00000000000..bb963cb72d2
--- /dev/null
+++ b/apps/files_encryption/l10n/ms_MY.php
@@ -0,0 +1,3 @@
+<?php $TRANSLATIONS = array(
+"Saving..." => "Simpan..."
+);
diff --git a/apps/files_encryption/l10n/nb_NO.php b/apps/files_encryption/l10n/nb_NO.php
index a5e16a03421..d4e2b1ffb50 100644
--- a/apps/files_encryption/l10n/nb_NO.php
+++ b/apps/files_encryption/l10n/nb_NO.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Kryptering",
-"File encryption is enabled." => "Fil-kryptering er aktivert.",
-"The following file types will not be encrypted:" => "Følgende filtyper vil ikke bli kryptert:",
-"Exclude the following file types from encryption:" => "Ekskluder følgende filtyper fra kryptering:",
-"None" => "Ingen"
+"Saving..." => "Lagrer...",
+"Encryption" => "Kryptering"
);
diff --git a/apps/files_encryption/l10n/nl.php b/apps/files_encryption/l10n/nl.php
index b1cba96aad7..9c462917cf3 100644
--- a/apps/files_encryption/l10n/nl.php
+++ b/apps/files_encryption/l10n/nl.php
@@ -1,7 +1,22 @@
<?php $TRANSLATIONS = array(
+"Recovery key successfully enabled" => "Herstelsleutel succesvol geactiveerd",
+"Could not enable recovery key. Please check your recovery key password!" => "Kon herstelsleutel niet activeren. Controleer het wachtwoord van uw herstelsleutel!",
+"Recovery key successfully disabled" => "Herstelsleutel succesvol gedeactiveerd",
+"Could not disable recovery key. Please check your recovery key password!" => "Kon herstelsleutel niet deactiveren. Controleer het wachtwoord van uw herstelsleutel!",
+"Password successfully changed." => "Wachtwoord succesvol gewijzigd.",
+"Could not change the password. Maybe the old password was not correct." => "Kon wachtwoord niet wijzigen. Wellicht oude wachtwoord niet juist ingevoerd.",
+"Saving..." => "Opslaan",
"Encryption" => "Versleuteling",
-"File encryption is enabled." => "Bestandsversleuteling geactiveerd.",
-"The following file types will not be encrypted:" => "De volgende bestandstypen zullen niet worden versleuteld:",
-"Exclude the following file types from encryption:" => "Sluit de volgende bestandstypen uit van versleuteling:",
-"None" => "Geen"
+"Enable encryption passwords recovery key (allow sharing to recovery key):" => "Activeer versleuteling van wachtwoorden herstelsleutel (maak delen met herstel sleutel mogelijk):",
+"Recovery account password" => "Herstel account wachtwoord",
+"Enabled" => "Geactiveerd",
+"Disabled" => "Gedeactiveerd",
+"Change encryption passwords recovery key:" => "Wijzig versleuteling wachtwoord herstelsleutel",
+"Old Recovery account password" => "Oude herstel account wachtwoord",
+"New Recovery account password" => "Nieuwe herstel account wachtwoord",
+"Change Password" => "Wijzigen wachtwoord",
+"Enable password recovery by sharing all files with your administrator:" => "Activeer wachtwoordherstel door alle bestanden met uw beheerder te delen:",
+"Enabling this option will allow you to reobtain access to your encrypted files if your password is lost" => "Door deze optie te activeren kunt u toegang tot uw versleutelde bestanden krijgen als u uw wachtwoord kwijt bent",
+"File recovery settings updated" => "Bestandsherstel instellingen bijgewerkt",
+"Could not update file recovery" => "Kon bestandsherstel niet bijwerken"
);
diff --git a/apps/files_encryption/l10n/nn_NO.php b/apps/files_encryption/l10n/nn_NO.php
new file mode 100644
index 00000000000..97b3a27a9d0
--- /dev/null
+++ b/apps/files_encryption/l10n/nn_NO.php
@@ -0,0 +1,3 @@
+<?php $TRANSLATIONS = array(
+"Saving..." => "Lagrar …"
+);
diff --git a/apps/files_encryption/l10n/oc.php b/apps/files_encryption/l10n/oc.php
new file mode 100644
index 00000000000..0a34c4cda12
--- /dev/null
+++ b/apps/files_encryption/l10n/oc.php
@@ -0,0 +1,3 @@
+<?php $TRANSLATIONS = array(
+"Saving..." => "Enregistra..."
+);
diff --git a/apps/files_encryption/l10n/pl.php b/apps/files_encryption/l10n/pl.php
index 2fa86f454f9..a6f90db4cd8 100644
--- a/apps/files_encryption/l10n/pl.php
+++ b/apps/files_encryption/l10n/pl.php
@@ -1,7 +1,18 @@
<?php $TRANSLATIONS = array(
+"Password successfully changed." => "Zmiana hasła udana.",
+"Could not change the password. Maybe the old password was not correct." => "Nie można zmienić hasła. Może stare hasło nie było poprawne.",
+"Saving..." => "Zapisywanie...",
"Encryption" => "Szyfrowanie",
-"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" => "Brak"
+"Enable encryption passwords recovery key (allow sharing to recovery key):" => "Włącz szyfrowanie odzyskiwanych haseł klucza (zezwalaj na odzyskiwanie klucza):",
+"Recovery account password" => "Odzyskiwanie hasła konta",
+"Enabled" => "WÅ‚Ä…czone",
+"Disabled" => "Wyłączone",
+"Change encryption passwords recovery key:" => "Zmiana klucza szyfrowania haseł odzyskiwania:",
+"Old Recovery account password" => "Stare hasło odzyskiwania",
+"New Recovery account password" => "Nowe hasło odzyskiwania",
+"Change Password" => "Zmień hasło",
+"Enable password recovery by sharing all files with your administrator:" => "Włączyć hasło odzyskiwania przez udostępnianie wszystkich plików z administratorem:",
+"Enabling this option will allow you to reobtain access to your encrypted files if your password is lost" => "Włączenie tej opcji umożliwia otrzymać dostęp do zaszyfrowanych plików w przypadku utraty hasła",
+"File recovery settings updated" => "Ustawienia odzyskiwania plików zmienione",
+"Could not update file recovery" => "Nie można zmienić pliku odzyskiwania"
);
diff --git a/apps/files_encryption/l10n/pt_BR.php b/apps/files_encryption/l10n/pt_BR.php
index 28807db72ce..e5fa0b55cad 100644
--- a/apps/files_encryption/l10n/pt_BR.php
+++ b/apps/files_encryption/l10n/pt_BR.php
@@ -1,7 +1,22 @@
<?php $TRANSLATIONS = array(
+"Recovery key successfully enabled" => "Recuperação de chave habilitada com sucesso",
+"Could not enable recovery key. Please check your recovery key password!" => "Impossível habilitar recuperação de chave. Por favor verifique sua senha para recuperação de chave!",
+"Recovery key successfully disabled" => "Recuperação de chave desabilitada com sucesso",
+"Could not disable recovery key. Please check your recovery key password!" => "Impossível desabilitar recuperação de chave. Por favor verifique sua senha para recuperação de chave!",
+"Password successfully changed." => "Senha alterada com sucesso.",
+"Could not change the password. Maybe the old password was not correct." => "Não foi possível alterar a senha. Talvez a senha antiga não estava correta.",
+"Saving..." => "Salvando...",
"Encryption" => "Criptografia",
-"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" => "Nenhuma"
+"Enable encryption passwords recovery key (allow sharing to recovery key):" => "Ativar a criptografia de chave de recuperação de senhas (permitir compartilhar a chave de recuperação):",
+"Recovery account password" => "Recuperar a senha da conta",
+"Enabled" => "Habilidado",
+"Disabled" => "Desabilitado",
+"Change encryption passwords recovery key:" => "Mudar a criptografia de chave de recuperação de senhas:",
+"Old Recovery account password" => "Recuperação de senha de conta antiga",
+"New Recovery account password" => "Senha Nova da conta de Recuperação",
+"Change Password" => "Trocar Senha",
+"Enable password recovery by sharing all files with your administrator:" => "Habilitar recuperação de senha através da partilha de todos os arquivos com o administrador:",
+"Enabling this option will allow you to reobtain access to your encrypted files if your password is lost" => "Ativando esta opção irá permitir que você reobtainha acesso aos seus arquivos criptografados se sua senha for perdida",
+"File recovery settings updated" => "Configurações de recuperação de arquivo atualizado",
+"Could not update file recovery" => "Não foi possível atualizar a recuperação de arquivos"
);
diff --git a/apps/files_encryption/l10n/pt_PT.php b/apps/files_encryption/l10n/pt_PT.php
index 1c46011fc10..e1bb17ecaa7 100644
--- a/apps/files_encryption/l10n/pt_PT.php
+++ b/apps/files_encryption/l10n/pt_PT.php
@@ -1,7 +1,9 @@
<?php $TRANSLATIONS = array(
+"Password successfully changed." => "Password alterada com sucesso.",
+"Could not change the password. Maybe the old password was not correct." => "Não foi possivel alterar a password. Possivelmente a password antiga não está correcta.",
+"Saving..." => "A guardar...",
"Encryption" => "Encriptação",
-"File encryption is enabled." => "A encriptação de ficheiros está ligada",
-"The following file types will not be encrypted:" => "Os seguintes ficheiros não serão encriptados:",
-"Exclude the following file types from encryption:" => "Excluir da encriptação os seguintes tipos de ficheiro:",
-"None" => "Nenhum"
+"Enabled" => "Activado",
+"Disabled" => "Desactivado",
+"Change Password" => "Mudar a Password"
);
diff --git a/apps/files_encryption/l10n/ro.php b/apps/files_encryption/l10n/ro.php
index a5a6fb3cb78..9e04b627c42 100644
--- a/apps/files_encryption/l10n/ro.php
+++ b/apps/files_encryption/l10n/ro.php
@@ -1,4 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "ÃŽncriptare",
-"None" => "Niciuna"
+"Saving..." => "Se salvează...",
+"Encryption" => "ÃŽncriptare"
);
diff --git a/apps/files_encryption/l10n/ru.php b/apps/files_encryption/l10n/ru.php
index 22c1e3da374..aaf7f0997c3 100644
--- a/apps/files_encryption/l10n/ru.php
+++ b/apps/files_encryption/l10n/ru.php
@@ -1,7 +1,18 @@
<?php $TRANSLATIONS = array(
+"Password successfully changed." => "Пароль изменен удачно.",
+"Could not change the password. Maybe the old password was not correct." => "Ðевозможно изменить пароль. Возможно Ñтарый пароль не был верен.",
+"Saving..." => "Сохранение...",
"Encryption" => "Шифрование",
-"File encryption is enabled." => "Шифрование файла включено.",
-"The following file types will not be encrypted:" => "Следующие типы файлов не будут зашифрованы:",
-"Exclude the following file types from encryption:" => "ИÑключить Ñледующие типы файлов из шифрованных:",
-"None" => "Ðичего"
+"Enable encryption passwords recovery key (allow sharing to recovery key):" => "Включить шифрование Ð¿Ð°Ñ€Ð¾Ð»Ñ ÐºÐ»ÑŽÑ‡Ð° воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ (понадобитÑÑ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ðµ Ð´Ð»Ñ Ð²Ð¾ÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÐ»ÑŽÑ‡Ð°)",
+"Recovery account password" => "ВоÑÑтановление Ð¿Ð°Ñ€Ð¾Ð»Ñ ÑƒÑ‡ÐµÑ‚Ð½Ð¾Ð¹ запиÑи",
+"Enabled" => "Включено",
+"Disabled" => "Отключено",
+"Change encryption passwords recovery key:" => "Изменить шифрование Ð¿Ð°Ñ€Ð¾Ð»Ñ ÐºÐ»ÑŽÑ‡Ð° воÑÑтановлениÑ:",
+"Old Recovery account password" => "Старое ВоÑÑтановление Ð¿Ð°Ñ€Ð¾Ð»Ñ ÑƒÑ‡ÐµÑ‚Ð½Ð¾Ð¹ запиÑи",
+"New Recovery account password" => "Ðовое ВоÑÑтановление Ð¿Ð°Ñ€Ð¾Ð»Ñ ÑƒÑ‡ÐµÑ‚Ð½Ð¾Ð¹ запиÑи",
+"Change Password" => "Изменить пароль",
+"Enable password recovery by sharing all files with your administrator:" => "Включить воÑÑтановление Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð¿ÑƒÑ‚ÐµÐ¼ доÑтупа Вашего админиÑтратора ко вÑем файлам",
+"Enabling this option will allow you to reobtain access to your encrypted files if your password is lost" => "Включение Ñтой опции позволит вам получить доÑтуп к зашифрованным файлам, в Ñлучае утери паролÑ",
+"File recovery settings updated" => "ÐаÑтройки файла воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ñ‹",
+"Could not update file recovery" => "Ðевозможно обновить файл воÑÑтановлениÑ"
);
diff --git a/apps/files_encryption/l10n/ru_RU.php b/apps/files_encryption/l10n/ru_RU.php
index 7222235485c..1351f63f89b 100644
--- a/apps/files_encryption/l10n/ru_RU.php
+++ b/apps/files_encryption/l10n/ru_RU.php
@@ -1,4 +1,3 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Шифрование",
-"None" => "Ðи один"
+"Saving..." => "Сохранение"
);
diff --git a/apps/files_encryption/l10n/si_LK.php b/apps/files_encryption/l10n/si_LK.php
index d9cec4b7220..6c678bb3a4f 100644
--- a/apps/files_encryption/l10n/si_LK.php
+++ b/apps/files_encryption/l10n/si_LK.php
@@ -1,4 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "ගුප්ත කේතනය",
-"None" => "කිසිවක් නà·à¶­"
+"Saving..." => "සුරà·à¶šà·™à¶¸à·’න් පවතී...",
+"Encryption" => "ගුප්ත කේතනය"
);
diff --git a/apps/files_encryption/l10n/sk_SK.php b/apps/files_encryption/l10n/sk_SK.php
index bebb6234710..279481fbd4f 100644
--- a/apps/files_encryption/l10n/sk_SK.php
+++ b/apps/files_encryption/l10n/sk_SK.php
@@ -1,7 +1,11 @@
<?php $TRANSLATIONS = array(
+"Password successfully changed." => "Heslo úspešne zmenené.",
+"Saving..." => "Ukladám...",
"Encryption" => "Å ifrovanie",
-"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" => "Žiadne"
+"Enabled" => "Povolené",
+"Disabled" => "Zakázané",
+"Change encryption passwords recovery key:" => "ZmeniÅ¥ Å¡ifrovacie heslo obnovovacieho kľúÄa:",
+"Change Password" => "Zmeniť heslo",
+"File recovery settings updated" => "Nastavenie obnovy súborov aktualizované",
+"Could not update file recovery" => "Nemožno aktualizovať obnovenie súborov"
);
diff --git a/apps/files_encryption/l10n/sl.php b/apps/files_encryption/l10n/sl.php
index 4754e21214e..a420fe161df 100644
--- a/apps/files_encryption/l10n/sl.php
+++ b/apps/files_encryption/l10n/sl.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Å ifriranje",
-"File encryption is enabled." => "Å ifriranje datotek je omogoÄeno.",
-"The following file types will not be encrypted:" => "Navedene vrste datotek ne bodo Å¡ifrirane:",
-"Exclude the following file types from encryption:" => "Ne Å¡ifriraj navedenih vrst datotek:",
-"None" => "Brez"
+"Saving..." => "Poteka shranjevanje ...",
+"Encryption" => "Å ifriranje"
);
diff --git a/apps/files_encryption/l10n/sr.php b/apps/files_encryption/l10n/sr.php
index 91f7fc62a90..a36e37c1790 100644
--- a/apps/files_encryption/l10n/sr.php
+++ b/apps/files_encryption/l10n/sr.php
@@ -1,4 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Шифровање",
-"None" => "Ðишта"
+"Saving..." => "Чување у току...",
+"Encryption" => "Шифровање"
);
diff --git a/apps/files_encryption/l10n/sv.php b/apps/files_encryption/l10n/sv.php
index e214a937a1d..966963b5549 100644
--- a/apps/files_encryption/l10n/sv.php
+++ b/apps/files_encryption/l10n/sv.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Kryptering",
-"File encryption is enabled." => "Filkryptering är aktiverat.",
-"The following file types will not be encrypted:" => "Följande filtyper kommer inte att krypteras:",
-"Exclude the following file types from encryption:" => "Exkludera följande filtyper från kryptering:",
-"None" => "Ingen"
+"Saving..." => "Sparar...",
+"Encryption" => "Kryptering"
);
diff --git a/apps/files_encryption/l10n/ta_LK.php b/apps/files_encryption/l10n/ta_LK.php
index 152e631d0fc..63fe9ecde86 100644
--- a/apps/files_encryption/l10n/ta_LK.php
+++ b/apps/files_encryption/l10n/ta_LK.php
@@ -1,4 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "மறைகà¯à®•à¯à®±à®¿à®¯à¯€à®Ÿà¯",
-"None" => "ஒனà¯à®±à¯à®®à®¿à®²à¯à®²à¯ˆ"
+"Saving..." => "சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯...",
+"Encryption" => "மறைகà¯à®•à¯à®±à®¿à®¯à¯€à®Ÿà¯"
);
diff --git a/apps/files_encryption/l10n/th_TH.php b/apps/files_encryption/l10n/th_TH.php
index e46d2491186..6cab4370ccf 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" => "ไม่ต้อง"
+"Saving..." => "à¸à¸³à¸¥à¸±à¸‡à¸šà¸±à¸™à¸—ึà¸à¸‚้อมูล...",
+"Encryption" => "à¸à¸²à¸£à¹€à¸‚้ารหัส"
);
diff --git a/apps/files_encryption/l10n/tr.php b/apps/files_encryption/l10n/tr.php
index 6b42c757e65..917ff0a0eae 100644
--- a/apps/files_encryption/l10n/tr.php
+++ b/apps/files_encryption/l10n/tr.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Åžifreleme",
-"File encryption is enabled." => "Dosya ÅŸifreleme aktif.",
-"The following file types will not be encrypted:" => "Belirtilen dosya tipleri ÅŸifrelenmeyecek:",
-"Exclude the following file types from encryption:" => "Seçilen dosya tiplerini şifreleme:",
-"None" => "Hiçbiri"
+"Saving..." => "Kaydediliyor...",
+"Encryption" => "Åžifreleme"
);
diff --git a/apps/files_encryption/l10n/ug.php b/apps/files_encryption/l10n/ug.php
new file mode 100644
index 00000000000..954d95b4132
--- /dev/null
+++ b/apps/files_encryption/l10n/ug.php
@@ -0,0 +1,4 @@
+<?php $TRANSLATIONS = array(
+"Saving..." => "ساقلاۋاتىدۇ…",
+"Encryption" => "شىÙىرلاش"
+);
diff --git a/apps/files_encryption/l10n/uk.php b/apps/files_encryption/l10n/uk.php
index d4957141191..1c176a39142 100644
--- a/apps/files_encryption/l10n/uk.php
+++ b/apps/files_encryption/l10n/uk.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "ШифруваннÑ",
-"File encryption is enabled." => "Увімкнуто ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñ–Ð².",
-"The following file types will not be encrypted:" => "Такі типи файлів шифруватиÑÑŒ не будуть:",
-"Exclude the following file types from encryption:" => "Виключити наÑтупні типи файлів з ​​шифруваннÑ:",
-"None" => "Жоден"
+"Saving..." => "Зберігаю...",
+"Encryption" => "ШифруваннÑ"
);
diff --git a/apps/files_encryption/l10n/vi.php b/apps/files_encryption/l10n/vi.php
index 0a88d1b2db6..0af5bdc9a67 100644
--- a/apps/files_encryption/l10n/vi.php
+++ b/apps/files_encryption/l10n/vi.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "Mã hóa",
-"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 có gì hết"
+"Saving..." => "Äang lÆ°u...",
+"Encryption" => "Mã hóa"
);
diff --git a/apps/files_encryption/l10n/zh_CN.GB2312.php b/apps/files_encryption/l10n/zh_CN.GB2312.php
index 12d903e6567..3c405a81ace 100644
--- a/apps/files_encryption/l10n/zh_CN.GB2312.php
+++ b/apps/files_encryption/l10n/zh_CN.GB2312.php
@@ -1,4 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "加密",
-"None" => "æ— "
+"Saving..." => "ä¿å­˜ä¸­...",
+"Encryption" => "加密"
);
diff --git a/apps/files_encryption/l10n/zh_CN.php b/apps/files_encryption/l10n/zh_CN.php
index 13fa95203e4..e565fce801c 100644
--- a/apps/files_encryption/l10n/zh_CN.php
+++ b/apps/files_encryption/l10n/zh_CN.php
@@ -1,7 +1,4 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "加密",
-"File encryption is enabled." => "文件加密已å¯ç”¨.",
-"The following file types will not be encrypted:" => "如下的文件类型将ä¸ä¼šè¢«åŠ å¯†:",
-"Exclude the following file types from encryption:" => "从加密中排除如下的文件类型:",
-"None" => "æ— "
+"Saving..." => "ä¿å­˜ä¸­",
+"Encryption" => "加密"
);
diff --git a/apps/files_encryption/l10n/zh_HK.php b/apps/files_encryption/l10n/zh_HK.php
index 0c0b709fdc1..0a38a2ddf85 100644
--- a/apps/files_encryption/l10n/zh_HK.php
+++ b/apps/files_encryption/l10n/zh_HK.php
@@ -1,6 +1,3 @@
<?php $TRANSLATIONS = array(
-"Encryption" => "加密",
-"File encryption is enabled." => "檔案加密已開啟",
-"The following file types will not be encrypted:" => "以下文件類別將ä¸æœƒè¢«åŠ å¯†",
-"None" => "空"
+"Encryption" => "加密"
);
diff --git a/apps/files_encryption/l10n/zh_TW.php b/apps/files_encryption/l10n/zh_TW.php
index 95e61b45dc2..faea3f54a18 100644
--- a/apps/files_encryption/l10n/zh_TW.php
+++ b/apps/files_encryption/l10n/zh_TW.php
@@ -1,7 +1,14 @@
<?php $TRANSLATIONS = array(
+"Password successfully changed." => "æˆåŠŸè®Šæ›´å¯†ç¢¼ã€‚",
+"Could not change the password. Maybe the old password was not correct." => "無法變更密碼,或許是輸入的舊密碼ä¸æ­£ç¢ºã€‚",
+"Saving..." => "儲存中...",
"Encryption" => "加密",
-"File encryption is enabled." => "檔案加密已被啟用",
-"The following file types will not be encrypted:" => "以下的文件類型ä¸æœƒè¢«åŠ å¯†ï¼š",
-"Exclude the following file types from encryption:" => "從加密中排除的檔案類型:",
-"None" => "ç„¡"
+"Enabled" => "已啓用",
+"Disabled" => "å·²åœç”¨",
+"Change encryption passwords recovery key:" => "變更加密密碼還原金鑰:",
+"Change Password" => "變更密碼",
+"Enable password recovery by sharing all files with your administrator:" => "與管ç†å“¡åˆ†äº«æ‰€æœ‰æª”案以啓用密碼還原功能:",
+"Enabling this option will allow you to reobtain access to your encrypted files if your password is lost" => "啓用此é¸é …å…許您未來éºå¤±å¯†ç¢¼æ™‚é‡æ–°å–得已加密的檔案",
+"File recovery settings updated" => "檔案還原設定已更新",
+"Could not update file recovery" => "無法更新檔案還原設定"
);
diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php
index 437a18669e5..ddeb3590f60 100755
--- a/apps/files_encryption/lib/crypt.php
+++ b/apps/files_encryption/lib/crypt.php
@@ -25,13 +25,8 @@
namespace OCA\Encryption;
-require_once 'Crypt_Blowfish/Blowfish.php';
-
-// Todo:
-// - Add a setting "Don´t encrypt files larger than xx because of performance"
-// - Don't use a password directly as encryption key. but a key which is
-// stored on the server and encrypted with the user password. -> change pass
-// faster
+//require_once '../3rdparty/Crypt_Blowfish/Blowfish.php';
+require_once realpath(dirname(__FILE__) . '/../3rdparty/Crypt_Blowfish/Blowfish.php');
/**
* Class for common cryptography functionality
@@ -41,10 +36,10 @@ class Crypt {
/**
* @brief return encryption mode client or server side encryption
- * @param string user name (use system wide setting if name=null)
+ * @param string $user name (use system wide setting if name=null)
* @return string 'client' or 'server'
*/
- public static function mode( $user = null ) {
+ public static function mode($user = null) {
return 'server';
@@ -56,30 +51,33 @@ class Crypt {
*/
public static function createKeypair() {
- $res = openssl_pkey_new();
+ $res = openssl_pkey_new(array('private_key_bits' => 4096));
// Get private key
- openssl_pkey_export( $res, $privateKey );
+ openssl_pkey_export($res, $privateKey);
// Get public key
- $publicKey = openssl_pkey_get_details( $res );
+ $publicKey = openssl_pkey_get_details($res);
$publicKey = $publicKey['key'];
- return( array( 'publicKey' => $publicKey, 'privateKey' => $privateKey ) );
+ return (array(
+ 'publicKey' => $publicKey,
+ 'privateKey' => $privateKey
+ ));
}
/**
* @brief Add arbitrary padding to encrypted data
* @param string $data data to be padded
- * @return padded data
+ * @return string padded data
* @note In order to end up with data exactly 8192 bytes long we must
* add two letters. It is impossible to achieve exactly 8192 length
* blocks with encryption alone, hence padding is added to achieve the
* required length.
*/
- public static function addPadding( $data ) {
+ public static function addPadding($data) {
$padded = $data . 'xx';
@@ -90,13 +88,13 @@ class Crypt {
/**
* @brief Remove arbitrary padding to encrypted data
* @param string $padded padded data to remove padding from
- * @return unpadded data on success, false on error
+ * @return string unpadded data on success, false on error
*/
- public static function removePadding( $padded ) {
+ public static function removePadding($padded) {
- if ( substr( $padded, -2 ) == 'xx' ) {
+ if (substr($padded, -2) === 'xx') {
- $data = substr( $padded, 0, -2 );
+ $data = substr($padded, 0, -2);
return $data;
@@ -111,29 +109,30 @@ class Crypt {
/**
* @brief Check if a file's contents contains an IV and is symmetrically encrypted
- * @return true / false
+ * @param $content
+ * @return boolean
* @note see also OCA\Encryption\Util->isEncryptedPath()
*/
- public static function isCatfile( $content ) {
+ public static function isCatfileContent($content) {
- if ( !$content ) {
+ if (!$content) {
return false;
}
- $noPadding = self::removePadding( $content );
+ $noPadding = self::removePadding($content);
// Fetch encryption metadata from end of file
- $meta = substr( $noPadding, -22 );
+ $meta = substr($noPadding, -22);
// Fetch IV from end of file
- $iv = substr( $meta, -16 );
+ $iv = substr($meta, -16);
// Fetch identifier from start of metadata
- $identifier = substr( $meta, 0, 6 );
+ $identifier = substr($meta, 0, 6);
- if ( $identifier == '00iv00') {
+ if ($identifier === '00iv00') {
return true;
@@ -150,36 +149,36 @@ class Crypt {
* @param string $path
* @return bool
*/
- public static function isEncryptedMeta( $path ) {
+ public static function isEncryptedMeta($path) {
// TODO: Use DI to get \OC\Files\Filesystem out of here
// Fetch all file metadata from DB
- $metadata = \OC\Files\Filesystem::getFileInfo( $path, '' );
+ $metadata = \OC\Files\Filesystem::getFileInfo($path);
// Return encryption status
- return isset( $metadata['encrypted'] ) and ( bool )$metadata['encrypted'];
+ return isset($metadata['encrypted']) && ( bool )$metadata['encrypted'];
}
/**
* @brief Check if a file is encrypted via legacy system
+ * @param $data
* @param string $relPath The path of the file, relative to user/data;
* e.g. filename or /Docs/filename, NOT admin/files/filename
- * @return true / false
+ * @return boolean
*/
- public static function isLegacyEncryptedContent( $data, $relPath ) {
+ public static function isLegacyEncryptedContent($data, $relPath) {
// Fetch all file metadata from DB
- $metadata = \OC\Files\Filesystem::getFileInfo( $relPath, '' );
+ $metadata = \OC\Files\Filesystem::getFileInfo($relPath, '');
// If a file is flagged with encryption in DB, but isn't a
// valid content + IV combination, it's probably using the
// legacy encryption system
- if (
- isset( $metadata['encrypted'] )
- and $metadata['encrypted'] === true
- and ! self::isCatfile( $data )
+ if (isset($metadata['encrypted'])
+ && $metadata['encrypted'] === true
+ && !self::isCatfileContent($data)
) {
return true;
@@ -194,17 +193,20 @@ class Crypt {
/**
* @brief Symmetrically encrypt a string
- * @returns encrypted file
+ * @param $plainContent
+ * @param $iv
+ * @param string $passphrase
+ * @return string encrypted file content
*/
- public static function encrypt( $plainContent, $iv, $passphrase = '' ) {
+ public static function encrypt($plainContent, $iv, $passphrase = '') {
- if ( $encryptedContent = openssl_encrypt( $plainContent, 'AES-128-CFB', $passphrase, false, $iv ) ) {
+ if ($encryptedContent = openssl_encrypt($plainContent, 'AES-128-CFB', $passphrase, false, $iv)) {
return $encryptedContent;
} else {
- \OC_Log::write( 'Encryption library', 'Encryption (symmetric) of content failed', \OC_Log::ERROR );
+ \OCP\Util::writeLog('Encryption library', 'Encryption (symmetric) of content failed', \OCP\Util::ERROR);
return false;
@@ -214,18 +216,21 @@ class Crypt {
/**
* @brief Symmetrically decrypt a string
- * @returns decrypted file
+ * @param $encryptedContent
+ * @param $iv
+ * @param $passphrase
+ * @throws \Exception
+ * @return string decrypted file content
*/
- public static function decrypt( $encryptedContent, $iv, $passphrase ) {
+ public static function decrypt($encryptedContent, $iv, $passphrase) {
- if ( $plainContent = openssl_decrypt( $encryptedContent, 'AES-128-CFB', $passphrase, false, $iv ) ) {
+ if ($plainContent = openssl_decrypt($encryptedContent, 'AES-128-CFB', $passphrase, false, $iv)) {
return $plainContent;
-
} else {
- throw new \Exception( 'Encryption library: Decryption (symmetric) of content failed' );
+ throw new \Exception('Encryption library: Decryption (symmetric) of content failed');
}
@@ -237,7 +242,7 @@ class Crypt {
* @param string $iv IV to be concatenated
* @returns string concatenated content
*/
- public static function concatIv ( $content, $iv ) {
+ public static function concatIv($content, $iv) {
$combined = $content . '00iv00' . $iv;
@@ -250,20 +255,20 @@ class Crypt {
* @param string $catFile concatenated data to be split
* @returns array keys: encrypted, iv
*/
- public static function splitIv ( $catFile ) {
+ public static function splitIv($catFile) {
// Fetch encryption metadata from end of file
- $meta = substr( $catFile, -22 );
+ $meta = substr($catFile, -22);
// Fetch IV from end of file
- $iv = substr( $meta, -16 );
+ $iv = substr($meta, -16);
// Remove IV and IV identifier text to expose encrypted content
- $encrypted = substr( $catFile, 0, -22 );
+ $encrypted = substr($catFile, 0, -22);
$split = array(
- 'encrypted' => $encrypted
- , 'iv' => $iv
+ 'encrypted' => $encrypted,
+ 'iv' => $iv
);
return $split;
@@ -272,14 +277,16 @@ class Crypt {
/**
* @brief Symmetrically encrypts a string and returns keyfile content
- * @param $plainContent content to be encrypted in keyfile
- * @returns encrypted content combined with IV
+ * @param string $plainContent content to be encrypted in keyfile
+ * @param string $passphrase
+ * @return bool|string
+ * @return string encrypted content combined with IV
* @note IV need not be specified, as it will be stored in the returned keyfile
* and remain accessible therein.
*/
- public static function symmetricEncryptFileContent( $plainContent, $passphrase = '' ) {
+ public static function symmetricEncryptFileContent($plainContent, $passphrase = '') {
- if ( !$plainContent ) {
+ if (!$plainContent) {
return false;
@@ -287,18 +294,18 @@ class Crypt {
$iv = self::generateIv();
- if ( $encryptedContent = self::encrypt( $plainContent, $iv, $passphrase ) ) {
+ if ($encryptedContent = self::encrypt($plainContent, $iv, $passphrase)) {
// Combine content to encrypt with IV identifier and actual IV
- $catfile = self::concatIv( $encryptedContent, $iv );
+ $catfile = self::concatIv($encryptedContent, $iv);
- $padded = self::addPadding( $catfile );
+ $padded = self::addPadding($catfile);
return $padded;
} else {
- \OC_Log::write( 'Encryption library', 'Encryption (symmetric) of keyfile content failed', \OC_Log::ERROR );
+ \OCP\Util::writeLog('Encryption library', 'Encryption (symmetric) of keyfile content failed', \OCP\Util::ERROR);
return false;
@@ -309,31 +316,37 @@ class Crypt {
/**
* @brief Symmetrically decrypts keyfile content
- * @param string $source
- * @param string $target
- * @param string $key the decryption key
- * @returns decrypted content
+ * @param $keyfileContent
+ * @param string $passphrase
+ * @throws \Exception
+ * @return bool|string
+ * @internal param string $source
+ * @internal param string $target
+ * @internal param string $key the decryption key
+ * @returns string decrypted content
*
* This function decrypts a file
*/
- public static function symmetricDecryptFileContent( $keyfileContent, $passphrase = '' ) {
+ public static function symmetricDecryptFileContent($keyfileContent, $passphrase = '') {
- if ( !$keyfileContent ) {
+ if (!$keyfileContent) {
- throw new \Exception( 'Encryption library: no data provided for decryption' );
+ throw new \Exception('Encryption library: no data provided for decryption');
}
// Remove padding
- $noPadding = self::removePadding( $keyfileContent );
+ $noPadding = self::removePadding($keyfileContent);
// Split into enc data and catfile
- $catfile = self::splitIv( $noPadding );
+ $catfile = self::splitIv($noPadding);
- if ( $plainContent = self::decrypt( $catfile['encrypted'], $catfile['iv'], $passphrase ) ) {
+ if ($plainContent = self::decrypt($catfile['encrypted'], $catfile['iv'], $passphrase)) {
return $plainContent;
+ } else {
+ return false;
}
}
@@ -346,15 +359,15 @@ class Crypt {
*
* This function decrypts a file
*/
- public static function symmetricEncryptFileContentKeyfile( $plainContent ) {
+ public static function symmetricEncryptFileContentKeyfile($plainContent) {
$key = self::generateKey();
- if( $encryptedContent = self::symmetricEncryptFileContent( $plainContent, $key ) ) {
+ if ($encryptedContent = self::symmetricEncryptFileContent($plainContent, $key)) {
return array(
- 'key' => $key
- , 'encrypted' => $encryptedContent
+ 'key' => $key,
+ 'encrypted' => $encryptedContent
);
} else {
@@ -368,22 +381,41 @@ class Crypt {
/**
* @brief Create asymmetrically encrypted keyfile content using a generated key
* @param string $plainContent content to be encrypted
- * @returns array keys: key, encrypted
- * @note symmetricDecryptFileContent() can be used to decrypt files created using this method
- *
- * This function decrypts a file
+ * @param array $publicKeys array keys must be the userId of corresponding user
+ * @returns array keys: keys (array, key = userId), data
+ * @note symmetricDecryptFileContent() can decrypt files created using this method
*/
- public static function multiKeyEncrypt( $plainContent, array $publicKeys ) {
+ public static function multiKeyEncrypt($plainContent, array $publicKeys) {
+
+ // openssl_seal returns false without errors if $plainContent
+ // is empty, so trigger our own error
+ if (empty($plainContent)) {
+
+ throw new \Exception('Cannot mutliKeyEncrypt empty plain content');
+
+ }
// Set empty vars to be set by openssl by reference
$sealed = '';
- $envKeys = array();
+ $shareKeys = array();
+ $mappedShareKeys = array();
- if( openssl_seal( $plainContent, $sealed, $envKeys, $publicKeys ) ) {
+ if (openssl_seal($plainContent, $sealed, $shareKeys, $publicKeys)) {
+
+ $i = 0;
+
+ // Ensure each shareKey is labelled with its
+ // corresponding userId
+ foreach ($publicKeys as $userId => $publicKey) {
+
+ $mappedShareKeys[$userId] = $shareKeys[$i];
+ $i++;
+
+ }
return array(
- 'keys' => $envKeys
- , 'encrypted' => $sealed
+ 'keys' => $mappedShareKeys,
+ 'data' => $sealed
);
} else {
@@ -396,27 +428,31 @@ class Crypt {
/**
* @brief Asymmetrically encrypt a file using multiple public keys
- * @param string $plainContent content to be encrypted
+ * @param $encryptedContent
+ * @param $shareKey
+ * @param $privateKey
+ * @return bool
+ * @internal param string $plainContent content to be encrypted
* @returns string $plainContent decrypted string
* @note symmetricDecryptFileContent() can be used to decrypt files created using this method
*
* This function decrypts a file
*/
- public static function multiKeyDecrypt( $encryptedContent, $envKey, $privateKey ) {
+ public static function multiKeyDecrypt($encryptedContent, $shareKey, $privateKey) {
- if ( !$encryptedContent ) {
+ if (!$encryptedContent) {
return false;
}
- if ( openssl_open( $encryptedContent, $plainContent, $envKey, $privateKey ) ) {
+ if (openssl_open($encryptedContent, $plainContent, $shareKey, $privateKey)) {
return $plainContent;
} else {
- \OC_Log::write( 'Encryption library', 'Decryption (asymmetric) of sealed content failed', \OC_Log::ERROR );
+ \OCP\Util::writeLog('Encryption library', 'Decryption (asymmetric) of sealed content failed', \OCP\Util::ERROR);
return false;
@@ -425,12 +461,14 @@ class Crypt {
}
/**
- * @brief Asymmetrically encrypt a string using a public key
- * @returns encrypted file
+ * @brief Asymetrically encrypt a string using a public key
+ * @param $plainContent
+ * @param $publicKey
+ * @return string encrypted file
*/
- public static function keyEncrypt( $plainContent, $publicKey ) {
+ public static function keyEncrypt($plainContent, $publicKey) {
- openssl_public_encrypt( $plainContent, $encryptedContent, $publicKey );
+ openssl_public_encrypt($plainContent, $encryptedContent, $publicKey);
return $encryptedContent;
@@ -438,110 +476,19 @@ class Crypt {
/**
* @brief Asymetrically decrypt a file using a private key
- * @returns decrypted file
- */
- public static function keyDecrypt( $encryptedContent, $privatekey ) {
-
- openssl_private_decrypt( $encryptedContent, $plainContent, $privatekey );
-
- return $plainContent;
-
- }
-
- /**
- * @brief Encrypts content symmetrically and generates keyfile asymmetrically
- * @returns array containing catfile and new keyfile.
- * keys: data, key
- * @note this method is a wrapper for combining other crypt class methods
- */
- public static function keyEncryptKeyfile( $plainContent, $publicKey ) {
-
- // Encrypt plain data, generate keyfile & encrypted file
- $cryptedData = self::symmetricEncryptFileContentKeyfile( $plainContent );
-
- // Encrypt keyfile
- $cryptedKey = self::keyEncrypt( $cryptedData['key'], $publicKey );
-
- return array( 'data' => $cryptedData['encrypted'], 'key' => $cryptedKey );
-
- }
-
- /**
- * @brief Takes catfile, keyfile, and private key, and
- * performs decryption
- * @returns decrypted content
- * @note this method is a wrapper for combining other crypt class methods
- */
- public static function keyDecryptKeyfile( $catfile, $keyfile, $privateKey ) {
-
- // Decrypt the keyfile with the user's private key
- $decryptedKeyfile = self::keyDecrypt( $keyfile, $privateKey );
-
- // Decrypt the catfile symmetrically using the decrypted keyfile
- $decryptedData = self::symmetricDecryptFileContent( $catfile, $decryptedKeyfile );
-
- return $decryptedData;
-
- }
-
- /**
- * @brief Symmetrically encrypt a file by combining encrypted component data blocks
- */
- public static function symmetricBlockEncryptFileContent( $plainContent, $key ) {
-
- $crypted = '';
-
- $remaining = $plainContent;
-
- $testarray = array();
-
- while( strlen( $remaining ) ) {
-
- //echo "\n\n\$block = ".substr( $remaining, 0, 6126 );
-
- // Encrypt a chunk of unencrypted data and add it to the rest
- $block = self::symmetricEncryptFileContent( substr( $remaining, 0, 6126 ), $key );
-
- $padded = self::addPadding( $block );
-
- $crypted .= $block;
-
- $testarray[] = $block;
-
- // Remove the data already encrypted from remaining unencrypted data
- $remaining = substr( $remaining, 6126 );
-
- }
-
- return $crypted;
-
- }
-
-
- /**
- * @brief Symmetrically decrypt a file by combining encrypted component data blocks
+ * @param $encryptedContent
+ * @param $privatekey
+ * @return string decrypted file
*/
- public static function symmetricBlockDecryptFileContent( $crypted, $key ) {
-
- $decrypted = '';
-
- $remaining = $crypted;
-
- $testarray = array();
-
- while( strlen( $remaining ) ) {
-
- $testarray[] = substr( $remaining, 0, 8192 );
-
- // Decrypt a chunk of unencrypted data and add it to the rest
- $decrypted .= self::symmetricDecryptFileContent( $remaining, $key );
+ public static function keyDecrypt($encryptedContent, $privatekey) {
- // Remove the data already encrypted from remaining unencrypted data
- $remaining = substr( $remaining, 8192 );
+ $result = @openssl_private_decrypt($encryptedContent, $plainContent, $privatekey);
+ if ($result) {
+ return $plainContent;
}
- return $decrypted;
+ return $result;
}
@@ -551,24 +498,24 @@ class Crypt {
*/
public static function generateIv() {
- if ( $random = openssl_random_pseudo_bytes( 12, $strong ) ) {
+ if ($random = openssl_random_pseudo_bytes(12, $strong)) {
- if ( !$strong ) {
+ if (!$strong) {
// If OpenSSL indicates randomness is insecure, log error
- \OC_Log::write( 'Encryption library', 'Insecure symmetric key was generated using openssl_random_pseudo_bytes()', \OC_Log::WARN );
+ \OCP\Util::writeLog('Encryption library', 'Insecure symmetric key was generated using openssl_random_pseudo_bytes()', \OCP\Util::WARN);
}
// We encode the iv purely for string manipulation
// purposes - it gets decoded before use
- $iv = base64_encode( $random );
+ $iv = base64_encode($random);
return $iv;
} else {
- throw new \Exception( 'Generating IV failed' );
+ throw new \Exception('Generating IV failed');
}
@@ -581,12 +528,12 @@ class Crypt {
public static function generateKey() {
// Generate key
- if ( $key = base64_encode( openssl_random_pseudo_bytes( 183, $strong ) ) ) {
+ if ($key = base64_encode(openssl_random_pseudo_bytes(183, $strong))) {
- if ( !$strong ) {
+ if (!$strong) {
// If OpenSSL indicates randomness is insecure, log error
- throw new \Exception ( 'Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()' );
+ throw new \Exception('Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()');
}
@@ -603,15 +550,15 @@ class Crypt {
/**
* @brief Get the blowfish encryption handeler for a key
* @param $key string (optional)
- * @return Crypt_Blowfish blowfish object
+ * @return \Crypt_Blowfish blowfish object
*
* if the key is left out, the default handeler will be used
*/
- public static function getBlowfish( $key = '' ) {
+ public static function getBlowfish($key = '') {
- if ( $key ) {
+ if ($key) {
- return new \Crypt_Blowfish( $key );
+ return new \Crypt_Blowfish($key);
} else {
@@ -621,13 +568,17 @@ class Crypt {
}
- public static function legacyCreateKey( $passphrase ) {
+ /**
+ * @param $passphrase
+ * @return mixed
+ */
+ public static function legacyCreateKey($passphrase) {
// Generate a random integer
- $key = mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 );
+ $key = mt_rand(10000, 99999) . mt_rand(10000, 99999) . mt_rand(10000, 99999) . mt_rand(10000, 99999);
// Encrypt the key with the passphrase
- $legacyEncKey = self::legacyEncrypt( $key, $passphrase );
+ $legacyEncKey = self::legacyEncrypt($key, $passphrase);
return $legacyEncKey;
@@ -635,61 +586,79 @@ class Crypt {
/**
* @brief encrypts content using legacy blowfish system
- * @param $content the cleartext message you want to encrypt
- * @param $key the encryption key (optional)
- * @returns encrypted content
+ * @param string $content the cleartext message you want to encrypt
+ * @param string $passphrase
+ * @returns string encrypted content
*
* This function encrypts an content
*/
- public static function legacyEncrypt( $content, $passphrase = '' ) {
+ public static function legacyEncrypt($content, $passphrase = '') {
- $bf = self::getBlowfish( $passphrase );
+ $bf = self::getBlowfish($passphrase);
- return $bf->encrypt( $content );
+ return $bf->encrypt($content);
}
/**
* @brief decrypts content using legacy blowfish system
- * @param $content the cleartext message you want to decrypt
- * @param $key the encryption key (optional)
- * @returns cleartext content
+ * @param string $content the cleartext message you want to decrypt
+ * @param string $passphrase
+ * @return string cleartext content
*
* This function decrypts an content
*/
- public static function legacyDecrypt( $content, $passphrase = '' ) {
-
- $bf = self::getBlowfish( $passphrase );
-
- $decrypted = $bf->decrypt( $content );
+ private static function legacyDecrypt($content, $passphrase = '') {
- $trimmed = rtrim( $decrypted, "\0" );
+ $bf = self::getBlowfish($passphrase);
- return $trimmed;
+ $decrypted = $bf->decrypt($content);
+ return $decrypted;
}
- public static function legacyKeyRecryptKeyfile( $legacyEncryptedContent, $legacyPassphrase, $publicKey, $newPassphrase ) {
-
- $decrypted = self::legacyDecrypt( $legacyEncryptedContent, $legacyPassphrase );
-
- $recrypted = self::keyEncryptKeyfile( $decrypted, $publicKey );
-
- return $recrypted;
+ /**
+ * @param $data
+ * @param string $key
+ * @param int $maxLength
+ * @return string
+ */
+ public static function legacyBlockDecrypt($data, $key = '', $maxLength = 0) {
+ $result = '';
+ while (strlen($data)) {
+ $result .= self::legacyDecrypt(substr($data, 0, 8192), $key);
+ $data = substr($data, 8192);
+ }
+ if ($maxLength > 0) {
+ return substr($result, 0, $maxLength);
+ } else {
+ return rtrim($result, "\0");
+ }
}
/**
- * @brief Re-encryptes a legacy blowfish encrypted file using AES with integrated IV
- * @param $legacyContent the legacy encrypted content to re-encrypt
- * @returns cleartext content
- *
- * This function decrypts an content
+ * @param $legacyEncryptedContent
+ * @param $legacyPassphrase
+ * @param $publicKeys
+ * @return array
*/
- public static function legacyRecrypt( $legacyContent, $legacyPassphrase, $newPassphrase ) {
+ public static function legacyKeyRecryptKeyfile($legacyEncryptedContent, $legacyPassphrase, $publicKeys) {
- // TODO: write me
+ $decrypted = self::legacyBlockDecrypt($legacyEncryptedContent, $legacyPassphrase);
+
+ // Encrypt plain data, generate keyfile & encrypted file
+ $cryptedData = self::symmetricEncryptFileContentKeyfile($decrypted);
+
+ // Encrypt plain keyfile to multiple sharefiles
+ $multiEncrypted = Crypt::multiKeyEncrypt($cryptedData['key'], $publicKeys);
+
+ return array(
+ 'data' => $cryptedData['encrypted'],
+ 'filekey' => $multiEncrypted['data'],
+ 'sharekeys' => $multiEncrypted['keys']
+ );
}
-}
+} \ No newline at end of file
diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php
new file mode 100755
index 00000000000..e078ab35541
--- /dev/null
+++ b/apps/files_encryption/lib/helper.php
@@ -0,0 +1,203 @@
+<?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
+ * @package OCA\Encryption
+ */
+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');
+ }
+
+ /**
+ * @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', 'post_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 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()) {
+
+ \OCP\Util::writeLog('Encryption library', 'User account "' . $util->getUserId()
+ . '" is not ready for encryption; configuration started', \OCP\Util::DEBUG);
+
+ if (!$util->setupServerSide($password)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @brief enable recovery
+ *
+ * @param $recoveryKeyId
+ * @param $recoveryPassword
+ * @internal param \OCA\Encryption\Util $util
+ * @internal param string $password
+ * @return bool
+ */
+ public static function adminEnableRecovery($recoveryKeyId, $recoveryPassword) {
+ $view = new \OC\Files\View('/');
+
+ if ($recoveryKeyId === null) {
+ $recoveryKeyId = 'recovery_' . substr(md5(time()), 0, 8);
+ \OC_Appconfig::setValue('files_encryption', 'recoveryKeyId', $recoveryKeyId);
+ }
+
+ 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"))
+ ) {
+
+ $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'], $recoveryPassword);
+
+ // Save private key
+ $view->file_put_contents('/owncloud_private_key/' . $recoveryKeyId . '.private.key', $encryptedPrivateKey);
+
+ // create control file which let us check later on if the entered password was correct.
+ $encryptedControlData = \OCA\Encryption\Crypt::keyEncrypt("ownCloud", $keypair['publicKey']);
+ if (!$view->is_dir('/control-file')) {
+ $view->mkdir('/control-file');
+ }
+ $view->file_put_contents('/control-file/controlfile.enc', $encryptedControlData);
+
+ \OC_FileProxy::$enabled = true;
+
+ // Set recoveryAdmin as enabled
+ \OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1);
+
+ $return = true;
+
+ } else { // get recovery key and check the password
+ $util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \OCP\User::getUser());
+ $return = $util->checkRecoveryPassword($recoveryPassword);
+ if ($return) {
+ \OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1);
+ }
+ }
+
+ return $return;
+ }
+
+
+ /**
+ * @brief disable recovery
+ *
+ * @param $recoveryPassword
+ * @return bool
+ */
+ public static function adminDisableRecovery($recoveryPassword) {
+ $util = new Util(new \OC_FilesystemView('/'), \OCP\User::getUser());
+ $return = $util->checkRecoveryPassword($recoveryPassword);
+
+ if ($return) {
+ // Set recoveryAdmin as disabled
+ \OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 0);
+ }
+
+ return $return;
+ }
+
+
+ /**
+ * @brief checks if access is public/anonymous user
+ * @return bool
+ */
+ public static function isPublicAccess() {
+ if (\OCP\USER::getUser() === false
+ || (isset($_GET['service']) && $_GET['service'] == 'files'
+ && isset($_GET['t']))
+ ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @brief Format a path to be relative to the /user/files/ directory
+ * @param string $path the absolute path
+ * @return string e.g. turns '/admin/files/test.txt' into 'test.txt'
+ */
+ public static function stripUserFilesPath($path) {
+ $trimmed = ltrim($path, '/');
+ $split = explode('/', $trimmed);
+ $sliced = array_slice($split, 2);
+ $relPath = implode('/', $sliced);
+
+ return $relPath;
+ }
+} \ No newline at end of file
diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php
index 95587797154..e911c1785df 100755
--- a/apps/files_encryption/lib/keymanager.php
+++ b/apps/files_encryption/lib/keymanager.php
@@ -28,19 +28,26 @@ namespace OCA\Encryption;
* @note Where a method requires a view object, it's root must be '/'
*/
class Keymanager {
-
+
/**
* @brief retrieve the ENCRYPTED private key from a user
- *
- * @return string private key or false
+ *
+ * @param \OC_FilesystemView $view
+ * @param string $user
+ * @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';
-
- $key = $view->file_get_contents( $path );
-
+ 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;
}
@@ -50,102 +57,152 @@ class Keymanager {
* @param $userId
* @return string public key or false
*/
- public static function getPublicKey( \OC_FilesystemView $view, $userId ) {
-
- return $view->file_get_contents( '/public-keys/' . '/' . $userId . '.public.key' );
-
+ public static function getPublicKey(\OC_FilesystemView $view, $userId) {
+
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ $result = $view->file_get_contents('/public-keys/' . $userId . '.public.key');
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ return $result;
+
}
-
+
/**
- * @brief retrieve both keys from a user (private and public)
+ * @brief Retrieve a user's public and private key
* @param \OC_FilesystemView $view
* @param $userId
* @return array keys: privateKey, publicKey
*/
- public static function getUserKeys( \OC_FilesystemView $view, $userId ) {
-
+ public static function getUserKeys(\OC_FilesystemView $view, $userId) {
+
return array(
- 'publicKey' => self::getPublicKey( $view, $userId )
- , 'privateKey' => self::getPrivateKey( $view, $userId )
+ 'publicKey' => self::getPublicKey($view, $userId),
+ 'privateKey' => self::getPrivateKey($view, $userId)
);
-
+
}
-
+
/**
- * @brief Retrieve public keys of all users with access to a file
- * @param string $path Path to file
- * @return array of public keys for the given file
- * @note Checks that the sharing app is enabled should be performed
- * by client code, that isn't checked here
+ * @brief Retrieve public keys for given users
+ * @param \OC_FilesystemView $view
+ * @param array $userIds
+ * @return array of public keys for the specified users
*/
- public static function getPublicKeys( \OC_FilesystemView $view, $userId, $filePath ) {
-
- $path = ltrim( $path, '/' );
-
- $filepath = '/' . $userId . '/files/' . $filePath;
-
- // Check if sharing is enabled
- if ( OC_App::isEnabled( 'files_sharing' ) ) {
-
-
-
- } else {
-
- // check if it is a file owned by the user and not shared at all
- $userview = new \OC_FilesystemView( '/'.$userId.'/files/' );
-
- if ( $userview->file_exists( $path ) ) {
-
- $users[] = $userId;
-
- }
-
- }
-
- $view = new \OC_FilesystemView( '/public-keys/' );
-
- $keylist = array();
-
- $count = 0;
-
- foreach ( $users as $user ) {
-
- $keylist['key'.++$count] = $view->file_get_contents( $user.'.public.key' );
-
+ public static function getPublicKeys(\OC_FilesystemView $view, array $userIds) {
+
+ $keys = array();
+
+ foreach ($userIds as $userId) {
+
+ $keys[$userId] = self::getPublicKey($view, $userId);
+
}
-
- return $keylist;
-
+
+ return $keys;
+
}
-
+
/**
* @brief store file encryption key
*
+ * @param \OC_FilesystemView $view
* @param string $path relative path of the file, including filename
- * @param string $key
+ * @param $userId
+ * @param $catfile
+ * @internal param string $key
* @return bool true/false
- * @note The keyfile is not encrypted here. Client code must
+ * @note The keyfile is not encrypted here. Client code must
* asymmetrically encrypt the keyfile before passing it to this method
*/
- public static function setFileKey( \OC_FilesystemView $view, $path, $userId, $catfile ) {
-
- $basePath = '/' . $userId . '/files_encryption/keyfiles';
-
- $targetPath = self::keySetPreparation( $view, $path, $basePath, $userId );
-
- if ( $view->is_dir( $basePath . '/' . $targetPath ) ) {
-
-
-
+ public static function setFileKey(\OC_FilesystemView $view, $path, $userId, $catfile) {
+
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \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);
+
+ $basePath = '/' . $owner . '/files_encryption/keyfiles';
+
+ $targetPath = self::keySetPreparation($view, $filename, $basePath, $owner);
+
+ 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);
+
+ }
+ }
+
+ // try reusing key file if part file
+ if (self::isPartialFilePath($targetPath)) {
+
+ $result = $view->file_put_contents(
+ $basePath . '/' . self::fixPartialFilePath($targetPath) . '.key', $catfile);
+
} else {
- // Save the keyfile in parallel directory
- return $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile );
-
+ $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) || preg_match('/\.etmp$/', $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) || preg_match('/\.etmp$/', $path)) {
+
+ return true;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
/**
* @brief retrieve keyfile for an encrypted file
* @param \OC_FilesystemView $view
@@ -156,168 +213,359 @@ class Keymanager {
* @note The keyfile returned is asymmetrically encrypted. Decryption
* of the keyfile must be performed by client code
*/
- public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) {
-
- $filePath_f = ltrim( $filePath, '/' );
-
- $catfilePath = '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key';
-
- if ( $view->file_exists( $catfilePath ) ) {
-
- return $view->file_get_contents( $catfilePath );
-
+ 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;
+ \OC_FileProxy::$enabled = false;
+
+ if ($view->file_exists($keyfilePath)) {
+
+ $result = $view->file_get_contents($keyfilePath);
+
} else {
-
- return false;
-
+
+ $result = false;
+
}
-
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ return $result;
+
}
-
+
/**
* @brief Delete a keyfile
*
- * @param OC_FilesystemView $view
+ * @param \OC_FilesystemView $view
* @param string $userId username
* @param string $path path of the file the key belongs to
* @return bool Outcome of unlink operation
* @note $path must be relative to data/user/files. e.g. mydoc.txt NOT
* /data/admin/files/mydoc.txt
*/
- public static function deleteFileKey( \OC_FilesystemView $view, $userId, $path ) {
-
- $trimmed = ltrim( $path, '/' );
- $keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed . '.key';
-
- // Unlink doesn't tell us if file was deleted (not found returns
- // true), so we perform our own test
- if ( $view->file_exists( $keyPath ) ) {
-
- return $view->unlink( $keyPath );
-
+ public static function deleteFileKey(\OC_FilesystemView $view, $userId, $path) {
+
+ $trimmed = ltrim($path, '/');
+ $keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed;
+
+ $result = false;
+
+ if ($view->is_dir($keyPath)) {
+
+ $result = $view->unlink($keyPath);
+
} else {
-
- \OC_Log::write( 'Encryption library', 'Could not delete keyfile; does not exist: "' . $keyPath, \OC_Log::ERROR );
-
- return false;
-
+ if ($view->file_exists($keyPath . '.key')) {
+
+ $result = $view->unlink($keyPath . '.key');
+
+ }
+ }
+
+ if (!$result) {
+
+ \OCP\Util::writeLog('Encryption library',
+ 'Could not delete keyfile; does not exist: "' . $keyPath, \OCP\Util::ERROR);
+
}
-
+
+ return $result;
+
}
-
+
/**
* @brief store private key from the user
- * @param string key
+ * @param string $key
* @return bool
* @note Encryption of the private key must be performed by client code
* as no encryption takes place here
*/
- public static function setPrivateKey( $key ) {
-
+ public static function setPrivateKey($key) {
+
$user = \OCP\User::getUser();
-
- $view = new \OC_FilesystemView( '/' . $user . '/files_encryption' );
-
+
+ $view = new \OC_FilesystemView('/' . $user . '/files_encryption');
+
+ $proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
-
- if ( !$view->file_exists( '' ) )
- $view->mkdir( '' );
-
- return $view->file_put_contents( $user . '.private.key', $key );
+
+ if (!$view->file_exists(''))
+ $view->mkdir('');
+
+ $result = $view->file_put_contents($user . '.private.key', $key);
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ return $result;
}
-
+
/**
- * @brief store private keys from the user
+ * @brief store share key
*
- * @param string privatekey
- * @param string publickey
+ * @param \OC_FilesystemView $view
+ * @param string $path relative path of the file, including filename
+ * @param $userId
+ * @param $shareKey
+ * @internal param string $key
+ * @internal param string $dbClassName
* @return bool true/false
+ * @note The keyfile is not encrypted here. Client code must
+ * asymmetrically encrypt the keyfile before passing it to this method
+ */
+ 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
+ $util = new Util($view, \OCP\User::getUser());
+
+ 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';
+
+ }
+
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ $result = $view->file_put_contents($writePath, $shareKey);
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ if (
+ is_int($result)
+ && $result > 0
+ ) {
+
+ return true;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+ /**
+ * @brief store multiple share keys for a single file
+ * @param \OC_FilesystemView $view
+ * @param $path
+ * @param array $shareKeys
+ * @return bool
*/
- public static function setUserKeys($privatekey, $publickey) {
-
- return ( self::setPrivateKey( $privatekey ) && self::setPublicKey( $publickey ) );
-
+ public static function setShareKeys(\OC_FilesystemView $view, $path, array $shareKeys) {
+
+ // $shareKeys must be an array with the following format:
+ // [userId] => [encrypted key]
+
+ $result = true;
+
+ foreach ($shareKeys as $userId => $shareKey) {
+
+ if (!self::setShareKey($view, $path, $userId, $shareKey)) {
+
+ // If any of the keys are not set, flag false
+ $result = false;
+
+ }
+
+ }
+
+ // Returns false if any of the keys weren't set
+ return $result;
+
}
-
+
/**
- * @brief store public key of the user
- *
- * @param string key
- * @return bool true/false
+ * @brief retrieve shareKey for an encrypted file
+ * @param \OC_FilesystemView $view
+ * @param string $userId
+ * @param string $filePath
+ * @internal param \OCA\Encryption\file $string name
+ * @return string file key or false
+ * @note The sharekey returned is encrypted. Decryption
+ * of the keyfile must be performed by client code
*/
- public static function setPublicKey( $key ) {
-
- $view = new \OC_FilesystemView( '/public-keys' );
-
+ public static function getShareKey(\OC_FilesystemView $view, $userId, $filePath) {
+
+ // 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;
-
- if ( !$view->file_exists( '' ) )
- $view->mkdir( '' );
-
- return $view->file_put_contents( \OCP\User::getUser() . '.public.key', $key );
-
+ //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($filePath);
+ $shareKeyPath = \OC\Files\Filesystem::normalizePath(
+ '/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey');
+
+ if ($view->file_exists($shareKeyPath)) {
+
+ $result = $view->file_get_contents($shareKeyPath);
+
+ } else {
+
+ $result = false;
+
+ }
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ return $result;
+
}
-
+
/**
- * @brief store file encryption key
+ * @brief delete all share keys of a given file
+ * @param \OC_FilesystemView $view
+ * @param string $userId owner of the file
+ * @param string $filePath path to the file, relative to the owners file dir
+ */
+ public static function delAllShareKeys(\OC_FilesystemView $view, $userId, $filePath) {
+
+ if ($view->is_dir($userId . '/files/' . $filePath)) {
+ $view->unlink($userId . '/files_encryption/share-keys/' . $filePath);
+ } else {
+ $localKeyPath = $view->getLocalFile($userId . '/files_encryption/share-keys/' . $filePath);
+ $matches = glob(preg_quote($localKeyPath) . '*.shareKey');
+ foreach ($matches as $ma) {
+ $result = unlink($ma);
+ if (!$result) {
+ \OCP\Util::writeLog('Encryption library',
+ 'Keyfile or shareKey could not be deleted for file "' . $filePath . '"', \OCP\Util::ERROR);
+ }
+ }
+ }
+ }
+
+ /**
+ * @brief Delete a single user's shareKey for a single file
+ */
+ public static function delShareKey(\OC_FilesystemView $view, $userIds, $filePath) {
+
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \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($filePath);
+
+ $shareKeyPath = \OC\Files\Filesystem::normalizePath('/' . $owner . '/files_encryption/share-keys/' . $filename);
+
+ if ($view->is_dir($shareKeyPath)) {
+
+ $localPath = \OC\Files\Filesystem::normalizePath($view->getLocalFolder($shareKeyPath));
+ self::recursiveDelShareKeys($localPath, $userIds);
+
+ } else {
+
+ foreach ($userIds as $userId) {
+
+ if (!$view->unlink($shareKeyPath . '.' . $userId . '.shareKey')) {
+ \OCP\Util::writeLog('Encryption library',
+ 'Could not delete shareKey; does not exist: "' . $shareKeyPath . '.' . $userId
+ . '.shareKey"', \OCP\Util::ERROR);
+ }
+
+ }
+ }
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+ }
+
+ /**
+ * @brief recursively delete share keys from given users
*
- * @param string $path relative path of the file, including filename
- * @param string $key
- * @param null $view
- * @param string $dbClassName
- * @return bool true/false
- * @note The keyfile is not encrypted here. Client code must
- * asymmetrically encrypt the keyfile before passing it to this method
+ * @param string $dir directory
+ * @param array $userIds user ids for which the share keys should be deleted
*/
- public static function setShareKey( \OC_FilesystemView $view, $path, $userId, $shareKey ) {
-
- $basePath = '/' . $userId . '/files_encryption/share-keys';
-
- $shareKeyPath = self::keySetPreparation( $view, $path, $basePath, $userId );
-
- return $view->file_put_contents( $basePath . '/' . $shareKeyPath . '.shareKey', $shareKey );
-
+ private static function recursiveDelShareKeys($dir, $userIds) {
+ foreach ($userIds as $userId) {
+ $matches = glob(preg_quote($dir) . '/*' . preg_quote('.' . $userId . '.shareKey'));
+ }
+ /** @var $matches array */
+ foreach ($matches as $ma) {
+ if (!unlink($ma)) {
+ \OCP\Util::writeLog('Encryption library',
+ 'Could not delete shareKey; does not exist: "' . $ma . '"', \OCP\Util::ERROR);
+ }
+ }
+ $subdirs = $directories = glob(preg_quote($dir) . '/*', GLOB_ONLYDIR);
+ foreach ($subdirs as $subdir) {
+ self::recursiveDelShareKeys($subdir, $userIds);
+ }
}
-
+
/**
* @brief Make preparations to vars and filesystem for saving a keyfile
*/
- public static function keySetPreparation( \OC_FilesystemView $view, $path, $basePath, $userId ) {
-
- $targetPath = ltrim( $path, '/' );
-
- $path_parts = pathinfo( $targetPath );
-
+ public static function keySetPreparation(\OC_FilesystemView $view, $path, $basePath, $userId) {
+
+ $targetPath = ltrim($path, '/');
+
+ $path_parts = pathinfo($targetPath);
+
// If the file resides within a subdirectory, create it
- if (
- isset( $path_parts['dirname'] )
- && ! $view->file_exists( $basePath . '/' . $path_parts['dirname'] )
+ if (
+ isset($path_parts['dirname'])
+ && !$view->file_exists($basePath . '/' . $path_parts['dirname'])
) {
-
- $view->mkdir( $basePath . '/' . $path_parts['dirname'] );
-
+ $sub_dirs = explode(DIRECTORY_SEPARATOR, $basePath . '/' . $path_parts['dirname']);
+ $dir = '';
+ foreach ($sub_dirs as $sub_dir) {
+ $dir .= '/' . $sub_dir;
+ if (!$view->is_dir($dir)) {
+ $view->mkdir($dir);
+ }
+ }
}
-
+
return $targetPath;
-
- }
- /**
- * @brief Fetch the legacy encryption key from user files
- * @param string $login used to locate the legacy key
- * @param string $passphrase used to decrypt the legacy key
- * @return true / false
- *
- * if the key is left out, the default handler will be used
- */
- public function getLegacyKey() {
-
- $user = \OCP\User::getUser();
- $view = new \OC_FilesystemView( '/' . $user );
- return $view->file_get_contents( 'encryption.key' );
-
}
-
} \ No newline at end of file
diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php
index 55cddf2bec8..0df34a38bd7 100644
--- a/apps/files_encryption/lib/proxy.php
+++ b/apps/files_encryption/lib/proxy.php
@@ -1,41 +1,45 @@
<?php
/**
-* ownCloud
-*
-* @author Sam Tuke, Robin Appelman
-* @copyright 2012 Sam Tuke samtuke@owncloud.com, Robin Appelman
-* icewind1991@gmail.com
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
-* 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/>.
-*
-*/
+ * ownCloud
+ *
+ * @author Sam Tuke, Robin Appelman
+ * @copyright 2012 Sam Tuke samtuke@owncloud.com, Robin Appelman
+ * icewind1991@gmail.com
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * 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/>.
+ *
+ */
/**
-* @brief Encryption proxy which handles filesystem operations before and after
-* execution and encrypts, and handles keyfiles accordingly. Used for
-* webui.
-*/
+ * @brief Encryption proxy which handles filesystem operations before and after
+ * execution and encrypts, and handles keyfiles accordingly. Used for
+ * webui.
+ */
namespace OCA\Encryption;
+/**
+ * Class Proxy
+ * @package OCA\Encryption
+ */
class Proxy extends \OC_FileProxy {
private static $blackList = null; //mimetypes blacklisted from encryption
-
+
private static $enableEncryption = null;
-
+
/**
* Check if a file requires encryption
* @param string $path
@@ -43,347 +47,383 @@ class Proxy extends \OC_FileProxy {
*
* Tests if server side encryption is enabled, and file is allowed by blacklists
*/
- private static function shouldEncrypt( $path ) {
-
- if ( is_null( self::$enableEncryption ) ) {
-
- if (
- \OCP\Config::getAppValue( 'files_encryption', 'enable_encryption', 'true' ) == 'true'
- && Crypt::mode() == 'server'
+ private static function shouldEncrypt($path) {
+
+ if (is_null(self::$enableEncryption)) {
+
+ if (
+ \OCP\Config::getAppValue('files_encryption', 'enable_encryption', 'true') === 'true'
+ && Crypt::mode() === 'server'
) {
-
+
self::$enableEncryption = true;
-
+
} else {
-
+
self::$enableEncryption = false;
-
+
}
-
+
}
-
- if ( !self::$enableEncryption ) {
-
+
+ if (!self::$enableEncryption) {
+
return false;
-
+
}
-
- if ( is_null(self::$blackList ) ) {
-
- self::$blackList = explode(',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', 'jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg' ) );
-
+
+ if (is_null(self::$blackList)) {
+
+ self::$blackList = explode(',', \OCP\Config::getAppValue('files_encryption', 'type_blacklist', ''));
+
}
-
- if ( Crypt::isCatfile( $path ) ) {
-
+
+ if (Crypt::isCatfileContent($path)) {
+
return true;
-
+
}
-
- $extension = substr( $path, strrpos( $path, '.' ) +1 );
-
- if ( array_search( $extension, self::$blackList ) === false ) {
-
+
+ $extension = substr($path, strrpos($path, '.') + 1);
+
+ if (array_search($extension, self::$blackList) === false) {
+
return true;
-
+
}
-
+
return false;
}
-
- public function preFile_put_contents( $path, &$data ) {
-
- if ( self::shouldEncrypt( $path ) ) {
-
- if ( !is_resource( $data ) ) { //stream put contents should have been converted to fopen
-
- $userId = \OCP\USER::getUser();
-
- $rootView = new \OC_FilesystemView( '/' );
-
- // Set the filesize for userland, before encrypting
- $size = strlen( $data );
-
- // Disable encryption proxy to prevent recursive calls
- \OC_FileProxy::$enabled = false;
-
- // TODO: Check if file is shared, if so, use multiKeyEncrypt
-
- // Encrypt plain data and fetch key
- $encrypted = Crypt::keyEncryptKeyfile( $data, Keymanager::getPublicKey( $rootView, $userId ) );
-
- // Replace plain content with encrypted content by reference
- $data = $encrypted['data'];
-
- $filePath = explode( '/', $path );
-
- $filePath = array_slice( $filePath, 3 );
-
- $filePath = '/' . implode( '/', $filePath );
-
- // TODO: make keyfile dir dynamic from app config
-
- $view = new \OC_FilesystemView( '/' );
-
- // Save keyfile for newly encrypted file in parallel directory tree
- Keymanager::setFileKey( $view, $filePath, $userId, $encrypted['key'] );
-
- // Update the file cache with file info
- \OC\Files\Filesystem::putFileInfo( $path, array( 'encrypted'=>true, 'size' => $size ), '' );
-
- // Re-enable proxy - our work is done
- \OC_FileProxy::$enabled = true;
-
+
+ /**
+ * @param $path
+ * @param $data
+ * @return bool
+ */
+ public function preFile_put_contents($path, &$data) {
+
+ if (self::shouldEncrypt($path)) {
+
+ if (!is_resource($data)) {
+
+ // get root view
+ $view = new \OC_FilesystemView('/');
+
+ // get relative path
+ $relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
+
+ if (!isset($relativePath)) {
+ return true;
+ }
+
+ $handle = fopen('crypt://' . $relativePath . '.etmp', 'w');
+ if (is_resource($handle)) {
+
+ // write data to stream
+ fwrite($handle, $data);
+
+ // close stream
+ fclose($handle);
+
+ // disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ // get encrypted content
+ $data = $view->file_get_contents($path . '.etmp');
+
+ // remove our temp file
+ $view->unlink($path . '.etmp');
+
+ // re-enable proxy - our work is done
+ \OC_FileProxy::$enabled = $proxyStatus;
+ }
}
}
-
+
+ return true;
+
}
-
+
/**
* @param string $path Path of file from which has been read
* @param string $data Data that has been read from file
*/
- public function postFile_get_contents( $path, $data ) {
-
- // TODO: Use dependency injection to add required args for view and user etc. to this method
+ public function postFile_get_contents($path, $data) {
+
+ $plainData = null;
+ $view = new \OC_FilesystemView('/');
+
+ // get relative path
+ $relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
+
+ // init session
+ $session = new \OCA\Encryption\Session($view);
- // Disable encryption proxy to prevent recursive calls
- \OC_FileProxy::$enabled = false;
-
// If data is a catfile
- if (
- Crypt::mode() == 'server'
- && Crypt::isCatfile( $data )
+ if (
+ Crypt::mode() === 'server'
+ && Crypt::isCatfileContent($data)
) {
-
- $split = explode( '/', $path );
-
- $filePath = array_slice( $split, 3 );
-
- $filePath = '/' . implode( '/', $filePath );
-
- //$cached = \OC\Files\Filesystem::getFileInfo( $path, '' );
-
- $view = new \OC_FilesystemView( '' );
-
- $userId = \OCP\USER::getUser();
-
- // TODO: Check if file is shared, if so, use multiKeyDecrypt
-
- $encryptedKeyfile = Keymanager::getFileKey( $view, $userId, $filePath );
-
- $session = new Session();
-
- $decrypted = Crypt::keyDecryptKeyfile( $data, $encryptedKeyfile, $session->getPrivateKey( $split[1] ) );
-
+
+ $handle = fopen('crypt://' . $relativePath, 'r');
+
+ if (is_resource($handle)) {
+ while (($plainDataChunk = fgets($handle, 8192)) !== false) {
+ $plainData .= $plainDataChunk;
+ }
+ }
+
} elseif (
- Crypt::mode() == 'server'
- && isset( $_SESSION['legacyenckey'] )
- && Crypt::isEncryptedMeta( $path )
+ Crypt::mode() == 'server'
+ && \OC::$session->exists('legacyenckey')
+ && Crypt::isEncryptedMeta($path)
) {
-
- $decrypted = Crypt::legacyDecrypt( $data, $_SESSION['legacyenckey'] );
-
+ // Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ $plainData = Crypt::legacyBlockDecrypt($data, $session->getLegacyKey());
+
+ \OC_FileProxy::$enabled = $proxyStatus;
}
-
- \OC_FileProxy::$enabled = true;
-
- if ( ! isset( $decrypted ) ) {
-
- $decrypted = $data;
-
+
+ if (!isset($plainData)) {
+
+ $plainData = $data;
+
}
-
- return $decrypted;
-
+
+ return $plainData;
+
}
-
+
/**
* @brief When a file is deleted, remove its keyfile also
*/
- public function preUnlink( $path ) {
-
+ public function preUnlink($path) {
+
+ // let the trashbin handle this
+ if (\OCP\App::isEnabled('files_trashbin')) {
+ return true;
+ }
+
// Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
-
- $view = new \OC_FilesystemView( '/' );
-
+
+ $view = new \OC_FilesystemView('/');
+
$userId = \OCP\USER::getUser();
-
- // Format path to be relative to user files dir
- $trimmed = ltrim( $path, '/' );
- $split = explode( '/', $trimmed );
- $sliced = array_slice( $split, 2 );
- $relPath = implode( '/', $sliced );
-
- if ( $view->is_dir( $path ) ) {
-
- // Dirs must be handled separately as deleteFileKey
- // doesn't handle them
- $view->unlink( $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/'. $relPath );
-
- } else {
-
- // Delete keyfile so it isn't orphaned
- $result = Keymanager::deleteFileKey( $view, $userId, $relPath );
-
- \OC_FileProxy::$enabled = true;
-
- return $result;
-
+
+ $util = new Util($view, $userId);
+
+ // get relative path
+ $relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
+
+ list($owner, $ownerPath) = $util->getUidAndFilename($relativePath);
+
+ // Delete keyfile & shareKey so it isn't orphaned
+ if (!Keymanager::deleteFileKey($view, $owner, $ownerPath)) {
+ \OCP\Util::writeLog('Encryption library',
+ 'Keyfile or shareKey could not be deleted for file "' . $ownerPath . '"', \OCP\Util::ERROR);
}
-
+
+ Keymanager::delAllShareKeys($view, $owner, $ownerPath);
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ // If we don't return true then file delete will fail; better
+ // to leave orphaned keyfiles than to disallow file deletion
+ return true;
+
}
/**
- * @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
+ * @param $path
+ * @return bool
*/
- public function preRename( $oldPath, $newPath ) {
-
- // Disable encryption proxy to prevent recursive calls
- \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 . '.key';
-
- $newTrimmed = ltrim( $newPath, '/' );
- $newSplit = explode( '/', $newTrimmed );
- $newSliced = array_slice( $newSplit, 2 );
- $newRelPath = implode( '/', $newSliced );
- $newKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $newRelPath . '.key';
-
- // Rename keyfile so it isn't orphaned
- $result = $view->rename( $oldKeyfilePath, $newKeyfilePath );
-
- \OC_FileProxy::$enabled = true;
-
- return $result;
-
+ public function postTouch($path) {
+ $this->handleFile($path);
+
+ return true;
}
-
- public function postFopen( $path, &$result ){
-
- if ( !$result ) {
-
+
+ /**
+ * @param $path
+ * @param $result
+ * @return resource
+ */
+ public function postFopen($path, &$result) {
+
+ if (!$result) {
+
return $result;
-
+
}
-
- // Reformat path for use with OC_FSV
- $path_split = explode( '/', $path );
- $path_f = implode( array_slice( $path_split, 3 ) );
-
+
+ // split the path parts
+ $pathParts = explode('/', $path);
+
+ // get relative path
+ $relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
+
+ // FIXME: handling for /userId/cache used by webdav for chunking. The cache chunks are NOT encrypted
+ if (isset($pathParts[2]) && $pathParts[2] === 'cache') {
+ return $result;
+ }
+
// Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
-
- $meta = stream_get_meta_data( $result );
-
- $view = new \OC_FilesystemView( '' );
-
- $util = new Util( $view, \OCP\USER::getUser());
-
+
+ $meta = stream_get_meta_data($result);
+
+ $view = new \OC_FilesystemView('');
+
+ $util = new Util($view, \OCP\USER::getUser());
+
// If file is already encrypted, decrypt using crypto protocol
- if (
- Crypt::mode() == 'server'
- && $util->isEncryptedPath( $path )
+ if (
+ Crypt::mode() === 'server'
+ && $util->isEncryptedPath($path)
) {
-
+
// Close the original encrypted file
- fclose( $result );
-
+ fclose($result);
+
// Open the file using the crypto stream wrapper
// protocol and let it do the decryption work instead
- $result = fopen( 'crypt://' . $path_f, $meta['mode'] );
-
-
- } elseif (
- self::shouldEncrypt( $path )
- and $meta ['mode'] != 'r'
- and $meta['mode'] != 'rb'
+ $result = fopen('crypt://' . $relativePath, $meta['mode']);
+
+ } elseif (
+ self::shouldEncrypt($path)
+ and $meta ['mode'] !== 'r'
+ and $meta['mode'] !== 'rb'
) {
- // If the file is not yet encrypted, but should be
- // encrypted when it's saved (it's not read only)
-
- // NOTE: this is the case for new files saved via WebDAV
-
- if (
- $view->file_exists( $path )
- and $view->filesize( $path ) > 0
- ) {
- $x = $view->file_get_contents( $path );
-
- $tmp = tmpfile();
-
-// // Make a temporary copy of the original file
-// \OCP\Files::streamCopy( $result, $tmp );
-//
-// // Close the original stream, we'll return another one
-// fclose( $result );
-//
-// $view->file_put_contents( $path_f, $tmp );
-//
-// fclose( $tmp );
-
- }
-
- $result = fopen( 'crypt://'.$path_f, $meta['mode'] );
-
+ $result = fopen('crypt://' . $relativePath, $meta['mode']);
}
-
+
// Re-enable the proxy
- \OC_FileProxy::$enabled = true;
-
+ \OC_FileProxy::$enabled = $proxyStatus;
+
return $result;
-
- }
- public function postGetMimeType( $path, $mime ) {
-
- if ( Crypt::isCatfile( $path ) ) {
-
- $mime = \OCP\Files::getMimeType( 'crypt://' . $path, 'w' );
-
- }
-
- return $mime;
-
}
- public function postStat( $path, $data ) {
-
- if ( Crypt::isCatfile( $path ) ) {
-
- $cached = \OC\Files\Filesystem::getFileInfo( $path, '' );
-
- $data['size'] = $cached['size'];
-
+ /**
+ * @param $path
+ * @param $data
+ * @return array
+ */
+ public function postGetFileInfo($path, $data) {
+
+ // if path is a folder do nothing
+ if (is_array($data) && array_key_exists('size', $data)) {
+
+ // Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ // get file size
+ $data['size'] = self::postFileSize($path, $data['size']);
+
+ // Re-enable the proxy
+ \OC_FileProxy::$enabled = $proxyStatus;
}
-
+
return $data;
}
- public function postFileSize( $path, $size ) {
-
- if ( Crypt::isCatfile( $path ) ) {
-
- $cached = \OC\Files\Filesystem::getFileInfo( $path, '' );
-
- return $cached['size'];
-
- } else {
-
+ /**
+ * @param $path
+ * @param $size
+ * @return bool
+ */
+ public function postFileSize($path, $size) {
+
+ $view = new \OC_FilesystemView('/');
+
+ // if path is a folder do nothing
+ if ($view->is_dir($path)) {
return $size;
-
}
+
+ // get relative path
+ $relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
+
+ // if path is empty we cannot resolve anything
+ if (empty($relativePath)) {
+ return $size;
+ }
+
+ $fileInfo = false;
+ // get file info from database/cache if not .part file
+ if (!Keymanager::isPartialFilePath($path)) {
+ $fileInfo = $view->getFileInfo($path);
+ }
+
+ // if file is encrypted return real file size
+ if (is_array($fileInfo) && $fileInfo['encrypted'] === true) {
+ $size = $fileInfo['unencrypted_size'];
+ } else {
+ // self healing if file was removed from file cache
+ if (!is_array($fileInfo)) {
+ $fileInfo = array();
+ }
+
+ $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 if not .part file
+ if (!Keymanager::isPartialFilePath($relativePath)) {
+ $view->putFileInfo($path, $fileInfo);
+ }
+ }
+
+ }
+ return $size;
+ }
+
+ /**
+ * @param $path
+ */
+ 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 \OCA\Encryption\Session($view);
+ $userId = \OCP\User::getUser();
+ $util = new Util($view, $userId);
+
+ // split the path parts
+ $pathParts = explode('/', $path);
+
+ // get relative path
+ $relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
+
+ // only if file is on 'files' folder fix file size and sharing
+ if (isset($pathParts[2]) && $pathParts[2] === 'files' && $util->fixFileSize($path)) {
+
+ // get sharing app state
+ $sharingEnabled = \OCP\Share::isEnabled();
+
+ // get users
+ $usersSharing = $util->getSharingUsersArray($sharingEnabled, $relativePath);
+
+ // update sharing-keys
+ $util->setSharedFileKeyfiles($session, $usersSharing, $relativePath);
+ }
+
+ \OC_FileProxy::$enabled = $proxyStatus;
}
}
diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php
index 769a40b359f..bff1737554b 100644
--- a/apps/files_encryption/lib/session.php
+++ b/apps/files_encryption/lib/session.php
@@ -28,76 +28,164 @@ namespace OCA\Encryption;
class Session {
+ private $view;
+
+ /**
+ * @brief if session is started, check if ownCloud key pair is set up, if not create it
+ * @param \OC_FilesystemView $view
+ *
+ * @note The ownCloud key pair is used to allow public link sharing even if encryption is enabled
+ */
+ public function __construct($view) {
+
+ $this->view = $view;
+
+ if (!$this->view->is_dir('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/" . $publicShareKeyId . ".public.key")
+ || !$this->view->file_exists("/owncloud_private_key/" . $publicShareKeyId . ".private.key")
+ ) {
+
+ $keypair = Crypt::createKeypair();
+
+ // Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ // 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 empty passphrase
+ $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], '');
+
+ // Save private key
+ $this->view->file_put_contents(
+ '/owncloud_private_key/' . $publicShareKeyId . '.private.key', $encryptedPrivateKey);
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ }
+
+ if (\OCA\Encryption\Helper::isPublicAccess()) {
+ // 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->setPublicSharePrivateKey( $privateKey );
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+ }
+ }
+
/**
* @brief Sets user private key to session
+ * @param string $privateKey
* @return bool
*
+ * @note this should only be set on login
*/
- public function setPrivateKey( $privateKey ) {
-
- $_SESSION['privateKey'] = $privateKey;
-
+ public function setPrivateKey($privateKey) {
+
+ \OC::$session->set('privateKey', $privateKey);
+
return true;
-
+
}
-
+
/**
- * @brief Gets user private key from session
+ * @brief Gets user or public share private key from session
* @returns string $privateKey The user's plaintext private key
*
*/
public function getPrivateKey() {
-
- if (
- isset( $_SESSION['privateKey'] )
- && !empty( $_SESSION['privateKey'] )
- ) {
-
- return $_SESSION['privateKey'];
-
+ // return the public share private key if this is a public access
+ if (\OCA\Encryption\Helper::isPublicAccess()) {
+ return $this->getPublicSharePrivateKey();
} else {
-
- return false;
-
+ if (!is_null( \OC::$session->get('privateKey') )) {
+ return \OC::$session->get('privateKey');
+ } else {
+ return false;
+ }
}
-
}
-
+
/**
- * @brief Sets user legacy key to session
+ * @brief Sets public user private key to session
+ * @param string $privateKey
* @return bool
+ */
+ public function setPublicSharePrivateKey($privateKey) {
+
+ \OC::$session->set('publicSharePrivateKey', $privateKey);
+
+ return true;
+
+ }
+
+ /**
+ * @brief Gets public share private key from session
+ * @returns string $privateKey
*
*/
- public function setLegacyKey( $legacyKey ) {
-
- if ( $_SESSION['legacyKey'] = $legacyKey ) {
-
- return true;
-
+ public function getPublicSharePrivateKey() {
+
+ if (!is_null( \OC::$session->get('publicSharePrivateKey') )) {
+ return \OC::$session->get('publicSharePrivateKey');
+ } else {
+ return false;
}
-
}
-
+
+
+ /**
+ * @brief Sets user legacy key to session
+ * @param $legacyKey
+ * @return bool
+ */
+ public function setLegacyKey($legacyKey) {
+
+ \OC::$session->set('legacyKey', $legacyKey);
+
+ return true;
+ }
+
/**
* @brief Gets user legacy key from session
* @returns string $legacyKey The user's plaintext legacy key
*
*/
public function getLegacyKey() {
-
- if (
- isset( $_SESSION['legacyKey'] )
- && !empty( $_SESSION['legacyKey'] )
- ) {
-
- return $_SESSION['legacyKey'];
-
+
+ if ( !is_null( \OC::$session->get('legacyKey') ) ) {
+
+ return \OC::$session->get('legacyKey');
+
} else {
-
+
return false;
-
+
}
-
+
}
-} \ No newline at end of file
+}
diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php
index 65d7d57a05a..072c5286644 100644
--- a/apps/files_encryption/lib/stream.php
+++ b/apps/files_encryption/lib/stream.php
@@ -3,7 +3,7 @@
* ownCloud
*
* @author Robin Appelman
- * @copyright 2012 Sam Tuke <samtuke@owncloud.com>, 2011 Robin Appelman
+ * @copyright 2012 Sam Tuke <samtuke@owncloud.com>, 2011 Robin Appelman
* <icewind1991@gmail.com>
*
* This library is free software; you can redistribute it and/or
@@ -32,27 +32,28 @@ namespace OCA\Encryption;
/**
* @brief Provides 'crypt://' stream wrapper protocol.
- * @note We use a stream wrapper because it is the most secure way to handle
+ * @note We use a stream wrapper because it is the most secure way to handle
* decrypted content transfers. There is no safe way to decrypt the entire file
* somewhere on the server, so we have to encrypt and decrypt blocks on the fly.
* @note Paths used with this protocol MUST BE RELATIVE. Use URLs like:
- * crypt://filename, or crypt://subdirectory/filename, NOT
- * crypt:///home/user/owncloud/data. Otherwise keyfiles will be put in
- * [owncloud]/data/user/files_encryption/keyfiles/home/user/owncloud/data and
+ * crypt://filename, or crypt://subdirectory/filename, NOT
+ * crypt:///home/user/owncloud/data. Otherwise keyfiles will be put in
+ * [owncloud]/data/user/files_encryption/keyfiles/home/user/owncloud/data and
* will not be accessible to other methods.
- * @note Data read and written must always be 8192 bytes long, as this is the
- * buffer size used internally by PHP. The encryption process makes the input
- * data longer, and input is chunked into smaller pieces in order to result in
+ * @note Data read and written must always be 8192 bytes long, as this is the
+ * buffer size used internally by PHP. The encryption process makes the input
+ * data longer, and input is chunked into smaller pieces in order to result in
* a 8192 encrypted block size.
+ * @note When files are deleted via webdav, or when they are updated and the
+ * previous version deleted, this is handled by OC\Files\View, and thus the
+ * encryption proxies are used and keyfiles deleted.
*/
class Stream {
+ private $plainKey;
+ private $encKeyfiles;
- public static $sourceStreams = array();
-
- // TODO: make all below properties private again once unit testing is
- // configured correctly
- public $rawPath; // The raw path received by stream_open
- public $path_f; // The raw path formatted to include username and data dir
+ private $rawPath; // The raw path relative to the data dir
+ private $relPath; // rel path to users file dir
private $userId;
private $handle; // Resource returned by fopen
private $path;
@@ -60,226 +61,191 @@ class Stream {
private $meta = array(); // Header / meta for source stream
private $count;
private $writeCache;
- public $size;
+ private $size;
+ private $unencryptedSize;
private $publicKey;
private $keyfile;
private $encKeyfile;
private static $view; // a fsview object set to user dir
private $rootView; // a fsview object set to '/'
- public function stream_open( $path, $mode, $options, &$opened_path ) {
-
- // Get access to filesystem via filesystemview object
- if ( !self::$view ) {
-
- self::$view = new \OC_FilesystemView( $this->userId . '/' );
+ /**
+ * @param $path
+ * @param $mode
+ * @param $options
+ * @param $opened_path
+ * @return bool
+ */
+ public function stream_open($path, $mode, $options, &$opened_path) {
+ if (!isset($this->rootView)) {
+ $this->rootView = new \OC_FilesystemView('/');
}
-
- // Set rootview object if necessary
- if ( ! $this->rootView ) {
- $this->rootView = new \OC_FilesystemView( $this->userId . '/' );
+ $util = new Util($this->rootView, \OCP\USER::getUser());
- }
-
- $this->userId = \OCP\User::getUser();
-
- // Get the bare file path
- $path = str_replace( 'crypt://', '', $path );
-
- $this->rawPath = $path;
-
- $this->path_f = $this->userId . '/files/' . $path;
-
- if (
- dirname( $path ) == 'streams'
- and isset( self::$sourceStreams[basename( $path )] )
- ) {
-
- // Is this just for unit testing purposes?
+ $this->userId = $util->getUserId();
- $this->handle = self::$sourceStreams[basename( $path )]['stream'];
+ // 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));
- $this->path = self::$sourceStreams[basename( $path )]['path'];
+ // rawPath is relative to the data directory
+ $this->rawPath = $util->getUserFilesDir() . $this->relPath;
- $this->size = self::$sourceStreams[basename( $path )]['size'];
+ // Disable fileproxies so we can get the file size and open the source file without recursive encryption
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
- } else {
+ if (
+ $mode === 'w'
+ or $mode === 'w+'
+ or $mode === 'wb'
+ or $mode === 'wb+'
+ ) {
- if (
- $mode == 'w'
- or $mode == 'w+'
- or $mode == 'wb'
- or $mode == 'wb+'
- ) {
+ // We're writing a new file so start write counter with 0 bytes
+ $this->size = 0;
+ $this->unencryptedSize = 0;
- $this->size = 0;
+ } else {
- } else {
-
-
-
- $this->size = self::$view->filesize( $this->path_f, $mode );
-
- //$this->size = filesize( $path );
-
- }
+ $this->size = $this->rootView->filesize($this->rawPath, $mode);
+ }
- // Disable fileproxies so we can open the source file without recursive encryption
- \OC_FileProxy::$enabled = false;
+ $this->handle = $this->rootView->fopen($this->rawPath, $mode);
- //$this->handle = fopen( $path, $mode );
-
- $this->handle = self::$view->fopen( $this->path_f, $mode );
-
- \OC_FileProxy::$enabled = true;
+ \OC_FileProxy::$enabled = $proxyStatus;
- if ( !is_resource( $this->handle ) ) {
+ if (!is_resource($this->handle)) {
- \OCP\Util::writeLog( 'files_encryption', 'failed to open '.$path, \OCP\Util::ERROR );
+ \OCP\Util::writeLog('files_encryption', 'failed to open file "' . $this->rawPath . '"', \OCP\Util::ERROR);
- }
+ } else {
+
+ $this->meta = stream_get_meta_data($this->handle);
}
- if ( is_resource( $this->handle ) ) {
- $this->meta = stream_get_meta_data( $this->handle );
+ return is_resource($this->handle);
- }
+ }
- return is_resource( $this->handle );
+ /**
+ * @param $offset
+ * @param int $whence
+ */
+ public function stream_seek($offset, $whence = SEEK_SET) {
- }
-
- public function stream_seek( $offset, $whence = SEEK_SET ) {
-
$this->flush();
-
- fseek( $this->handle, $offset, $whence );
-
- }
-
- public function stream_tell() {
- return ftell($this->handle);
+
+ fseek($this->handle, $offset, $whence);
+
}
-
- public function stream_read( $count ) {
-
+
+ /**
+ * @param $count
+ * @return bool|string
+ * @throws \Exception
+ */
+ public function stream_read($count) {
+
$this->writeCache = '';
- if ( $count != 8192 ) {
-
+ if ($count !== 8192) {
+
// $count will always be 8192 https://bugs.php.net/bug.php?id=21641
// This makes this function a lot simpler, but will break this class if the above 'bug' gets 'fixed'
- \OCP\Util::writeLog( 'files_encryption', 'PHP "bug" 21641 no longer holds, decryption system requires refactoring', \OCP\Util::FATAL );
+ \OCP\Util::writeLog('files_encryption', 'PHP "bug" 21641 no longer holds, decryption system requires refactoring', \OCP\Util::FATAL);
die();
}
-// $pos = ftell( $this->handle );
-//
// Get the data from the file handle
- $data = fread( $this->handle, 8192 );
-
- if ( strlen( $data ) ) {
-
- $this->getKey();
-
- $result = Crypt::symmetricDecryptFileContent( $data, $this->keyfile );
-
- } else {
+ $data = fread($this->handle, 8192);
- $result = '';
+ $result = '';
- }
+ if (strlen($data)) {
+
+ if (!$this->getKey()) {
+
+ // Error! We don't have a key to decrypt the file with
+ throw new \Exception(
+ 'Encryption key not found for "' . $this->rawPath . '" during attempted read via stream');
+
+ }
+
+ // Decrypt data
+ $result = Crypt::symmetricDecryptFileContent($data, $this->plainKey);
-// $length = $this->size - $pos;
-//
-// if ( $length < 8192 ) {
-//
-// $result = substr( $result, 0, $length );
-//
-// }
+ }
return $result;
}
-
+
/**
* @brief Encrypt and pad data ready for writing to disk
* @param string $plainData data to be encrypted
* @param string $key key to use for encryption
- * @return encrypted data on success, false on failure
+ * @return string encrypted data on success, false on failure
*/
- public function preWriteEncrypt( $plainData, $key ) {
-
+ public function preWriteEncrypt($plainData, $key) {
+
// Encrypt data to 'catfile', which includes IV
- if ( $encrypted = Crypt::symmetricEncryptFileContent( $plainData, $key ) ) {
-
- return $encrypted;
-
+ if ($encrypted = Crypt::symmetricEncryptFileContent($plainData, $key)) {
+
+ return $encrypted;
+
} else {
-
+
return false;
-
+
}
-
+
}
-
+
/**
- * @brief Get the keyfile for the current file, generate one if necessary
- * @param bool $generate if true, a new key will be generated if none can be found
+ * @brief Fetch the plain encryption key for the file and set it as plainKey property
+ * @internal param bool $generate if true, a new key will be generated if none can be found
* @return bool true on key found and set, false on key not found and new key generated and set
*/
public function getKey() {
-
- // If a keyfile already exists for a file named identically to
- // file to be written
- if ( self::$view->file_exists( $this->userId . '/'. 'files_encryption' . '/' . 'keyfiles' . '/' . $this->rawPath . '.key' ) ) {
-
- // TODO: add error handling for when file exists but no
- // keyfile
-
- // Fetch existing keyfile
- $this->encKeyfile = Keymanager::getFileKey( $this->rootView, $this->userId, $this->rawPath );
-
- $this->getUser();
-
- $session = new Session();
-
- $privateKey = $session->getPrivateKey( $this->userId );
-
- $this->keyfile = Crypt::keyDecrypt( $this->encKeyfile, $privateKey );
-
+
+ // Check if key is already set
+ if (isset($this->plainKey) && isset($this->encKeyfile)) {
+
return true;
-
+
+ }
+
+ // Fetch and decrypt keyfile
+ // Fetch existing keyfile
+ $this->encKeyfile = Keymanager::getFileKey($this->rootView, $this->userId, $this->relPath);
+
+ // If a keyfile already exists
+ if ($this->encKeyfile) {
+
+ $session = new \OCA\Encryption\Session( $this->rootView );
+
+ $privateKey = $session->getPrivateKey($this->userId);
+
+ $shareKey = Keymanager::getShareKey($this->rootView, $this->userId, $this->relPath);
+
+ $this->plainKey = Crypt::multiKeyDecrypt($this->encKeyfile, $shareKey, $privateKey);
+
+ return true;
+
} else {
-
+
return false;
-
- }
-
- }
-
- public function getuser() {
-
- // Only get the user again if it isn't already set
- if ( empty( $this->userId ) ) {
-
- // TODO: Move this user call out of here - it belongs
- // elsewhere
- $this->userId = \OCP\User::getUser();
-
+
}
-
- // TODO: Add a method for getting the user in case OCP\User::
- // getUser() doesn't work (can that scenario ever occur?)
-
+
}
-
+
/**
* @brief Handle plain data from the stream, and write it in 8192 byte blocks
* @param string $data data to be written to disk
@@ -289,99 +255,55 @@ class Stream {
* @note Padding is added to each encrypted block to ensure that the resulting block is exactly 8192 bytes. This is removed during stream_read
* @note PHP automatically updates the file pointer after writing data to reflect it's length. There is generally no need to update the poitner manually using fseek
*/
- public function stream_write( $data ) {
-
+ public function stream_write($data) {
+
// Disable the file proxies so that encryption is not
// automatically attempted when the file is written to disk -
// we are handling that separately here and we don't want to
// get into an infinite loop
+ $proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
-
+
// Get the length of the unencrypted data that we are handling
- $length = strlen( $data );
-
- // So far this round, no data has been written
- $written = 0;
-
- // Find out where we are up to in the writing of data to the
+ $length = strlen($data);
+
+ // Find out where we are up to in the writing of data to the
// file
- $pointer = ftell( $this->handle );
-
- // Make sure the userId is set
- $this->getuser();
-
- // TODO: Check if file is shared, if so, use multiKeyEncrypt and
- // save shareKeys in necessary user directories
-
+ $pointer = ftell($this->handle);
+
// Get / generate the keyfile for the file we're handling
// If we're writing a new file (not overwriting an existing
// one), save the newly generated keyfile
- if ( ! $this->getKey() ) {
-
- $this->keyfile = Crypt::generateKey();
-
- $this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId );
-
- $this->encKeyfile = Crypt::keyEncrypt( $this->keyfile, $this->publicKey );
-
- $view = new \OC_FilesystemView( '/' );
- $userId = \OCP\User::getUser();
-
- // Save the new encrypted file key
- Keymanager::setFileKey( $view, $this->rawPath, $userId, $this->encKeyfile );
-
+ if (!$this->getKey()) {
+
+ $this->plainKey = Crypt::generateKey();
+
}
// If extra data is left over from the last round, make sure it
// is integrated into the next 6126 / 8192 block
- if ( $this->writeCache ) {
-
+ if ($this->writeCache) {
+
// Concat writeCache to start of $data
$data = $this->writeCache . $data;
-
- // Clear the write cache, ready for resuse - it has been
+
+ // Clear the write cache, ready for reuse - it has been
// flushed and its old contents processed
$this->writeCache = '';
}
-//
-// // Make sure we always start on a block start
- if ( 0 != ( $pointer % 8192 ) ) {
- // if the current position of
- // file indicator is not aligned to a 8192 byte block, fix it
- // so that it is
-
-// fseek( $this->handle, - ( $pointer % 8192 ), SEEK_CUR );
-//
-// $pointer = ftell( $this->handle );
-//
-// $unencryptedNewBlock = fread( $this->handle, 8192 );
-//
-// fseek( $this->handle, - ( $currentPos % 8192 ), SEEK_CUR );
-//
-// $block = Crypt::symmetricDecryptFileContent( $unencryptedNewBlock, $this->keyfile );
-//
-// $x = substr( $block, 0, $currentPos % 8192 );
-//
-// $data = $x . $data;
-//
-// fseek( $this->handle, - ( $currentPos % 8192 ), SEEK_CUR );
-//
- }
-// $currentPos = ftell( $this->handle );
-
-// // While there still remains somed data to be processed & written
- while( strlen( $data ) > 0 ) {
-//
-// // Remaining length for this iteration, not of the
-// // entire file (may be greater than 8192 bytes)
-// $remainingLength = strlen( $data );
-//
-// // If data remaining to be written is less than the
-// // size of 1 6126 byte block
- if ( strlen( $data ) < 6126 ) {
-
+ // While there still remains some data to be processed & written
+ while (strlen($data) > 0) {
+
+ // Remaining length for this iteration, not of the
+ // entire file (may be greater than 8192 bytes)
+ $remainingLength = strlen($data);
+
+ // If data remaining to be written is less than the
+ // size of 1 6126 byte block
+ if ($remainingLength < 6126) {
+
// Set writeCache to contents of $data
// The writeCache will be carried over to the
// next write round, and added to the start of
@@ -394,101 +316,167 @@ class Stream {
// Clear $data ready for next round
$data = '';
-//
+
} else {
-
+
// Read the chunk from the start of $data
- $chunk = substr( $data, 0, 6126 );
-
- $encrypted = $this->preWriteEncrypt( $chunk, $this->keyfile );
-
+ $chunk = substr($data, 0, 6126);
+
+ $encrypted = $this->preWriteEncrypt($chunk, $this->plainKey);
+
// Write the data chunk to disk. This will be
// attended to the last data chunk if the file
// being handled totals more than 6126 bytes
- fwrite( $this->handle, $encrypted );
-
- $writtenLen = strlen( $encrypted );
- //fseek( $this->handle, $writtenLen, SEEK_CUR );
+ fwrite($this->handle, $encrypted);
- // Remove the chunk we just processed from
+ // Remove the chunk we just processed from
// $data, leaving only unprocessed data in $data
// var, for handling on the next round
- $data = substr( $data, 6126 );
+ $data = substr($data, 6126);
}
-
+
}
- $this->size = max( $this->size, $pointer + $length );
-
+ $this->size = max($this->size, $pointer + $length);
+ $this->unencryptedSize += $length;
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
return $length;
}
- public function stream_set_option( $option, $arg1, $arg2 ) {
- switch($option) {
+ /**
+ * @param $option
+ * @param $arg1
+ * @param $arg2
+ */
+ public function stream_set_option($option, $arg1, $arg2) {
+ $return = false;
+ switch ($option) {
case STREAM_OPTION_BLOCKING:
- stream_set_blocking( $this->handle, $arg1 );
+ $return = stream_set_blocking($this->handle, $arg1);
break;
case STREAM_OPTION_READ_TIMEOUT:
- stream_set_timeout( $this->handle, $arg1, $arg2 );
+ $return = stream_set_timeout($this->handle, $arg1, $arg2);
break;
case STREAM_OPTION_WRITE_BUFFER:
- stream_set_write_buffer( $this->handle, $arg1, $arg2 );
+ $return = stream_set_write_buffer($this->handle, $arg1);
}
+
+ return $return;
}
+ /**
+ * @return array
+ */
public function stream_stat() {
return fstat($this->handle);
}
-
- public function stream_lock( $mode ) {
- flock( $this->handle, $mode );
+
+ /**
+ * @param $mode
+ */
+ public function stream_lock($mode) {
+ return flock($this->handle, $mode);
}
-
+
+ /**
+ * @return bool
+ */
public function stream_flush() {
-
- return fflush( $this->handle );
+
+ return fflush($this->handle);
// Not a typo: http://php.net/manual/en/function.fflush.php
-
+
}
+ /**
+ * @return bool
+ */
public function stream_eof() {
return feof($this->handle);
}
private function flush() {
-
- if ( $this->writeCache ) {
-
+
+ if ($this->writeCache) {
+
// Set keyfile property for file in question
$this->getKey();
-
- $encrypted = $this->preWriteEncrypt( $this->writeCache, $this->keyfile );
-
- fwrite( $this->handle, $encrypted );
-
+
+ $encrypted = $this->preWriteEncrypt($this->writeCache, $this->plainKey);
+
+ fwrite($this->handle, $encrypted);
+
$this->writeCache = '';
-
+
}
-
+
}
+ /**
+ * @return bool
+ */
public function stream_close() {
-
+
$this->flush();
- if (
- $this->meta['mode']!='r'
- and $this->meta['mode']!='rb'
+ if (
+ $this->meta['mode'] !== 'r'
+ and $this->meta['mode'] !== 'rb'
+ and $this->size > 0
) {
+ // 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;
- \OC\Files\Filesystem::putFileInfo( $this->path, array( 'encrypted' => true, 'size' => $this->size ), '' );
+ // 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 );
+ return fclose($this->handle);
}
diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php
index 52bc74db27a..04bd4dc8aca 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
@@ -21,78 +21,82 @@
*
*/
-// Todo:
+# Bugs
+# ----
+# Sharing a file to a user without encryption set up will not provide them with access but won't notify the sharer
+# Sharing all files to admin for recovery purposes still in progress
+# Possibly public links are broken (not tested since last merge of master)
+
+
+# Missing features
+# ----------------
+# Make sure user knows if large files weren't encrypted
+
+
+# Test
+# ----
+# Test that writing files works when recovery is enabled, and sharing API is disabled
+# Test trashbin support
+
+
+// Old Todo:
// - Crypt/decrypt button in the userinterface
// - Setting if crypto should be on by default
// - Add a setting "Don´t encrypt files larger than xx because of performance
// reasons"
-// - Transparent decrypt/encrypt in filesystem.php. Autodetect if a file is
-// encrypted (.encrypted extension)
-// - Don't use a password directly as encryption key. but a key which is
-// stored on the server and encrypted with the user password. -> password
-// change faster
-// - IMPORTANT! Check if the block lenght of the encrypted data stays the same
namespace OCA\Encryption;
/**
* @brief Class for utilities relating to encrypted file storage system
- * @param OC_FilesystemView $view expected to have OC '/' as root path
+ * @param \OC_FilesystemView $view expected to have OC '/' as root path
* @param string $userId ID of the logged in user
* @param int $client indicating status of client side encryption. Currently
* unused, likely to become obsolete shortly
*/
class Util {
-
-
+
// Web UI:
-
+
//// DONE: files created via web ui are encrypted
//// DONE: file created & encrypted via web ui are readable in web ui
//// DONE: file created & encrypted via web ui are readable via webdav
-
-
+
+
// WebDAV:
-
+
//// DONE: new data filled files added via webdav get encrypted
//// DONE: new data filled files added via webdav are readable via webdav
//// DONE: reading unencrypted files when encryption is enabled works via
//// webdav
//// DONE: files created & encrypted via web ui are readable via webdav
-
-
+
+
// Legacy support:
-
+
//// DONE: add method to check if file is encrypted using new system
//// DONE: add method to check if file is encrypted using old system
//// DONE: add method to fetch legacy key
//// DONE: add method to decrypt legacy encrypted data
-
-
+
+
// Admin UI:
-
+
//// DONE: changing user password also changes encryption passphrase
-
+
//// 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
-
-
+
+
private $view; // OC_FilesystemView object for filesystem operations
private $userId; // ID of the currently logged-in user
private $pwd; // User Password
@@ -103,166 +107,322 @@ 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;
+
+ /**
+ * @param \OC_FilesystemView $view
+ * @param $userId
+ * @param bool $client
+ */
+ public function __construct(\OC_FilesystemView $view, $userId, $client = false) {
- public function __construct( \OC_FilesystemView $view, $userId, $client = false ) {
-
$this->view = $view;
$this->userId = $userId;
$this->client = $client;
- $this->userDir = '/' . $this->userId;
- $this->userFilesDir = '/' . $this->userId . '/' . 'files';
- $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 (\OCA\Encryption\Helper::isPublicAccess()) {
+ $this->userId = $this->publicShareKeyId;
+
+ // only handle for files_sharing app
+ if (isset($GLOBALS['app']) && $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
+ }
}
-
+
+ /**
+ * @return bool
+ */
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 )
+
+ 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)
) {
-
+
return false;
-
+
} else {
-
+
return true;
-
+
}
-
+
}
-
- /**
- * @brief Sets up user folders and keys for serverside encryption
- * @param $passphrase passphrase to encrypt server-stored private key with
- */
- public function setupServerSide( $passphrase = null ) {
-
- // Create user dir
- if( !$this->view->file_exists( $this->userDir ) ) {
-
- $this->view->mkdir( $this->userDir );
-
- }
-
- // Create user files dir
- if( !$this->view->file_exists( $this->userFilesDir ) ) {
-
- $this->view->mkdir( $this->userFilesDir );
-
- }
-
- // Create shared public key directory
- if( !$this->view->file_exists( $this->publicKeyDir ) ) {
-
- $this->view->mkdir( $this->publicKeyDir );
-
- }
-
- // Create encryption app directory
- if( !$this->view->file_exists( $this->encryptionDir ) ) {
-
- $this->view->mkdir( $this->encryptionDir );
-
- }
-
- // Create mirrored keyfile directory
- if( !$this->view->file_exists( $this->keyfilesPath ) ) {
-
- $this->view->mkdir( $this->keyfilesPath );
-
- }
-
- // Create mirrored share env keys directory
- if( !$this->view->file_exists( $this->shareKeysPath ) ) {
-
- $this->view->mkdir( $this->shareKeysPath );
-
- }
-
+
+ /**
+ * @brief Sets up user folders and keys for serverside encryption
+ *
+ * @param string $passphrase to encrypt server-stored private key with
+ * @return bool
+ */
+ public function setupServerSide($passphrase = null) {
+
+ // Set directories to check / create
+ $setUpDirs = array(
+ $this->userDir,
+ $this->userFilesDir,
+ $this->publicKeyDir,
+ $this->encryptionDir,
+ $this->keyfilesPath,
+ $this->shareKeysPath
+ );
+
+ // Check / create all necessary dirs
+ foreach ($setUpDirs as $dirPath) {
+
+ if (!$this->view->file_exists($dirPath)) {
+
+ $this->view->mkdir($dirPath);
+
+ }
+
+ }
+
// Create user keypair
- if (
- ! $this->view->file_exists( $this->publicKeyPath )
- or ! $this->view->file_exists( $this->privateKeyPath )
+ // we should never override a keyfile
+ if (
+ !$this->view->file_exists($this->publicKeyPath)
+ && !$this->view->file_exists($this->privateKeyPath)
) {
-
+
// Generate keypair
$keypair = Crypt::createKeypair();
-
+
\OC_FileProxy::$enabled = false;
-
+
// Save public key
- $this->view->file_put_contents( $this->publicKeyPath, $keypair['publicKey'] );
-
+ $this->view->file_put_contents($this->publicKeyPath, $keypair['publicKey']);
+
// Encrypt private key with user pwd as passphrase
- $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], $passphrase );
-
+ $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $passphrase);
+
// Save private key
- $this->view->file_put_contents( $this->privateKeyPath, $encryptedPrivateKey );
-
+ $this->view->file_put_contents($this->privateKeyPath, $encryptedPrivateKey);
+
\OC_FileProxy::$enabled = true;
-
+
+ } else {
+ // check if public-key exists but private-key is missing
+ if ($this->view->file_exists($this->publicKeyPath) && !$this->view->file_exists($this->privateKeyPath)) {
+ \OCP\Util::writeLog('Encryption library',
+ 'public key exists but private key is missing for "' . $this->userId . '"', \OCP\Util::FATAL);
+ return false;
+ } else {
+ if (!$this->view->file_exists($this->publicKeyPath) && $this->view->file_exists($this->privateKeyPath)
+ ) {
+ \OCP\Util::writeLog('Encryption library',
+ 'private key exists but public key is missing for "' . $this->userId . '"', \OCP\Util::FATAL);
+ return false;
+ }
+ }
}
-
+
+ // 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_enabled`) VALUES (?,?,?)';
+ $args = array(
+ $this->userId,
+ 'server-side',
+ 0
+ );
+ $query = \OCP\DB::prepare($sql);
+ $query->execute($args);
+
+ }
+
return true;
-
+
}
-
+
+ /**
+ * @return string
+ */
+ public function getPublicShareKeyId() {
+ return $this->publicShareKeyId;
+ }
+
+ /**
+ * @brief Check whether pwd recovery is enabled for a given user
+ * @return bool 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 recoveryEnabledForUser() {
+
+ $sql = 'SELECT `recovery_enabled` FROM `*PREFIX*encryption` WHERE uid = ?';
+
+ $args = array($this->userId);
+
+ $query = \OCP\DB::prepare($sql);
+
+ $result = $query->execute($args);
+
+ $recoveryEnabled = array();
+
+ if (\OCP\DB::isError($result)) {
+ \OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
+ } else {
+ if($result->numRows() > 0) {
+ $row = $result->fetchRow();
+ if (isset($row['recovery_enabled'])) {
+ $recoveryEnabled[] = $row['recovery_enabled'];
+ }
+ }
+ }
+
+ // If no record is found
+ if (empty($recoveryEnabled)) {
+
+ return false;
+
+ // If a record is found
+ } else {
+
+ return $recoveryEnabled[0];
+
+ }
+
+ }
+
+ /**
+ * @brief Enable / disable pwd recovery for a given user
+ * @param bool $enabled Whether to enable or disable recovery
+ * @return bool
+ */
+ public function setRecoveryForUser($enabled) {
+
+ $recoveryStatus = $this->recoveryEnabledForUser();
+
+ // If a record for this user already exists, update it
+ if (false === $recoveryStatus) {
+
+ $sql = 'INSERT INTO `*PREFIX*encryption` (`uid`,`mode`,`recovery_enabled`) VALUES (?,?,?)';
+
+ $args = array(
+ $this->userId,
+ 'server-side',
+ $enabled
+ );
+
+ // Create a new record instead
+ } else {
+
+ $sql = 'UPDATE `*PREFIX*encryption` SET recovery_enabled = ? WHERE uid = ?';
+
+ $args = array(
+ $enabled,
+ $this->userId
+ );
+
+ }
+
+ $query = \OCP\DB::prepare($sql);
+
+ if ($query->execute($args)) {
+
+ return true;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
/**
* @brief Find all files and their encryption status within a directory
* @param string $directory The path of the parent directory to search
+ * @param bool $found the founded files if called again
* @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
*/
- public function findFiles( $directory ) {
-
+ public function findEncFiles($directory, &$found = false) {
+
// Disable proxy - we don't want files to be decrypted before
// we handle them
\OC_FileProxy::$enabled = false;
-
- $found = array( 'plain' => array(), 'encrypted' => array(), 'legacy' => array() );
-
- if (
- $this->view->is_dir( $directory )
- && $handle = $this->view->opendir( $directory )
+
+ if ($found === false) {
+ $found = array(
+ 'plain' => array(),
+ 'encrypted' => array(),
+ 'legacy' => array()
+ );
+ }
+
+ if (
+ $this->view->is_dir($directory)
+ && $handle = $this->view->opendir($directory)
) {
-
- while ( false !== ( $file = readdir( $handle ) ) ) {
-
+
+ while (false !== ($file = readdir($handle))) {
+
if (
- $file != "."
- && $file != ".."
+ $file !== "."
+ && $file !== ".."
) {
-
- $filePath = $directory . '/' . $this->view->getRelativePath( '/' . $file );
- $relPath = $this->stripUserFilesPath( $filePath );
-
+
+ $filePath = $directory . '/' . $this->view->getRelativePath('/' . $file);
+ $relPath = \OCA\Encryption\Helper::stripUserFilesPath($filePath);
+
// If the path is a directory, search
// its contents
- if ( $this->view->is_dir( $filePath ) ) {
-
- $this->findFiles( $filePath );
-
- // If the path is a file, determine
- // its encryption status
- } elseif ( $this->view->is_file( $filePath ) ) {
-
+ if ($this->view->is_dir($filePath)) {
+
+ $this->findEncFiles($filePath, $found);
+
+ // If the path is a file, determine
+ // its encryption status
+ } elseif ($this->view->is_file($filePath)) {
+
// Disable proxies again, some-
// where they got re-enabled :/
\OC_FileProxy::$enabled = false;
-
- $data = $this->view->file_get_contents( $filePath );
-
+
+ $data = $this->view->file_get_contents($filePath);
+
// If the file is encrypted
// NOTE: If the userId is
// empty or not set, file will
@@ -270,207 +430,1118 @@ class Util {
// NOTE: This is inefficient;
// scanning every file like this
// will eat server resources :(
- if (
- Keymanager::getFileKey( $this->view, $this->userId, $file )
- && Crypt::isCatfile( $data )
+ if (
+ Keymanager::getFileKey($this->view, $this->userId, $relPath)
+ && Crypt::isCatfileContent($data)
) {
-
- $found['encrypted'][] = array( 'name' => $file, 'path' => $filePath );
-
- // If the file uses old
- // encryption system
- } elseif ( Crypt::isLegacyEncryptedContent( $this->view->file_get_contents( $filePath ), $relPath ) ) {
-
- $found['legacy'][] = array( 'name' => $file, 'path' => $filePath );
-
- // If the file is not encrypted
+
+ $found['encrypted'][] = array(
+ 'name' => $file,
+ 'path' => $filePath
+ );
+
+ // If the file uses old
+ // encryption system
+ } elseif ( Crypt::isLegacyEncryptedContent( $data, $relPath ) ) {
+
+ $found['legacy'][] = array(
+ 'name' => $file,
+ 'path' => $filePath
+ );
+
+ // If the file is not encrypted
} else {
-
- $found['plain'][] = array( 'name' => $file, 'path' => $filePath );
-
+
+ $found['plain'][] = array(
+ 'name' => $file,
+ 'path' => $relPath
+ );
+
}
-
+
}
-
+
}
-
+
}
-
+
\OC_FileProxy::$enabled = true;
-
- if ( empty( $found ) ) {
-
+
+ if (empty($found)) {
+
return false;
-
+
} else {
-
+
return $found;
-
+
}
-
+
}
-
+
\OC_FileProxy::$enabled = true;
-
+
return 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
- // original form
+
+ /**
+ * @brief Fetch the last lines of a file efficiently
+ * @note Safe to use on large files; does not read entire file to memory
+ * @note Derivative of http://tekkie.flashbit.net/php/tail-functionality-in-php
+ */
+ public function tail($filename, $numLines) {
+
\OC_FileProxy::$enabled = false;
-
- $data = $this->view->file_get_contents( $path );
-
+
+ $text = '';
+ $pos = -1;
+ $handle = $this->view->fopen($filename, 'r');
+
+ while ($numLines > 0) {
+
+ --$pos;
+
+ if (fseek($handle, $pos, SEEK_END) !== 0) {
+
+ rewind($handle);
+ $numLines = 0;
+
+ } elseif (fgetc($handle) === "\n") {
+
+ --$numLines;
+
+ }
+
+ $block_size = (-$pos) % 8192;
+ if ($block_size === 0 || $numLines === 0) {
+
+ $text = fread($handle, ($block_size === 0 ? 8192 : $block_size)) . $text;
+
+ }
+ }
+
+ fclose($handle);
+
\OC_FileProxy::$enabled = true;
-
- return Crypt::isCatfile( $data );
-
+
+ return $text;
}
-
+
/**
- * @brief Format a path to be relative to the /user/files/ directory
+ * @brief Check if a given path identifies an encrypted file
+ * @param string $path
+ * @return boolean
*/
- public function stripUserFilesPath( $path ) {
-
- $trimmed = ltrim( $path, '/' );
- $split = explode( '/', $trimmed );
- $sliced = array_slice( $split, 2 );
- $relPath = implode( '/', $sliced );
-
- return $relPath;
-
+ public function isEncryptedPath($path) {
+
+ // Disable encryption proxy so data retrieved is in its
+ // original form
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ // we only need 24 byte from the last chunk
+ $data = '';
+ $handle = $this->view->fopen($path, 'r');
+ if (is_resource($handle) && !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 string $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;
+
+ // split the path parts
+ $pathParts = explode('/', $path);
+
+ // get relative path
+ $relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
+
+ if (isset($pathParts[2]) && $pathParts[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
+ $lastChunkNr = floor($size / 8192);
+
+ // open stream
+ $stream = fopen('crypt://' . $relativePath, "r");
+
+ if (is_resource($stream)) {
+ // calculate last chunk position
+ $lastChunckPos = ($lastChunkNr * 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 = (($lastChunkNr * 6126) + strlen($lastChunkContent));
+
+ // store file size
+ $result = $realSize;
+ }
+ }
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ return $result;
}
+
+ /**
+ * @brief fix the file size of the encrypted file
+ * @param string $path absolute path
+ * @return boolean 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;
+ }
+
/**
+ * @param $path
+ * @return bool
+ */
+ public function isSharedPath($path) {
+
+ $trimmed = ltrim($path, '/');
+ $split = explode('/', $trimmed);
+
+ if (isset($split[2]) && $split[2] === 'Shared') {
+
+ return true;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+ /**
* @brief Encrypt all files in a directory
- * @param string $publicKey the public key to encrypt files with
* @param string $dirPath the directory whose files will be encrypted
+ * @param null $legacyPassphrase
+ * @param null $newPassphrase
+ * @return bool
* @note Encryption is recursive
*/
- public function encryptAll( $publicKey, $dirPath, $legacyPassphrase = null, $newPassphrase = null ) {
-
- if ( $found = $this->findFiles( $dirPath ) ) {
-
+ public function encryptAll($dirPath, $legacyPassphrase = null, $newPassphrase = null) {
+
+ if ($found = $this->findEncFiles($dirPath)) {
+
// Disable proxy to prevent file being encrypted twice
\OC_FileProxy::$enabled = false;
-
+
// Encrypt unencrypted files
- foreach ( $found['plain'] as $plainFile ) {
-
- // Fetch data from file
- $plainData = $this->view->file_get_contents( $plainFile['path'] );
-
- // Encrypt data, generate catfile
- $encrypted = Crypt::keyEncryptKeyfile( $plainData, $publicKey );
-
- $relPath = $this->stripUserFilesPath( $plainFile['path'] );
-
- // Save keyfile
- Keymanager::setFileKey( $this->view, $relPath, $this->userId, $encrypted['key'] );
-
- // Overwrite the existing file with the encrypted one
- $this->view->file_put_contents( $plainFile['path'], $encrypted['data'] );
-
- $size = strlen( $encrypted['data'] );
-
+ foreach ($found['plain'] as $plainFile) {
+
+ //relative to data/<user>/file
+ $relPath = $plainFile['path'];
+
+ //relative to /data
+ $rawPath = '/'.$this->userId . '/files/' . $plainFile['path'];
+
+ // Open plain file handle for binary reading
+ $plainHandle = $this->view->fopen( $rawPath, 'rb' );
+
+ // Open enc file handle for binary writing, with same filename as original plain file
+ $encHandle = fopen( 'crypt://' . $relPath.'.tmp', 'wb' );
+
+ // Move plain file to a temporary location
+ $size = stream_copy_to_stream( $plainHandle, $encHandle );
+
+ fclose($encHandle);
+
+ $fakeRoot = $this->view->getRoot();
+ $this->view->chroot('/'.$this->userId.'/files');
+
+ $this->view->rename($relPath . '.tmp', $relPath);
+
+ $this->view->chroot($fakeRoot);
+
// Add the file to the cache
- \OC\Files\Filesystem::putFileInfo( $plainFile['path'], array( 'encrypted'=>true, 'size' => $size ), '' );
-
+ \OC\Files\Filesystem::putFileInfo( $relPath, array( 'encrypted' => true, 'size' => $size, 'unencrypted_size' => $size ) );
}
-
+
// Encrypt legacy encrypted files
- if (
- ! empty( $legacyPassphrase )
- && ! empty( $newPassphrase )
+ if (
+ !empty($legacyPassphrase)
+ && !empty($newPassphrase)
) {
-
- foreach ( $found['legacy'] as $legacyFile ) {
-
+
+ foreach ($found['legacy'] as $legacyFile) {
+
// Fetch data from file
- $legacyData = $this->view->file_get_contents( $legacyFile['path'] );
-
+ $legacyData = $this->view->file_get_contents($legacyFile['path']);
+
+ $sharingEnabled = \OCP\Share::isEnabled();
+
+ // if file exists try to get sharing users
+ if ($this->view->file_exists($legacyFile['path'])) {
+ $uniqueUserIds = $this->getSharingUsersArray($sharingEnabled, $legacyFile['path'], $this->userId);
+ } else {
+ $uniqueUserIds[] = $this->userId;
+ }
+
+ // Fetch public keys for all users who will share the file
+ $publicKeys = Keymanager::getPublicKeys($this->view, $uniqueUserIds);
+
// Recrypt data, generate catfile
- $recrypted = Crypt::legacyKeyRecryptKeyfile( $legacyData, $legacyPassphrase, $publicKey, $newPassphrase );
-
- $relPath = $this->stripUserFilesPath( $legacyFile['path'] );
-
+ $recrypted = Crypt::legacyKeyRecryptKeyfile( $legacyData, $legacyPassphrase, $publicKeys );
+
+ $rawPath = $legacyFile['path'];
+ $relPath = \OCA\Encryption\Helper::stripUserFilesPath($rawPath);
+
// Save keyfile
- Keymanager::setFileKey( $this->view, $relPath, $this->userId, $recrypted['key'] );
-
+ Keymanager::setFileKey($this->view, $relPath, $this->userId, $recrypted['filekey']);
+
+ // Save sharekeys to user folders
+ Keymanager::setShareKeys($this->view, $relPath, $recrypted['sharekeys']);
+
// Overwrite the existing file with the encrypted one
- $this->view->file_put_contents( $legacyFile['path'], $recrypted['data'] );
-
- $size = strlen( $recrypted['data'] );
-
+ $this->view->file_put_contents($rawPath, $recrypted['data']);
+
+ $size = strlen($recrypted['data']);
+
// Add the file to the cache
- \OC\Files\Filesystem::putFileInfo( $legacyFile['path'], array( 'encrypted'=>true, 'size' => $size ), '' );
-
+ \OC\Files\Filesystem::putFileInfo($rawPath, array(
+ 'encrypted' => true,
+ 'size' => $size
+ ), '');
}
-
}
-
+
\OC_FileProxy::$enabled = true;
-
+
// If files were found, return true
return true;
-
} else {
-
+
// If no files were found, return false
return false;
-
}
-
}
-
+
/**
* @brief Return important encryption related paths
* @param string $pathName Name of the directory to return the path of
* @return string path
*/
- public function getPath( $pathName ) {
-
- switch ( $pathName ) {
-
+ public function getPath($pathName) {
+
+ switch ($pathName) {
+
case 'publicKeyDir':
-
+
return $this->publicKeyDir;
-
+
break;
-
+
case 'encryptionDir':
-
+
return $this->encryptionDir;
-
+
break;
-
+
case 'keyfilesPath':
-
+
return $this->keyfilesPath;
-
+
break;
-
+
case 'publicKeyPath':
-
+
return $this->publicKeyPath;
-
+
break;
-
+
case 'privateKeyPath':
-
+
return $this->privateKeyPath;
-
+
break;
-
}
-
+
+ return false;
+
+ }
+
+ /**
+ * @brief get path of a file.
+ * @param int $fileId id of the file
+ * @return string path of the file
+ */
+ public static function fileIdToPath($fileId) {
+
+ $sql = 'SELECT `path` FROM `*PREFIX*filecache` WHERE `fileid` = ?';
+
+ $query = \OCP\DB::prepare($sql);
+
+ $result = $query->execute(array($fileId));
+
+ $path = false;
+ if (\OCP\DB::isError($result)) {
+ \OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
+ } else {
+ if($result->numRows() > 0) {
+ $row = $result->fetchRow();
+ $path = substr($row['path'], strlen('files'));
+ }
+ }
+
+ return $path;
+
+ }
+
+ /**
+ * @brief Filter an array of UIDs to return only ones ready for sharing
+ * @param array $unfilteredUsers users to be checked for sharing readiness
+ * @return array as multi-dimensional array. keys: ready, unready
+ */
+ public function filterShareReadyUsers($unfilteredUsers) {
+
+ // This array will collect the filtered IDs
+ $readyIds = $unreadyIds = array();
+
+ // Loop through users and create array of UIDs that need new keyfiles
+ foreach ($unfilteredUsers as $user) {
+
+ $util = new Util($this->view, $user);
+
+ // Check that the user is encryption capable, or is the
+ // public system user 'ownCloud' (for public shares)
+ if (
+ $user === $this->publicShareKeyId
+ or $user === $this->recoveryKeyId
+ or $util->ready()
+ ) {
+
+ // Construct array of ready UIDs for Keymanager{}
+ $readyIds[] = $user;
+
+ } else {
+
+ // Construct array of unready UIDs for Keymanager{}
+ $unreadyIds[] = $user;
+
+ // Log warning; we can't do necessary setup here
+ // because we don't have the user passphrase
+ \OCP\Util::writeLog('Encryption library',
+ '"' . $user . '" is not setup for encryption', \OCP\Util::WARN);
+
+ }
+
+ }
+
+ return array(
+ 'ready' => $readyIds,
+ 'unready' => $unreadyIds
+ );
+
+ }
+
+ /**
+ * @brief Decrypt a keyfile without knowing how it was encrypted
+ * @param string $filePath
+ * @param string $fileOwner
+ * @param string $privateKey
+ * @return bool|string
+ * @note Checks whether file was encrypted with openssl_seal or
+ * openssl_encrypt, and decrypts accrdingly
+ * @note This was used when 2 types of encryption for keyfiles was used,
+ * but now we've switched to exclusively using openssl_seal()
+ */
+ public function decryptUnknownKeyfile($filePath, $fileOwner, $privateKey) {
+
+ // Get the encrypted keyfile
+ // NOTE: the keyfile format depends on how it was encrypted! At
+ // this stage we don't know how it was encrypted
+ $encKeyfile = Keymanager::getFileKey($this->view, $this->userId, $filePath);
+
+ // We need to decrypt the keyfile
+ // Has the file been shared yet?
+ if (
+ $this->userId === $fileOwner
+ && !Keymanager::getShareKey($this->view, $this->userId, $filePath) // NOTE: we can't use isShared() here because it's a post share hook so it always returns true
+ ) {
+
+ // The file has no shareKey, and its keyfile must be
+ // decrypted conventionally
+ $plainKeyfile = Crypt::keyDecrypt($encKeyfile, $privateKey);
+
+
+ } else {
+
+ // The file has a shareKey and must use it for decryption
+ $shareKey = Keymanager::getShareKey($this->view, $this->userId, $filePath);
+
+ $plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey);
+
+ }
+
+ return $plainKeyfile;
+
+ }
+
+ /**
+ * @brief Encrypt keyfile to multiple users
+ * @param Session $session
+ * @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);
+
+ // If we're attempting to share to unready users
+ if (!empty($filteredUids['unready'])) {
+
+ \OCP\Util::writeLog('Encryption library',
+ 'Sharing to these user(s) failed as they are unready for encryption:"'
+ . print_r($filteredUids['unready'], 1), \OCP\Util::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
+ $privateKey = $session->getPrivateKey();
+
+ $fileOwner = \OC\Files\Filesystem::getOwner($filePath);
+
+ // Decrypt keyfile
+ $plainKeyfile = $this->decryptUnknownKeyfile($filePath, $fileOwner, $privateKey);
+
+ // Re-enc keyfile to (additional) sharekeys
+ $multiEncKey = Crypt::multiKeyEncrypt($plainKeyfile, $userPubKeys);
+
+ // Save the recrypted key to it's owner's keyfiles directory
+ // Save new sharekeys to all necessary user directory
+ if (
+ !Keymanager::setFileKey($this->view, $filePath, $fileOwner, $multiEncKey['data'])
+ || !Keymanager::setShareKeys($this->view, $filePath, $multiEncKey['keys'])
+ ) {
+
+ \OCP\Util::writeLog('Encryption library',
+ 'Keyfiles could not be saved for users sharing ' . $filePath, \OCP\Util::ERROR);
+
+ return false;
+
+ }
+
+ // Return proxy to original status
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ return true;
+ }
+
+ /**
+ * @brief Find, sanitise and format users sharing a file
+ * @note This wraps other methods into a portable bundle
+ */
+ public function getSharingUsersArray($sharingEnabled, $filePath, $currentUserId = false) {
+
+ // Check if key recovery is enabled
+ 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);
+
+ $userIds = array();
+ if ($sharingEnabled) {
+
+ // Find out who, if anyone, is sharing the file
+ $result = \OCP\Share::getUsersSharingFile($ownerPath, $owner, 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) {
+
+ // 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;
+
+ }
+
+ // Remove duplicate UIDs
+ $uniqueUserIds = array_unique($userIds);
+
+ return $uniqueUserIds;
+
+ }
+
+ /**
+ * @brief Set file migration status for user
+ * @param $status
+ * @return bool
+ */
+ public function setMigrationStatus($status) {
+
+ $sql = 'UPDATE `*PREFIX*encryption` SET migration_status = ? WHERE uid = ?';
+
+ $args = array(
+ $status,
+ $this->userId
+ );
+
+ $query = \OCP\DB::prepare($sql);
+
+ if ($query->execute($args)) {
+
+ return true;
+
+ } else {
+
+ return false;
+
+ }
+
+ }
+
+ /**
+ * @brief Check whether pwd recovery is enabled for a given user
+ * @return bool 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 `migration_status` FROM `*PREFIX*encryption` WHERE uid = ?';
+
+ $args = array($this->userId);
+
+ $query = \OCP\DB::prepare($sql);
+
+ $result = $query->execute($args);
+
+ $migrationStatus = array();
+
+ if (\OCP\DB::isError($result)) {
+ \OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
+ } else {
+ if($result->numRows() > 0) {
+ $row = $result->fetchRow();
+ if (isset($row['migration_status'])) {
+ $migrationStatus[] = $row['migration_status'];
+ }
+ }
+ }
+
+ // 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 string $path Path of the file to check
+ * @throws \Exception
+ * @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 ($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
+
+ }
+
+ return array(
+ $fileOwnerUid,
+ $filename
+ );
+ }
+
+
+ }
+
+ /**
+ * @brief go recursively through a dir and collect all files and sub files.
+ * @param string $dir relative to the users files folder
+ * @return array with list of files relative to the users files folder
+ */
+ public function getAllFiles($dir) {
+
+ $result = array();
+
+ $content = $this->view->getDirectoryContent(\OC\Files\Filesystem::normalizePath($this->userFilesDir . '/' . $dir));
+
+ // handling for re shared folders
+ $pathSplit = explode('/', $dir);
+
+ foreach ($content as $c) {
+
+ $sharedPart = $pathSplit[sizeof($pathSplit) - 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;
+
+ if ($c['type'] === 'dir') {
+
+ $result = array_merge($result, $this->getAllFiles($path));
+
+ } else {
+
+ $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) {
+
+ $sql = 'SELECT `file_target`, `item_type` FROM `*PREFIX*share` WHERE `id` = ?';
+
+ $query = \OCP\DB::prepare($sql);
+
+ $result = $query->execute(array($id));
+
+ $row = array();
+ if (\OCP\DB::isError($result)) {
+ \OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
+ } else {
+ if($result->numRows() > 0) {
+ $row = $result->fetchRow();
+ }
+ }
+
+ return $row;
+
+ }
+
+ /**
+ * @brief get shares parent.
+ * @param int $id of the current share
+ * @return array of the parent
+ */
+ public static function getParentFromShare($id) {
+
+ $sql = 'SELECT `parent` FROM `*PREFIX*share` WHERE `id` = ?';
+
+ $query = \OCP\DB::prepare($sql);
+
+ $result = $query->execute(array($id));
+
+ $row = array();
+ if (\OCP\DB::isError($result)) {
+ \OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
+ } else {
+ if($result->numRows() > 0) {
+ $row = $result->fetchRow();
+ }
+ }
+
+ return $row;
+
+ }
+
+ /**
+ * @brief get owner of the shared files.
+ * @param $id
+ * @internal param int $Id of a share
+ * @return string owner
+ */
+ public function getOwnerFromSharedFile($id) {
+
+ $query = \OCP\DB::prepare('SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1);
+
+ $result = $query->execute(array($id));
+
+ $source = array();
+ if (\OCP\DB::isError($result)) {
+ \OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
+ } else {
+ if($result->numRows() > 0) {
+ $source = $result->fetchRow();
+ }
+ }
+
+ $fileOwner = false;
+
+ if (isset($source['parent'])) {
+
+ $parent = $source['parent'];
+
+ while (isset($parent)) {
+
+ $query = \OCP\DB::prepare('SELECT `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `id` = ?', 1);
+
+ $result = $query->execute(array($parent));
+
+ $item = array();
+ if (\OCP\DB::isError($result)) {
+ \OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
+ } else {
+ if($result->numRows() > 0) {
+ $item = $result->fetchRow();
+ }
+ }
+
+ if (isset($item['parent'])) {
+
+ $parent = $item['parent'];
+
+ } else {
+
+ $fileOwner = $item['uid_owner'];
+
+ break;
+
+ }
+ }
+
+ } else {
+
+ $fileOwner = $source['uid_owner'];
+
+ }
+
+ return $fileOwner;
+
+ }
+
+ /**
+ * @return string
+ */
+ public function getUserId() {
+ return $this->userId;
+ }
+
+ /**
+ * @return string
+ */
+ public function getUserFilesDir() {
+ return $this->userFilesDir;
+ }
+
+ /**
+ * @param $password
+ * @return bool
+ */
+ public function checkRecoveryPassword($password) {
+
+ $pathKey = '/owncloud_private_key/' . $this->recoveryKeyId . ".private.key";
+ $pathControlData = '/control-file/controlfile.enc';
+
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ $recoveryKey = $this->view->file_get_contents($pathKey);
+
+ $decryptedRecoveryKey = Crypt::symmetricDecryptFileContent($recoveryKey, $password);
+
+ $controlData = $this->view->file_get_contents($pathControlData);
+ $decryptedControlData = Crypt::keyDecrypt($controlData, $decryptedRecoveryKey);
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ if ($decryptedControlData === 'ownCloud') {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @return string
+ */
+ public function getRecoveryKeyId() {
+ return $this->recoveryKeyId;
+ }
+
+ /**
+ * @brief add recovery key to all encrypted files
+ */
+ public function addRecoveryKeys($path = '/') {
+ $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path);
+ foreach ($dirContent as $item) {
+ // get relative path from files_encryption/keyfiles/
+ $filePath = substr($item['path'], strlen('files_encryption/keyfiles'));
+ if ($item['type'] === 'dir') {
+ $this->addRecoveryKeys($filePath . '/');
+ } else {
+ $session = new \OCA\Encryption\Session(new \OC_FilesystemView('/'));
+ $sharingEnabled = \OCP\Share::isEnabled();
+ // remove '.key' extension from path e.g. 'file.txt.key' to 'file.txt'
+ $file = substr($filePath, 0, -4);
+ $usersSharing = $this->getSharingUsersArray($sharingEnabled, $file);
+ $this->setSharedFileKeyfiles($session, $usersSharing, $file);
+ }
+ }
+ }
+
+ /**
+ * @brief remove recovery key to all encrypted files
+ */
+ public function removeRecoveryKeys($path = '/') {
+ $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path);
+ foreach ($dirContent as $item) {
+ // get relative path from files_encryption/keyfiles
+ $filePath = substr($item['path'], strlen('files_encryption/keyfiles'));
+ if ($item['type'] === 'dir') {
+ $this->removeRecoveryKeys($filePath . '/');
+ } else {
+ // remove '.key' extension from path e.g. 'file.txt.key' to 'file.txt'
+ $file = substr($filePath, 0, -4);
+ $this->view->unlink($this->shareKeysPath . '/' . $file . '.' . $this->recoveryKeyId . '.shareKey');
+ }
+ }
+ }
+
+ /**
+ * @brief decrypt given file with recovery key and encrypt it again to the owner and his new key
+ * @param string $file
+ * @param string $privateKey recovery key to decrypt the file
+ */
+ private function recoverFile($file, $privateKey) {
+
+ $sharingEnabled = \OCP\Share::isEnabled();
+
+ // Find out who, if anyone, is sharing the file
+ if ($sharingEnabled) {
+ $result = \OCP\Share::getUsersSharingFile($file, $this->userId, true);
+ $userIds = $result['users'];
+ $userIds[] = $this->recoveryKeyId;
+ if ($result['public']) {
+ $userIds[] = $this->publicShareKeyId;
+ }
+ } else {
+ $userIds = array(
+ $this->userId,
+ $this->recoveryKeyId
+ );
+ }
+ $filteredUids = $this->filterShareReadyUsers($userIds);
+
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ //decrypt file key
+ $encKeyfile = $this->view->file_get_contents($this->keyfilesPath . $file . ".key");
+ $shareKey = $this->view->file_get_contents(
+ $this->shareKeysPath . $file . "." . $this->recoveryKeyId . ".shareKey");
+ $plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey);
+ // encrypt file key again to all users, this time with the new public key for the recovered use
+ $userPubKeys = Keymanager::getPublicKeys($this->view, $filteredUids['ready']);
+ $multiEncKey = Crypt::multiKeyEncrypt($plainKeyfile, $userPubKeys);
+
+ // write new keys to filesystem TDOO!
+ $this->view->file_put_contents($this->keyfilesPath . $file . '.key', $multiEncKey['data']);
+ foreach ($multiEncKey['keys'] as $userId => $shareKey) {
+ $shareKeyPath = $this->shareKeysPath . $file . '.' . $userId . '.shareKey';
+ $this->view->file_put_contents($shareKeyPath, $shareKey);
+ }
+
+ // Return proxy to original status
+ \OC_FileProxy::$enabled = $proxyStatus;
+ }
+
+ /**
+ * @brief collect all files and recover them one by one
+ * @param string $path to look for files keys
+ * @param string $privateKey private recovery key which is used to decrypt the files
+ */
+ private function recoverAllFiles($path, $privateKey) {
+ $dirContent = $this->view->getDirectoryContent($this->keyfilesPath . $path);
+ foreach ($dirContent as $item) {
+ // get relative path from files_encryption/keyfiles
+ $filePath = substr($item['path'], strlen('files_encryption/keyfiles'));
+ if ($item['type'] === 'dir') {
+ $this->recoverAllFiles($filePath . '/', $privateKey);
+ } else {
+ // remove '.key' extension from path e.g. 'file.txt.key' to 'file.txt'
+ $file = substr($filePath, 0, -4);
+ $this->recoverFile($file, $privateKey);
+ }
+ }
+ }
+
+ /**
+ * @brief recover users files in case of password lost
+ * @param string $recoveryPassword
+ */
+ public function recoverUsersFiles($recoveryPassword) {
+
+ // Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ $encryptedKey = $this->view->file_get_contents(
+ '/owncloud_private_key/' . $this->recoveryKeyId . '.private.key');
+ $privateKey = Crypt::symmetricDecryptFileContent($encryptedKey, $recoveryPassword);
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ $this->recoverAllFiles('/', $privateKey);
+ }
+
+ /**
+ * Get the path including the storage mount point
+ * @param int $id
+ * @return string the path including the mount point like AmazonS3/folder/file.txt
+ */
+ public function getPathWithMountPoint($id) {
+ list($storage, $internalPath) = \OC\Files\Cache\Cache::getById($id);
+ $mount = \OC\Files\Filesystem::getMountByStorageId($storage);
+ $mountPoint = $mount[0]->getMountPoint();
+ $path = \OC\Files\Filesystem::normalizePath($mountPoint.'/'.$internalPath);
+
+ // reformat the path to be relative e.g. /user/files/folder becomes /folder/
+ $relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
+
+ return $relativePath;
}
}
diff --git a/apps/files_encryption/settings-admin.php b/apps/files_encryption/settings-admin.php
new file mode 100644
index 00000000000..53676058982
--- /dev/null
+++ b/apps/files_encryption/settings-admin.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Copyright (c) 2011 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+\OC_Util::checkAdminUser();
+
+$tmpl = new OCP\Template('files_encryption', 'settings-admin');
+
+// Check if an adminRecovery account is enabled for recovering files after lost pwd
+$view = new OC_FilesystemView('');
+
+$recoveryAdminEnabled = OC_Appconfig::getValue('files_encryption', 'recoveryAdminEnabled');
+
+$tmpl->assign('recoveryEnabled', $recoveryAdminEnabled);
+
+\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 af0273cfdc4..3e96565949b 100644
--- a/apps/files_encryption/settings-personal.php
+++ b/apps/files_encryption/settings-personal.php
@@ -6,12 +6,23 @@
* See the COPYING-README file.
*/
-$tmpl = new OCP\Template( 'files_encryption', 'settings-personal');
+// Add CSS stylesheet
+\OC_Util::addStyle('files_encryption', 'settings-personal');
-$blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', 'jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg' ) );
+$tmpl = new OCP\Template('files_encryption', 'settings-personal');
-$tmpl->assign( 'blacklist', $blackList );
+$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');
+\OCP\Util::addScript('settings', 'personal');
+
+$tmpl->assign('recoveryEnabled', $recoveryAdminEnabled);
+$tmpl->assign('recoveryEnabledForUser', $recoveryEnabledForUser);
return $tmpl->fetchPage();
-return null;
diff --git a/apps/files_encryption/settings.php b/apps/files_encryption/settings.php
deleted file mode 100644
index d1260f44e9f..00000000000
--- a/apps/files_encryption/settings.php
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-/**
- * Copyright (c) 2011 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-\OC_Util::checkAdminUser();
-
-$tmpl = new OCP\Template( 'files_encryption', 'settings' );
-
-$blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', 'jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg' ) );
-
-$tmpl->assign( 'blacklist', $blackList );
-$tmpl->assign( 'encryption_mode', \OC_Appconfig::getValue( 'files_encryption', 'mode', 'none' ) );
-
-\OCP\Util::addscript( 'files_encryption', 'settings' );
-\OCP\Util::addscript( 'core', 'multiselect' );
-
-return $tmpl->fetchPage();
diff --git a/apps/files_encryption/templates/settings-admin.php b/apps/files_encryption/templates/settings-admin.php
new file mode 100644
index 00000000000..18fea1845f4
--- /dev/null
+++ b/apps/files_encryption/templates/settings-admin.php
@@ -0,0 +1,56 @@
+<form id="encryption">
+ <fieldset class="personalblock">
+
+ <p>
+ <strong><?php p($l->t( 'Encryption' )); ?></strong>
+ <br />
+ </p>
+ <p>
+ <?php p($l->t( "Enable encryption passwords recovery key (allow sharing to recovery key):" )); ?>
+ <br />
+ <br />
+ <input type="password" name="recoveryPassword" id="recoveryPassword" />
+ <label for="recoveryPassword"><?php p($l->t( "Recovery account password" )); ?></label>
+ <br />
+ <input
+ type='radio'
+ name='adminEnableRecovery'
+ value='1'
+ <?php echo ( $_["recoveryEnabled"] == 1 ? 'checked="checked"' : 'disabled' ); ?> />
+ <?php p($l->t( "Enabled" )); ?>
+ <br />
+
+ <input
+ type='radio'
+ name='adminEnableRecovery'
+ value='0'
+ <?php echo ( $_["recoveryEnabled"] == 0 ? 'checked="checked"' : 'disabled' ); ?> />
+ <?php p($l->t( "Disabled" )); ?>
+ </p>
+ <br /><br />
+ <p>
+ <strong><?php p($l->t( "Change encryption passwords recovery key:" )); ?></strong>
+ <br /><br />
+ <input
+ type="password"
+ name="changeRecoveryPassword"
+ id="oldRecoveryPassword"
+ <?php echo ( $_["recoveryEnabled"] == 0 ? 'disabled' : '' ); ?> />
+ <label for="oldRecoveryPassword"><?php p($l->t( "Old Recovery account password" )); ?></label>
+ <br />
+ <input
+ type="password"
+ name="changeRecoveryPassword"
+ id="newRecoveryPassword"
+ <?php echo ( $_["recoveryEnabled"] == 0 ? 'disabled' : '' ); ?> />
+ <label for="newRecoveryPassword"><?php p($l->t( "New Recovery account password" )); ?></label>
+ <br />
+ <button
+ type="button"
+ name="submitChangeRecoveryKey"
+ disabled><?php p($l->t( "Change Password" )); ?>
+ </button>
+ <span class="msg"></span>
+ </p>
+ </fieldset>
+</form>
diff --git a/apps/files_encryption/templates/settings-personal.php b/apps/files_encryption/templates/settings-personal.php
index 5f0accaed5f..04d6e79179e 100644
--- a/apps/files_encryption/templates/settings-personal.php
+++ b/apps/files_encryption/templates/settings-personal.php
@@ -1,22 +1,33 @@
<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.' )); ?>
- </p>
- <?php if ( ! empty( $_["blacklist"] ) ): ?>
- <p>
- <?php p($l->t( 'The following file types will not be encrypted:' )); ?>
- </p>
- <ul>
- <?php foreach( $_["blacklist"] as $type ): ?>
- <li>
- <?php p($type); ?>
- </li>
- <?php endforeach; ?>
- </ul>
+
+ <?php if ( $_["recoveryEnabled"] ): ?>
+ <p>
+ <label for="userEnableRecovery"><?php p( $l->t( "Enable password recovery by sharing all files with your 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 />
</fieldset>
</form>
diff --git a/apps/files_encryption/templates/settings.php b/apps/files_encryption/templates/settings.php
deleted file mode 100644
index b873d7f5aaf..00000000000
--- a/apps/files_encryption/templates/settings.php
+++ /dev/null
@@ -1,20 +0,0 @@
-<form id="encryption">
- <fieldset class="personalblock">
-
- <p>
- <strong><?php p($l->t( 'Encryption' )); ?></strong>
-
- <?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>
- </fieldset>
-</form>
diff --git a/apps/files_encryption/test/crypt.php b/apps/files_encryption/test/crypt.php
deleted file mode 100755
index aa87ec32821..00000000000
--- a/apps/files_encryption/test/crypt.php
+++ /dev/null
@@ -1,667 +0,0 @@
-<?php
-/**
- * Copyright (c) 2012 Sam Tuke <samtuke@owncloud.com>, and
- * Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-//require_once "PHPUnit/Framework/TestCase.php";
-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__).'/../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
- * handling process, and isolate calls to session class and data from the unit
- * tests relating to them (stream etc.). However getting mockery to work and
- * overload classes whilst also using the OC autoloader is difficult due to
- * load order Pear errors.
- */
-
-class Test_Crypt extends \PHPUnit_Framework_TestCase {
-
- function setUp() {
-
- // 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' );
- $this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' );
- $this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' );
- $this->randomKey = Encryption\Crypt::generateKey();
-
- $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)), '/' );
-
- }
-
- function tearDown() {
-
- }
-
- function testGenerateKey() {
-
- # TODO: use more accurate (larger) string length for test confirmation
-
- $key = Encryption\Crypt::generateKey();
-
- $this->assertTrue( strlen( $key ) > 16 );
-
- }
-
- function testGenerateIv() {
-
- $iv = Encryption\Crypt::generateIv();
-
- $this->assertEquals( 16, strlen( $iv ) );
-
- return $iv;
-
- }
-
- /**
- * @depends testGenerateIv
- */
- function testConcatIv( $iv ) {
-
- $catFile = Encryption\Crypt::concatIv( $this->dataLong, $iv );
-
- // Fetch encryption metadata from end of file
- $meta = substr( $catFile, -22 );
-
- $identifier = substr( $meta, 0, 6);
-
- // Fetch IV from end of file
- $foundIv = substr( $meta, 6 );
-
- $this->assertEquals( '00iv00', $identifier );
-
- $this->assertEquals( $iv, $foundIv );
-
- // Remove IV and IV identifier text to expose encrypted content
- $data = substr( $catFile, 0, -22 );
-
- $this->assertEquals( $this->dataLong, $data );
-
- return array(
- 'iv' => $iv
- , 'catfile' => $catFile
- );
-
- }
-
- /**
- * @depends testConcatIv
- */
- function testSplitIv( $testConcatIv ) {
-
- // Split catfile into components
- $splitCatfile = Encryption\Crypt::splitIv( $testConcatIv['catfile'] );
-
- // Check that original IV and split IV match
- $this->assertEquals( $testConcatIv['iv'], $splitCatfile['iv'] );
-
- // Check that original data and split data match
- $this->assertEquals( $this->dataLong, $splitCatfile['encrypted'] );
-
- }
-
- function testAddPadding() {
-
- $padded = Encryption\Crypt::addPadding( $this->dataLong );
-
- $padding = substr( $padded, -2 );
-
- $this->assertEquals( 'xx' , $padding );
-
- return $padded;
-
- }
-
- /**
- * @depends testAddPadding
- */
- function testRemovePadding( $padded ) {
-
- $noPadding = Encryption\Crypt::RemovePadding( $padded );
-
- $this->assertEquals( $this->dataLong, $noPadding );
-
- }
-
- function testEncrypt() {
-
- $random = openssl_random_pseudo_bytes( 13 );
-
- $iv = substr( base64_encode( $random ), 0, -4 ); // i.e. E5IG033j+mRNKrht
-
- $crypted = Encryption\Crypt::encrypt( $this->dataUrl, $iv, 'hat' );
-
- $this->assertNotEquals( $this->dataUrl, $crypted );
-
- }
-
- function testDecrypt() {
-
- $random = openssl_random_pseudo_bytes( 13 );
-
- $iv = substr( base64_encode( $random ), 0, -4 ); // i.e. E5IG033j+mRNKrht
-
- $crypted = Encryption\Crypt::encrypt( $this->dataUrl, $iv, 'hat' );
-
- $decrypt = Encryption\Crypt::decrypt( $crypted, $iv, 'hat' );
-
- $this->assertEquals( $this->dataUrl, $decrypt );
-
- }
-
- function testSymmetricEncryptFileContent() {
-
- # TODO: search in keyfile for actual content as IV will ensure this test always passes
-
- $crypted = Encryption\Crypt::symmetricEncryptFileContent( $this->dataShort, 'hat' );
-
- $this->assertNotEquals( $this->dataShort, $crypted );
-
-
- $decrypt = Encryption\Crypt::symmetricDecryptFileContent( $crypted, 'hat' );
-
- $this->assertEquals( $this->dataShort, $decrypt );
-
- }
-
- // These aren't used for now
-// function testSymmetricBlockEncryptShortFileContent() {
-//
-// $crypted = Encryption\Crypt::symmetricBlockEncryptFileContent( $this->dataShort, $this->randomKey );
-//
-// $this->assertNotEquals( $this->dataShort, $crypted );
-//
-//
-// $decrypt = Encryption\Crypt::symmetricBlockDecryptFileContent( $crypted, $this->randomKey );
-//
-// $this->assertEquals( $this->dataShort, $decrypt );
-//
-// }
-//
-// function testSymmetricBlockEncryptLongFileContent() {
-//
-// $crypted = Encryption\Crypt::symmetricBlockEncryptFileContent( $this->dataLong, $this->randomKey );
-//
-// $this->assertNotEquals( $this->dataLong, $crypted );
-//
-//
-// $decrypt = Encryption\Crypt::symmetricBlockDecryptFileContent( $crypted, $this->randomKey );
-//
-// $this->assertEquals( $this->dataLong, $decrypt );
-//
-// }
-
- function testSymmetricStreamEncryptShortFileContent() {
-
- $filename = 'tmp-'.time();
-
- $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 );
-
- // 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 );
-
- // Check that decrypted data matches
- $this->assertEquals( $this->dataShort, $manualDecrypt );
-
- }
-
- /**
- * @brief Test that data that is written by the crypto stream wrapper
- * @note Encrypted data is manually prepared and decrypted here to avoid dependency on success of stream_read
- * @note If this test fails with truncate content, check that enough array slices are being rejoined to form $e, as the crypt.php file may have gotten longer and broken the manual
- * reassembly of its data
- */
- function testSymmetricStreamEncryptLongFileContent() {
-
- // Generate a a random filename
- $filename = 'tmp-'.time();
-
- // Save long data as encrypted file using stream wrapper
- $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong.$this->dataLong );
-
- // 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
- $this->assertNotEquals( $this->dataLong.$this->dataLong, $retreivedCryptedFile );
-
- // Manuallly split saved file into separate IVs and encrypted chunks
- $r = preg_split('/(00iv00.{16,18})/', $retreivedCryptedFile, NULL, PREG_SPLIT_DELIM_CAPTURE);
-
- //print_r($r);
-
- // Join IVs and their respective data chunks
- $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 );
-
-
- // Set var for reassembling decrypted content
- $decrypt = '';
-
- // Manually decrypt chunk
- foreach ($e as $e) {
-
-// echo "\n\$e = $e";
-
- $chunkDecrypt = Encryption\Crypt::symmetricDecryptFileContent( $e, $decryptedKeyfile );
-
- // 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 );
-
- Encryption\Keymanager::deleteFileKey( $filename );
-
- }
-
- /**
- * @brief Test that data that is read by the crypto stream wrapper
- */
- function testSymmetricStreamDecryptShortFileContent() {
-
- $filename = 'tmp-'.time();
-
- // Save long data as encrypted file using stream wrapper
- $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 );
-
- $decrypt = file_get_contents( 'crypt://' . $filename );
-
- $this->assertEquals( $this->dataShort, $decrypt );
-
- }
-
- function testSymmetricStreamDecryptLongFileContent() {
-
- $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 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 );
-
- $this->assertEquals( $this->dataLong, $decrypt );
-
- }
-
- // Is this test still necessary?
-// function testSymmetricBlockStreamDecryptFileContent() {
-//
-// \OC_User::setUserId( 'admin' );
-//
-// // Disable encryption proxy to prevent unwanted en/decryption
-// \OC_FileProxy::$enabled = false;
-//
-// $cryptedFile = file_put_contents( 'crypt://' . '/blockEncrypt', $this->dataUrl );
-//
-// // Disable encryption proxy to prevent unwanted en/decryption
-// \OC_FileProxy::$enabled = false;
-//
-// echo "\n\n\$cryptedFile = " . $this->view->file_get_contents( '/blockEncrypt' );
-//
-// $retreivedCryptedFile = file_get_contents( 'crypt://' . '/blockEncrypt' );
-//
-// $this->assertEquals( $this->dataUrl, $retreivedCryptedFile );
-//
-// \OC_FileProxy::$enabled = false;
-//
-// }
-
- function testSymmetricEncryptFileContentKeyfile() {
-
- # TODO: search in keyfile for actual content as IV will ensure this test always passes
-
- $crypted = Encryption\Crypt::symmetricEncryptFileContentKeyfile( $this->dataUrl );
-
- $this->assertNotEquals( $this->dataUrl, $crypted['encrypted'] );
-
-
- $decrypt = Encryption\Crypt::symmetricDecryptFileContent( $crypted['encrypted'], $crypted['key'] );
-
- $this->assertEquals( $this->dataUrl, $decrypt );
-
- }
-
- function testIsEncryptedContent() {
-
- $this->assertFalse( Encryption\Crypt::isCatfile( $this->dataUrl ) );
-
- $this->assertFalse( Encryption\Crypt::isCatfile( $this->legacyEncryptedData ) );
-
- $keyfileContent = Encryption\Crypt::symmetricEncryptFileContent( $this->dataUrl, 'hat' );
-
- $this->assertTrue( Encryption\Crypt::isCatfile( $keyfileContent ) );
-
- }
-
- function testMultiKeyEncrypt() {
-
- # TODO: search in keyfile for actual content as IV will ensure this test always passes
-
- $pair1 = Encryption\Crypt::createKeypair();
-
- $this->assertEquals( 2, count( $pair1 ) );
-
- $this->assertTrue( strlen( $pair1['publicKey'] ) > 1 );
-
- $this->assertTrue( strlen( $pair1['privateKey'] ) > 1 );
-
-
- $crypted = Encryption\Crypt::multiKeyEncrypt( $this->dataUrl, array( $pair1['publicKey'] ) );
-
- $this->assertNotEquals( $this->dataUrl, $crypted['encrypted'] );
-
-
- $decrypt = Encryption\Crypt::multiKeyDecrypt( $crypted['encrypted'], $crypted['keys'][0], $pair1['privateKey'] );
-
- $this->assertEquals( $this->dataUrl, $decrypt );
-
- }
-
- function testKeyEncrypt() {
-
- // Generate keypair
- $pair1 = Encryption\Crypt::createKeypair();
-
- // Encrypt data
- $crypted = Encryption\Crypt::keyEncrypt( $this->dataUrl, $pair1['publicKey'] );
-
- $this->assertNotEquals( $this->dataUrl, $crypted );
-
- // Decrypt data
- $decrypt = Encryption\Crypt::keyDecrypt( $crypted, $pair1['privateKey'] );
-
- $this->assertEquals( $this->dataUrl, $decrypt );
-
- }
-
- // What is the point of this test? It doesn't use keyEncryptKeyfile()
- function testKeyEncryptKeyfile() {
-
- # TODO: Don't repeat encryption from previous tests, use PHPUnit test interdependency instead
-
- // Generate keypair
- $pair1 = Encryption\Crypt::createKeypair();
-
- // Encrypt plain data, generate keyfile & encrypted file
- $cryptedData = Encryption\Crypt::symmetricEncryptFileContentKeyfile( $this->dataUrl );
-
- // Encrypt keyfile
- $cryptedKey = Encryption\Crypt::keyEncrypt( $cryptedData['key'], $pair1['publicKey'] );
-
- // Decrypt keyfile
- $decryptKey = Encryption\Crypt::keyDecrypt( $cryptedKey, $pair1['privateKey'] );
-
- // Decrypt encrypted file
- $decryptData = Encryption\Crypt::symmetricDecryptFileContent( $cryptedData['encrypted'], $decryptKey );
-
- $this->assertEquals( $this->dataUrl, $decryptData );
-
- }
-
- /**
- * @brief test functionality of keyEncryptKeyfile() and
- * keyDecryptKeyfile()
- */
- function testKeyDecryptKeyfile() {
-
- $encrypted = Encryption\Crypt::keyEncryptKeyfile( $this->dataShort, $this->genPublicKey );
-
- $this->assertNotEquals( $encrypted['data'], $this->dataShort );
-
- $decrypted = Encryption\Crypt::keyDecryptKeyfile( $encrypted['data'], $encrypted['key'], $this->genPrivateKey );
-
- $this->assertEquals( $decrypted, $this->dataShort );
-
- }
-
-
- /**
- * @brief test encryption using legacy blowfish method
- */
- function testLegacyEncryptShort() {
-
- $crypted = Encryption\Crypt::legacyEncrypt( $this->dataShort, $this->pass );
-
- $this->assertNotEquals( $this->dataShort, $crypted );
-
- # TODO: search inencrypted text for actual content to ensure it
- # genuine transformation
-
- return $crypted;
-
- }
-
- /**
- * @brief test decryption using legacy blowfish method
- * @depends testLegacyEncryptShort
- */
- function testLegacyDecryptShort( $crypted ) {
-
- $decrypted = Encryption\Crypt::legacyDecrypt( $crypted, $this->pass );
-
- $this->assertEquals( $this->dataShort, $decrypted );
-
- }
-
- /**
- * @brief test encryption using legacy blowfish method
- */
- function testLegacyEncryptLong() {
-
- $crypted = Encryption\Crypt::legacyEncrypt( $this->dataLong, $this->pass );
-
- $this->assertNotEquals( $this->dataLong, $crypted );
-
- # TODO: search inencrypted text for actual content to ensure it
- # genuine transformation
-
- return $crypted;
-
- }
-
- /**
- * @brief test decryption using legacy blowfish method
- * @depends testLegacyEncryptLong
- */
- function testLegacyDecryptLong( $crypted ) {
-
- $decrypted = Encryption\Crypt::legacyDecrypt( $crypted, $this->pass );
-
- $this->assertEquals( $this->dataLong, $decrypted );
-
- }
-
- /**
- * @brief test generation of legacy encryption key
- * @depends testLegacyDecryptShort
- */
- function testLegacyCreateKey() {
-
- // Create encrypted key
- $encKey = Encryption\Crypt::legacyCreateKey( $this->pass );
-
- // Decrypt key
- $key = Encryption\Crypt::legacyDecrypt( $encKey, $this->pass );
-
- $this->assertTrue( is_numeric( $key ) );
-
- // Check that key is correct length
- $this->assertEquals( 20, strlen( $key ) );
-
- }
-
- /**
- * @brief test decryption using legacy blowfish method
- * @depends testLegacyEncryptLong
- */
- function testLegacyKeyRecryptKeyfileEncrypt( $crypted ) {
-
- $recrypted = Encryption\Crypt::LegacyKeyRecryptKeyfile( $crypted, $this->pass, $this->genPublicKey, $this->pass );
-
- $this->assertNotEquals( $this->dataLong, $recrypted['data'] );
-
- return $recrypted;
-
- # TODO: search inencrypted text for actual content to ensure it
- # genuine transformation
-
- }
-
-// function testEncryption(){
-//
-// $key=uniqid();
-// $file=OC::$SERVERROOT.'/3rdparty/MDB2.php';
-// $source=file_get_contents($file); //nice large text file
-// $encrypted=OC_Encryption\Crypt::encrypt($source,$key);
-// $decrypted=OC_Encryption\Crypt::decrypt($encrypted,$key);
-// $decrypted=rtrim($decrypted, "\0");
-// $this->assertNotEquals($encrypted,$source);
-// $this->assertEquals($decrypted,$source);
-//
-// $chunk=substr($source,0,8192);
-// $encrypted=OC_Encryption\Crypt::encrypt($chunk,$key);
-// $this->assertEquals(strlen($chunk),strlen($encrypted));
-// $decrypted=OC_Encryption\Crypt::decrypt($encrypted,$key);
-// $decrypted=rtrim($decrypted, "\0");
-// $this->assertEquals($decrypted,$chunk);
-//
-// $encrypted=OC_Encryption\Crypt::blockEncrypt($source,$key);
-// $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key);
-// $this->assertNotEquals($encrypted,$source);
-// $this->assertEquals($decrypted,$source);
-//
-// $tmpFileEncrypted=OCP\Files::tmpFile();
-// OC_Encryption\Crypt::encryptfile($file,$tmpFileEncrypted,$key);
-// $encrypted=file_get_contents($tmpFileEncrypted);
-// $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key);
-// $this->assertNotEquals($encrypted,$source);
-// $this->assertEquals($decrypted,$source);
-//
-// $tmpFileDecrypted=OCP\Files::tmpFile();
-// OC_Encryption\Crypt::decryptfile($tmpFileEncrypted,$tmpFileDecrypted,$key);
-// $decrypted=file_get_contents($tmpFileDecrypted);
-// $this->assertEquals($decrypted,$source);
-//
-// $file=OC::$SERVERROOT.'/core/img/weather-clear.png';
-// $source=file_get_contents($file); //binary file
-// $encrypted=OC_Encryption\Crypt::encrypt($source,$key);
-// $decrypted=OC_Encryption\Crypt::decrypt($encrypted,$key);
-// $decrypted=rtrim($decrypted, "\0");
-// $this->assertEquals($decrypted,$source);
-//
-// $encrypted=OC_Encryption\Crypt::blockEncrypt($source,$key);
-// $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key);
-// $this->assertEquals($decrypted,$source);
-//
-// }
-//
-// function testBinary(){
-// $key=uniqid();
-//
-// $file=__DIR__.'/binary';
-// $source=file_get_contents($file); //binary file
-// $encrypted=OC_Encryption\Crypt::encrypt($source,$key);
-// $decrypted=OC_Encryption\Crypt::decrypt($encrypted,$key);
-//
-// $decrypted=rtrim($decrypted, "\0");
-// $this->assertEquals($decrypted,$source);
-//
-// $encrypted=OC_Encryption\Crypt::blockEncrypt($source,$key);
-// $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key,strlen($source));
-// $this->assertEquals($decrypted,$source);
-// }
-
-}
diff --git a/apps/files_encryption/test/keymanager.php b/apps/files_encryption/test/keymanager.php
deleted file mode 100644
index bf453fe3163..00000000000
--- a/apps/files_encryption/test/keymanager.php
+++ /dev/null
@@ -1,130 +0,0 @@
-<?php
-/**
- * Copyright (c) 2012 Sam Tuke <samtuke@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-//require_once "PHPUnit/Framework/TestCase.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__).'/../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' );
-
-class Test_Keymanager extends \PHPUnit_Framework_TestCase {
-
- function setUp() {
-
- \OC_FileProxy::$enabled = false;
-
- // 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' );
- $this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' );
- $this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' );
- $this->randomKey = Encryption\Crypt::generateKey();
-
- $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)), '/' );
-
- }
-
- function tearDown(){
-
- \OC_FileProxy::$enabled = true;
-
- }
-
- function testGetPrivateKey() {
-
- $key = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId );
-
- // Will this length vary? Perhaps we should use a range instead
- $this->assertEquals( 2296, strlen( $key ) );
-
- }
-
- function testGetPublicKey() {
-
- $key = Encryption\Keymanager::getPublicKey( $this->view, $this->userId );
-
- $this->assertEquals( 451, strlen( $key ) );
-
- $this->assertEquals( '-----BEGIN PUBLIC KEY-----', substr( $key, 0, 26 ) );
- }
-
- function testSetFileKey() {
-
- # NOTE: This cannot be tested until we are able to break out
- # of the FileSystemView data directory root
-
- $key = Encryption\Crypt::symmetricEncryptFileContentKeyfile( $this->randomKey, 'hat' );
-
- $path = 'unittest-'.time().'txt';
-
- //$view = new \OC_FilesystemView( '/' . $this->userId . '/files_encryption/keyfiles' );
-
- Encryption\Keymanager::setFileKey( $this->view, $path, $this->userId, $key['key'] );
-
- }
-
-// /**
-// * @depends testGetPrivateKey
-// */
-// function testGetPrivateKey_decrypt() {
-//
-// $key = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId );
-//
-// # TODO: replace call to Crypt with a mock object?
-// $decrypted = Encryption\Crypt::symmetricDecryptFileContent( $key, $this->passphrase );
-//
-// $this->assertEquals( 1704, strlen( $decrypted ) );
-//
-// $this->assertEquals( '-----BEGIN PRIVATE KEY-----', substr( $decrypted, 0, 27 ) );
-//
-// }
-
- function testGetUserKeys() {
-
- $keys = Encryption\Keymanager::getUserKeys( $this->view, $this->userId );
-
- $this->assertEquals( 451, strlen( $keys['publicKey'] ) );
- $this->assertEquals( '-----BEGIN PUBLIC KEY-----', substr( $keys['publicKey'], 0, 26 ) );
- $this->assertEquals( 2296, strlen( $keys['privateKey'] ) );
-
- }
-
- function testGetPublicKeys() {
-
- # TODO: write me
-
- }
-
- function testGetFileKey() {
-
-// Encryption\Keymanager::getFileKey( $this->view, $this->userId, $this->filePath );
-
- }
-
-}
diff --git a/apps/files_encryption/test/legacy-encrypted-text.txt b/apps/files_encryption/test/legacy-encrypted-text.txt
deleted file mode 100644
index cb5bf50550d..00000000000
--- a/apps/files_encryption/test/legacy-encrypted-text.txt
+++ /dev/null
Binary files differ
diff --git a/apps/files_encryption/test/stream.php b/apps/files_encryption/test/stream.php
deleted file mode 100644
index ba82ac80eab..00000000000
--- a/apps/files_encryption/test/stream.php
+++ /dev/null
@@ -1,226 +0,0 @@
-// <?php
-// /**
-// * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
-// * This file is licensed under the Affero General Public License version 3 or
-// * later.
-// * See the COPYING-README file.
-// */
-//
-// namespace OCA\Encryption;
-//
-// class Test_Stream extends \PHPUnit_Framework_TestCase {
-//
-// function setUp() {
-//
-// \OC_Filesystem::mount( 'OC_Filestorage_Local', array(), '/' );
-//
-// $this->empty = '';
-//
-// $this->stream = new Stream();
-//
-// $this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) );
-// $this->dataShort = 'hats';
-//
-// $this->emptyTmpFilePath = \OCP\Files::tmpFile();
-//
-// $this->dataTmpFilePath = \OCP\Files::tmpFile();
-//
-// file_put_contents( $this->dataTmpFilePath, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est." );
-//
-// }
-//
-// function testStreamOpen() {
-//
-// $stream1 = new Stream();
-//
-// $handle1 = $stream1->stream_open( $this->emptyTmpFilePath, 'wb', array(), $this->empty );
-//
-// // Test that resource was returned successfully
-// $this->assertTrue( $handle1 );
-//
-// // Test that file has correct size
-// $this->assertEquals( 0, $stream1->size );
-//
-// // Test that path is correct
-// $this->assertEquals( $this->emptyTmpFilePath, $stream1->rawPath );
-//
-// $stream2 = new Stream();
-//
-// $handle2 = $stream2->stream_open( 'crypt://' . $this->emptyTmpFilePath, 'wb', array(), $this->empty );
-//
-// // Test that protocol identifier is removed from path
-// $this->assertEquals( $this->emptyTmpFilePath, $stream2->rawPath );
-//
-// // "Stat failed error" prevents this test from executing
-// // $stream3 = new Stream();
-// //
-// // $handle3 = $stream3->stream_open( $this->dataTmpFilePath, 'r', array(), $this->empty );
-// //
-// // $this->assertEquals( 0, $stream3->size );
-//
-// }
-//
-// function testStreamWrite() {
-//
-// $stream1 = new Stream();
-//
-// $handle1 = $stream1->stream_open( $this->emptyTmpFilePath, 'r+b', array(), $this->empty );
-//
-// # what about the keymanager? there is no key for the newly created temporary file!
-//
-// $stream1->stream_write( $this->dataShort );
-//
-// }
-//
-// // function getStream( $id, $mode, $size ) {
-// //
-// // if ( $id === '' ) {
-// //
-// // $id = uniqid();
-// // }
-// //
-// //
-// // if ( !isset( $this->tmpFiles[$id] ) ) {
-// //
-// // // If tempfile with given name does not already exist, create it
-// //
-// // $file = OCP\Files::tmpFile();
-// //
-// // $this->tmpFiles[$id] = $file;
-// //
-// // } else {
-// //
-// // $file = $this->tmpFiles[$id];
-// //
-// // }
-// //
-// // $stream = fopen( $file, $mode );
-// //
-// // Stream::$sourceStreams[$id] = array( 'path' => 'dummy' . $id, 'stream' => $stream, 'size' => $size );
-// //
-// // return fopen( 'crypt://streams/'.$id, $mode );
-// //
-// // }
-// //
-// // function testStream( ){
-// //
-// // $stream = $this->getStream( 'test1', 'w', strlen( 'foobar' ) );
-// //
-// // fwrite( $stream, 'foobar' );
-// //
-// // fclose( $stream );
-// //
-// //
-// // $stream = $this->getStream( 'test1', 'r', strlen( 'foobar' ) );
-// //
-// // $data = fread( $stream, 6 );
-// //
-// // fclose( $stream );
-// //
-// // $this->assertEquals( 'foobar', $data );
-// //
-// //
-// // $file = OC::$SERVERROOT.'/3rdparty/MDB2.php';
-// //
-// // $source = fopen( $file, 'r' );
-// //
-// // $target = $this->getStream( 'test2', 'w', 0 );
-// //
-// // OCP\Files::streamCopy( $source, $target );
-// //
-// // fclose( $target );
-// //
-// // fclose( $source );
-// //
-// //
-// // $stream = $this->getStream( 'test2', 'r', filesize( $file ) );
-// //
-// // $data = stream_get_contents( $stream );
-// //
-// // $original = file_get_contents( $file );
-// //
-// // $this->assertEquals( strlen( $original ), strlen( $data ) );
-// //
-// // $this->assertEquals( $original, $data );
-// //
-// // }
-//
-// }
-//
-// // class Test_CryptStream extends PHPUnit_Framework_TestCase {
-// // private $tmpFiles=array();
-// //
-// // function testStream(){
-// // $stream=$this->getStream('test1','w',strlen('foobar'));
-// // fwrite($stream,'foobar');
-// // fclose($stream);
-// //
-// // $stream=$this->getStream('test1','r',strlen('foobar'));
-// // $data=fread($stream,6);
-// // fclose($stream);
-// // $this->assertEquals('foobar',$data);
-// //
-// // $file=OC::$SERVERROOT.'/3rdparty/MDB2.php';
-// // $source=fopen($file,'r');
-// // $target=$this->getStream('test2','w',0);
-// // OCP\Files::streamCopy($source,$target);
-// // fclose($target);
-// // fclose($source);
-// //
-// // $stream=$this->getStream('test2','r',filesize($file));
-// // $data=stream_get_contents($stream);
-// // $original=file_get_contents($file);
-// // $this->assertEquals(strlen($original),strlen($data));
-// // $this->assertEquals($original,$data);
-// // }
-// //
-// // /**
-// // * get a cryptstream to a temporary file
-// // * @param string $id
-// // * @param string $mode
-// // * @param int size
-// // * @return resource
-// // */
-// // function getStream($id,$mode,$size){
-// // if($id===''){
-// // $id=uniqid();
-// // }
-// // if(!isset($this->tmpFiles[$id])){
-// // $file=OCP\Files::tmpFile();
-// // $this->tmpFiles[$id]=$file;
-// // }else{
-// // $file=$this->tmpFiles[$id];
-// // }
-// // $stream=fopen($file,$mode);
-// // OC_CryptStream::$sourceStreams[$id]=array('path'=>'dummy'.$id,'stream'=>$stream,'size'=>$size);
-// // return fopen('crypt://streams/'.$id,$mode);
-// // }
-// //
-// // function testBinary(){
-// // $file=__DIR__.'/binary';
-// // $source=file_get_contents($file);
-// //
-// // $stream=$this->getStream('test','w',strlen($source));
-// // fwrite($stream,$source);
-// // fclose($stream);
-// //
-// // $stream=$this->getStream('test','r',strlen($source));
-// // $data=stream_get_contents($stream);
-// // fclose($stream);
-// // $this->assertEquals(strlen($data),strlen($source));
-// // $this->assertEquals($source,$data);
-// //
-// // $file=__DIR__.'/zeros';
-// // $source=file_get_contents($file);
-// //
-// // $stream=$this->getStream('test2','w',strlen($source));
-// // fwrite($stream,$source);
-// // fclose($stream);
-// //
-// // $stream=$this->getStream('test2','r',strlen($source));
-// // $data=stream_get_contents($stream);
-// // fclose($stream);
-// // $this->assertEquals(strlen($data),strlen($source));
-// // $this->assertEquals($source,$data);
-// // }
-// // }
diff --git a/apps/files_encryption/test/util.php b/apps/files_encryption/test/util.php
deleted file mode 100755
index 1cdeff8008d..00000000000
--- a/apps/files_encryption/test/util.php
+++ /dev/null
@@ -1,225 +0,0 @@
-<?php
-/**
- * Copyright (c) 2012 Sam Tuke <samtuke@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-//require_once "PHPUnit/Framework/TestCase.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__).'/../appinfo/app.php' );
-
-// Load mockery files
-require_once 'Mockery/Loader.php';
-require_once 'Hamcrest/Hamcrest.php';
-$loader = new \Mockery\Loader;
-$loader->register();
-
-use \Mockery as m;
-use OCA\Encryption;
-
-class Test_Enc_Util extends \PHPUnit_Framework_TestCase {
-
- function setUp() {
-
- \OC_Filesystem::mount( 'OC_Filestorage_Local', array(), '/' );
-
- // 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'];
- $this->genPrivateKey = $keypair['privateKey'];
-
- $this->publicKeyDir = '/' . 'public-keys';
- $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption';
- $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 );
-
- }
-
- function tearDown(){
-
- m::close();
-
- }
-
- /**
- * @brief test that paths set during User construction are correct
- */
- function testKeyPaths() {
-
- $mockView = m::mock('OC_FilesystemView');
-
- $util = new Encryption\Util( $mockView, $this->userId );
-
- $this->assertEquals( $this->publicKeyDir, $util->getPath( 'publicKeyDir' ) );
- $this->assertEquals( $this->encryptionDir, $util->getPath( 'encryptionDir' ) );
- $this->assertEquals( $this->keyfilesPath, $util->getPath( 'keyfilesPath' ) );
- $this->assertEquals( $this->publicKeyPath, $util->getPath( 'publicKeyPath' ) );
- $this->assertEquals( $this->privateKeyPath, $util->getPath( 'privateKeyPath' ) );
-
- }
-
- /**
- * @brief test setup of encryption directories when they don't yet exist
- */
- function testSetupServerSideNotSetup() {
-
- $mockView = m::mock('OC_FilesystemView');
-
- $mockView->shouldReceive( 'file_exists' )->times(5)->andReturn( false );
- $mockView->shouldReceive( 'mkdir' )->times(4)->andReturn( true );
- $mockView->shouldReceive( 'file_put_contents' )->withAnyArgs();
-
- $util = new Encryption\Util( $mockView, $this->userId );
-
- $this->assertEquals( true, $util->setupServerSide( $this->pass ) );
-
- }
-
- /**
- * @brief test setup of encryption directories when they already exist
- */
- function testSetupServerSideIsSetup() {
-
- $mockView = m::mock('OC_FilesystemView');
-
- $mockView->shouldReceive( 'file_exists' )->times(6)->andReturn( true );
- $mockView->shouldReceive( 'file_put_contents' )->withAnyArgs();
-
- $util = new Encryption\Util( $mockView, $this->userId );
-
- $this->assertEquals( true, $util->setupServerSide( $this->pass ) );
-
- }
-
- /**
- * @brief test checking whether account is ready for encryption, when it isn't ready
- */
- function testReadyNotReady() {
-
- $mockView = m::mock('OC_FilesystemView');
-
- $mockView->shouldReceive( 'file_exists' )->times(1)->andReturn( false );
-
- $util = new Encryption\Util( $mockView, $this->userId );
-
- $this->assertEquals( false, $util->ready() );
-
- # TODO: Add more tests here to check that if any of the dirs are
- # then false will be returned. Use strict ordering?
-
- }
-
- /**
- * @brief test checking whether account is ready for encryption, when it is ready
- */
- function testReadyIsReady() {
-
- $mockView = m::mock('OC_FilesystemView');
-
- $mockView->shouldReceive( 'file_exists' )->times(3)->andReturn( true );
-
- $util = new Encryption\Util( $mockView, $this->userId );
-
- $this->assertEquals( true, $util->ready() );
-
- # TODO: Add more tests here to check that if any of the dirs are
- # then false will be returned. Use strict ordering?
-
- }
-
- function testFindFiles() {
-
-// $this->view->chroot( "/data/{$this->userId}/files" );
-
- $util = new Encryption\Util( $this->view, $this->userId );
-
- $files = $util->findFiles( '/', 'encrypted' );
-
- 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?
-
- }
-
-// /**
-// * @brief test decryption using legacy blowfish method
-// * @depends testLegacyEncryptLong
-// */
-// function testLegacyKeyRecryptKeyfileDecrypt( $recrypted ) {
-//
-// $decrypted = Encryption\Crypt::keyDecryptKeyfile( $recrypted['data'], $recrypted['key'], $this->genPrivateKey );
-//
-// $this->assertEquals( $this->dataLong, $decrypted );
-//
-// }
-
-// // Cannot use this test for now due to hidden dependencies in OC_FileCache
-// function testIsLegacyEncryptedContent() {
-//
-// $keyfileContent = OCA\Encryption\Crypt::symmetricEncryptFileContent( $this->legacyEncryptedData, 'hat' );
-//
-// $this->assertFalse( OCA\Encryption\Crypt::isLegacyEncryptedContent( $keyfileContent, '/files/admin/test.txt' ) );
-//
-// OC_FileCache::put( '/admin/files/legacy-encrypted-test.txt', $this->legacyEncryptedData );
-//
-// $this->assertTrue( OCA\Encryption\Crypt::isLegacyEncryptedContent( $this->legacyEncryptedData, '/files/admin/test.txt' ) );
-//
-// }
-
-// // Cannot use this test for now due to need for different root in OC_Filesystem_view class
-// function testGetLegacyKey() {
-//
-// $c = new \OCA\Encryption\Util( $view, false );
-//
-// $bool = $c->getLegacyKey( 'admin' );
-//
-// $this->assertTrue( $bool );
-//
-// $this->assertTrue( $c->legacyKey );
-//
-// $this->assertTrue( is_int( $c->legacyKey ) );
-//
-// $this->assertTrue( strlen( $c->legacyKey ) == 20 );
-//
-// }
-
-// // Cannot use this test for now due to need for different root in OC_Filesystem_view class
-// function testLegacyDecrypt() {
-//
-// $c = new OCA\Encryption\Util( $this->view, false );
-//
-// $bool = $c->getLegacyKey( 'admin' );
-//
-// $encrypted = $c->legacyEncrypt( $this->data, $c->legacyKey );
-//
-// $decrypted = $c->legacyDecrypt( $encrypted, $c->legacyKey );
-//
-// $this->assertEquals( $decrypted, $this->data );
-//
-// }
-
-} \ No newline at end of file
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/tests/crypt.php b/apps/files_encryption/tests/crypt.php
new file mode 100755
index 00000000000..32156eea272
--- /dev/null
+++ b/apps/files_encryption/tests/crypt.php
@@ -0,0 +1,809 @@
+<?php
+/**
+ * Copyright (c) 2012 Sam Tuke <samtuke@owncloud.com>, and
+ * Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+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');
+require_once realpath(dirname(__FILE__) . '/util.php');
+
+use OCA\Encryption;
+
+/**
+ * Class Test_Encryption_Crypt
+ */
+class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
+
+ const TEST_ENCRYPTION_CRYPT_USER1 = "test-crypt-user1";
+
+ public $userId;
+ public $pass;
+ public $stateFilesTrashbin;
+ public $dataLong;
+ public $dataUrl;
+ public $dataShort;
+ /**
+ * @var OC_FilesystemView
+ */
+ public $view;
+ public $legacyEncryptedData;
+ public $genPrivateKey;
+ public $genPublicKey;
+
+ public static function setUpBeforeClass() {
+ // reset backend
+ \OC_User::clearBackends();
+ \OC_User::useBackend('database');
+
+ // Filesystem related hooks
+ \OCA\Encryption\Helper::registerFilesystemHooks();
+
+ // Filesystem related hooks
+ \OCA\Encryption\Helper::registerUserHooks();
+
+ // clear and register hooks
+ \OC_FileProxy::clearProxies();
+ \OC_FileProxy::register(new OCA\Encryption\Proxy());
+
+ // create test user
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Crypt::TEST_ENCRYPTION_CRYPT_USER1, true);
+ }
+
+ function setUp() {
+ // set user id
+ \OC_User::setUserId(\Test_Encryption_Crypt::TEST_ENCRYPTION_CRYPT_USER1);
+ $this->userId = \Test_Encryption_Crypt::TEST_ENCRYPTION_CRYPT_USER1;
+ $this->pass = \Test_Encryption_Crypt::TEST_ENCRYPTION_CRYPT_USER1;
+
+ // 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');
+ $this->legacyData = realpath(dirname(__FILE__) . '/legacy-text.txt');
+ $this->legacyEncryptedData = realpath(dirname(__FILE__) . '/legacy-encrypted-text.txt');
+ $this->legacyEncryptedDataKey = realpath(dirname(__FILE__) . '/encryption.key');
+ $this->randomKey = Encryption\Crypt::generateKey();
+
+ $keypair = Encryption\Crypt::createKeypair();
+ $this->genPublicKey = $keypair['publicKey'];
+ $this->genPrivateKey = $keypair['privateKey'];
+
+ $this->view = new \OC_FilesystemView('/');
+
+ // 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');
+ }
+
+ function tearDown() {
+ // reset app files_trashbin
+ if ($this->stateFilesTrashbin) {
+ OC_App::enable('files_trashbin');
+ }
+ else {
+ OC_App::disable('files_trashbin');
+ }
+ }
+
+ public static function tearDownAfterClass() {
+ // cleanup test user
+ \OC_User::deleteUser(\Test_Encryption_Crypt::TEST_ENCRYPTION_CRYPT_USER1);
+ }
+
+ function testGenerateKey() {
+
+ # TODO: use more accurate (larger) string length for test confirmation
+
+ $key = Encryption\Crypt::generateKey();
+
+ $this->assertTrue(strlen($key) > 16);
+
+ }
+
+ /**
+ * @return String
+ */
+ function testGenerateIv() {
+
+ $iv = Encryption\Crypt::generateIv();
+
+ $this->assertEquals(16, strlen($iv));
+
+ return $iv;
+
+ }
+
+ /**
+ * @depends testGenerateIv
+ */
+ function testConcatIv($iv) {
+
+ $catFile = Encryption\Crypt::concatIv($this->dataLong, $iv);
+
+ // Fetch encryption metadata from end of file
+ $meta = substr($catFile, -22);
+
+ $identifier = substr($meta, 0, 6);
+
+ // Fetch IV from end of file
+ $foundIv = substr($meta, 6);
+
+ $this->assertEquals('00iv00', $identifier);
+
+ $this->assertEquals($iv, $foundIv);
+
+ // Remove IV and IV identifier text to expose encrypted content
+ $data = substr($catFile, 0, -22);
+
+ $this->assertEquals($this->dataLong, $data);
+
+ return array(
+ 'iv' => $iv
+ ,
+ 'catfile' => $catFile
+ );
+
+ }
+
+ /**
+ * @depends testConcatIv
+ */
+ function testSplitIv($testConcatIv) {
+
+ // Split catfile into components
+ $splitCatfile = Encryption\Crypt::splitIv($testConcatIv['catfile']);
+
+ // Check that original IV and split IV match
+ $this->assertEquals($testConcatIv['iv'], $splitCatfile['iv']);
+
+ // Check that original data and split data match
+ $this->assertEquals($this->dataLong, $splitCatfile['encrypted']);
+
+ }
+
+ /**
+ * @return string padded
+ */
+ function testAddPadding() {
+
+ $padded = Encryption\Crypt::addPadding($this->dataLong);
+
+ $padding = substr($padded, -2);
+
+ $this->assertEquals('xx', $padding);
+
+ return $padded;
+
+ }
+
+ /**
+ * @depends testAddPadding
+ */
+ function testRemovePadding($padded) {
+
+ $noPadding = Encryption\Crypt::RemovePadding($padded);
+
+ $this->assertEquals($this->dataLong, $noPadding);
+
+ }
+
+ function testEncrypt() {
+
+ $random = openssl_random_pseudo_bytes(13);
+
+ $iv = substr(base64_encode($random), 0, -4); // i.e. E5IG033j+mRNKrht
+
+ $crypted = Encryption\Crypt::encrypt($this->dataUrl, $iv, 'hat');
+
+ $this->assertNotEquals($this->dataUrl, $crypted);
+
+ }
+
+ function testDecrypt() {
+
+ $random = openssl_random_pseudo_bytes(13);
+
+ $iv = substr(base64_encode($random), 0, -4); // i.e. E5IG033j+mRNKrht
+
+ $crypted = Encryption\Crypt::encrypt($this->dataUrl, $iv, 'hat');
+
+ $decrypt = Encryption\Crypt::decrypt($crypted, $iv, 'hat');
+
+ $this->assertEquals($this->dataUrl, $decrypt);
+
+ }
+
+ function testSymmetricEncryptFileContent() {
+
+ # TODO: search in keyfile for actual content as IV will ensure this test always passes
+
+ $crypted = Encryption\Crypt::symmetricEncryptFileContent($this->dataShort, 'hat');
+
+ $this->assertNotEquals($this->dataShort, $crypted);
+
+
+ $decrypt = Encryption\Crypt::symmetricDecryptFileContent($crypted, 'hat');
+
+ $this->assertEquals($this->dataShort, $decrypt);
+
+ }
+
+ 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));
+
+ // 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 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 \OCA\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);
+ }
+
+ /**
+ * @brief Test that data that is written by the crypto stream wrapper
+ * @note Encrypted data is manually prepared and decrypted here to avoid dependency on success of stream_read
+ * @note If this test fails with truncate content, check that enough array slices are being rejoined to form $e, as the crypt.php file may have gotten longer and broken the manual
+ * reassembly of its data
+ */
+ function testSymmetricStreamEncryptLongFileContent() {
+
+ // Generate a a random filename
+ $filename = 'tmp-' . time() . '.test';
+
+ // Save long data as encrypted file using stream wrapper
+ $cryptedFile = file_put_contents('crypt://' . $filename, $this->dataLong . $this->dataLong);
+
+ // 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 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
+ $r = preg_split('/(00iv00.{16,18})/', $retreivedCryptedFile, NULL, PREG_SPLIT_DELIM_CAPTURE);
+
+ //print_r($r);
+
+ // Join IVs and their respective data chunks
+ $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[11], $r[12].$r[13], $r[14] );
+
+ //print_r($e);
+
+ // 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 \OCA\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 $chunk) {
+
+ $chunkDecrypt = Encryption\Crypt::symmetricDecryptFileContent($chunk, $plainKeyfile);
+
+ // Assemble decrypted chunks
+ $decrypt .= $chunkDecrypt;
+
+ }
+
+ $this->assertEquals($this->dataLong . $this->dataLong, $decrypt);
+
+ // Teardown
+
+ $this->view->unlink($this->userId . '/files/' . $filename);
+
+ Encryption\Keymanager::deleteFileKey($this->view, $this->userId, $filename);
+
+ }
+
+ /**
+ * @brief Test that data that is read by the crypto stream wrapper
+ */
+ function testSymmetricStreamDecryptShortFileContent() {
+
+ $filename = 'tmp-' . time();
+
+ // Save long data as encrypted file using stream wrapper
+ $cryptedFile = file_put_contents('crypt://' . $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;
+
+ $this->assertTrue(Encryption\Crypt::isEncryptedMeta($filename));
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ // 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() {
+
+ $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);
+
+ // tear down
+ $this->view->unlink($this->userId . '/files/' . $filename);
+ }
+
+ function testSymmetricEncryptFileContentKeyfile() {
+
+ # TODO: search in keyfile for actual content as IV will ensure this test always passes
+
+ $crypted = Encryption\Crypt::symmetricEncryptFileContentKeyfile($this->dataUrl);
+
+ $this->assertNotEquals($this->dataUrl, $crypted['encrypted']);
+
+
+ $decrypt = Encryption\Crypt::symmetricDecryptFileContent($crypted['encrypted'], $crypted['key']);
+
+ $this->assertEquals($this->dataUrl, $decrypt);
+
+ }
+
+ function testIsEncryptedContent() {
+
+ $this->assertFalse(Encryption\Crypt::isCatfileContent($this->dataUrl));
+
+ $this->assertFalse(Encryption\Crypt::isCatfileContent($this->legacyEncryptedData));
+
+ $keyfileContent = Encryption\Crypt::symmetricEncryptFileContent($this->dataUrl, 'hat');
+
+ $this->assertTrue(Encryption\Crypt::isCatfileContent($keyfileContent));
+
+ }
+
+ function testMultiKeyEncrypt() {
+
+ # TODO: search in keyfile for actual content as IV will ensure this test always passes
+
+ $pair1 = Encryption\Crypt::createKeypair();
+
+ $this->assertEquals(2, count($pair1));
+
+ $this->assertTrue(strlen($pair1['publicKey']) > 1);
+
+ $this->assertTrue(strlen($pair1['privateKey']) > 1);
+
+
+ $crypted = Encryption\Crypt::multiKeyEncrypt($this->dataShort, array($pair1['publicKey']));
+
+ $this->assertNotEquals($this->dataShort, $crypted['data']);
+
+
+ $decrypt = Encryption\Crypt::multiKeyDecrypt($crypted['data'], $crypted['keys'][0], $pair1['privateKey']);
+
+ $this->assertEquals($this->dataShort, $decrypt);
+
+ }
+
+ function testKeyEncrypt() {
+
+ // Generate keypair
+ $pair1 = Encryption\Crypt::createKeypair();
+
+ // Encrypt data
+ $crypted = Encryption\Crypt::keyEncrypt($this->dataUrl, $pair1['publicKey']);
+
+ $this->assertNotEquals($this->dataUrl, $crypted);
+
+ // Decrypt data
+ $decrypt = Encryption\Crypt::keyDecrypt($crypted, $pair1['privateKey']);
+
+ $this->assertEquals($this->dataUrl, $decrypt);
+
+ }
+
+ /**
+ * @brief test encryption using legacy blowfish method
+ */
+ function testLegacyEncryptShort() {
+
+ $crypted = Encryption\Crypt::legacyEncrypt($this->dataShort, $this->pass);
+
+ $this->assertNotEquals($this->dataShort, $crypted);
+
+ # TODO: search inencrypted text for actual content to ensure it
+ # genuine transformation
+
+ return $crypted;
+
+ }
+
+ /**
+ * @brief test decryption using legacy blowfish method
+ * @depends testLegacyEncryptShort
+ */
+ function testLegacyDecryptShort($crypted) {
+
+ $decrypted = Encryption\Crypt::legacyBlockDecrypt($crypted, $this->pass);
+
+ $this->assertEquals($this->dataShort, $decrypted);
+
+ }
+
+ /**
+ * @brief test encryption using legacy blowfish method
+ */
+ function testLegacyEncryptLong() {
+
+ $crypted = Encryption\Crypt::legacyEncrypt($this->dataLong, $this->pass);
+
+ $this->assertNotEquals($this->dataLong, $crypted);
+
+ # TODO: search inencrypted text for actual content to ensure it
+ # genuine transformation
+
+ return $crypted;
+
+ }
+
+ /**
+ * @brief test decryption using legacy blowfish method
+ * @depends testLegacyEncryptLong
+ */
+ function testLegacyDecryptLong($crypted) {
+
+ $decrypted = Encryption\Crypt::legacyBlockDecrypt($crypted, $this->pass);
+
+ $this->assertEquals($this->dataLong, $decrypted);
+
+ $this->assertFalse(Encryption\Crypt::getBlowfish(''));
+ }
+
+ /**
+ * @brief test generation of legacy encryption key
+ * @depends testLegacyDecryptShort
+ */
+ function testLegacyCreateKey() {
+
+ // Create encrypted key
+ $encKey = Encryption\Crypt::legacyCreateKey($this->pass);
+
+ // Decrypt key
+ $key = Encryption\Crypt::legacyBlockDecrypt($encKey, $this->pass);
+
+ $this->assertTrue(is_numeric($key));
+
+ // Check that key is correct length
+ $this->assertEquals(20, strlen($key));
+
+ }
+
+ /**
+ * @brief test decryption using legacy blowfish method
+ * @depends testLegacyEncryptLong
+ */
+ function testLegacyKeyRecryptKeyfileEncrypt($crypted) {
+
+ $recrypted = Encryption\Crypt::LegacyKeyRecryptKeyfile($crypted, $this->pass, array($this->genPublicKey));
+
+ $this->assertNotEquals($this->dataLong, $recrypted['data']);
+
+ return $recrypted;
+
+ # TODO: search inencrypted text for actual content to ensure it
+ # genuine transformation
+
+ }
+
+ 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 = '/newfolder' . time();
+ $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);
+ }
+
+ function testMoveFolder() {
+
+ $view = new \OC\Files\View('/' . $this->userId . '/files');
+
+ $filename = '/tmp-' . time();
+ $folder = '/folder' . time();
+
+ $view->mkdir($folder);
+
+ // Save long data as encrypted file using stream wrapper
+ $cryptedFile = file_put_contents('crypt://' . $folder . $filename, $this->dataLong);
+
+ // Test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile));
+
+ // Get file decrypted contents
+ $decrypt = file_get_contents('crypt://' . $folder . $filename);
+
+ $this->assertEquals($this->dataLong, $decrypt);
+
+ $newFolder = '/newfolder/subfolder' . time();
+ $view->mkdir('/newfolder');
+
+ $view->rename($folder, $newFolder);
+
+ // Get file decrypted contents
+ $newDecrypt = file_get_contents('crypt://' . $newFolder . $filename);
+
+ $this->assertEquals($this->dataLong, $newDecrypt);
+
+ // tear down
+ $view->unlink($newFolder);
+ $view->unlink('/newfolder');
+ }
+
+ function testChangePassphrase() {
+ $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);
+
+ // change password
+ \OC_User::setPassword($this->userId, 'test', null);
+
+ // relogin
+ $params['uid'] = $this->userId;
+ $params['password'] = 'test';
+ OCA\Encryption\Hooks::login($params);
+
+ // Get file decrypted contents
+ $newDecrypt = file_get_contents('crypt://' . $filename);
+
+ $this->assertEquals($this->dataLong, $newDecrypt);
+
+ // tear down
+ // change password back
+ \OC_User::setPassword($this->userId, $this->pass);
+ $view = new \OC\Files\View('/' . $this->userId . '/files');
+ $view->unlink($filename);
+ }
+
+ function testViewFilePutAndGetContents() {
+
+ $filename = '/tmp-' . time();
+ $view = new \OC\Files\View('/' . $this->userId . '/files');
+
+ // Save short data as encrypted file using stream wrapper
+ $cryptedFile = $view->file_put_contents($filename, $this->dataShort);
+
+ // Test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile));
+
+ // Get file decrypted contents
+ $decrypt = $view->file_get_contents($filename);
+
+ $this->assertEquals($this->dataShort, $decrypt);
+
+ // Save long data as encrypted file using stream wrapper
+ $cryptedFileLong = $view->file_put_contents($filename, $this->dataLong);
+
+ // Test that data was successfully written
+ $this->assertTrue(is_int($cryptedFileLong));
+
+ // Get file decrypted contents
+ $decryptLong = $view->file_get_contents($filename);
+
+ $this->assertEquals($this->dataLong, $decryptLong);
+
+ // tear down
+ $view->unlink($filename);
+ }
+
+ function testTouchExistingFile() {
+ $filename = '/tmp-' . time();
+ $view = new \OC\Files\View('/' . $this->userId . '/files');
+
+ // Save short data as encrypted file using stream wrapper
+ $cryptedFile = $view->file_put_contents($filename, $this->dataShort);
+
+ // Test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile));
+
+ $view->touch($filename);
+
+ // Get file decrypted contents
+ $decrypt = $view->file_get_contents($filename);
+
+ $this->assertEquals($this->dataShort, $decrypt);
+
+ // tear down
+ $view->unlink($filename);
+ }
+
+ function testTouchFile() {
+ $filename = '/tmp-' . time();
+ $view = new \OC\Files\View('/' . $this->userId . '/files');
+
+ $view->touch($filename);
+
+ // Save short data as encrypted file using stream wrapper
+ $cryptedFile = $view->file_put_contents($filename, $this->dataShort);
+
+ // Test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile));
+
+ // Get file decrypted contents
+ $decrypt = $view->file_get_contents($filename);
+
+ $this->assertEquals($this->dataShort, $decrypt);
+
+ // tear down
+ $view->unlink($filename);
+ }
+
+ function testFopenFile() {
+ $filename = '/tmp-' . time();
+ $view = new \OC\Files\View('/' . $this->userId . '/files');
+
+ // Save short data as encrypted file using stream wrapper
+ $cryptedFile = $view->file_put_contents($filename, $this->dataShort);
+
+ // Test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile));
+
+ $handle = $view->fopen($filename, 'r');
+
+ // Get file decrypted contents
+ $decrypt = fgets($handle);
+
+ $this->assertEquals($this->dataShort, $decrypt);
+
+ // tear down
+ $view->unlink($filename);
+ }
+}
diff --git a/apps/files_encryption/tests/encryption.key b/apps/files_encryption/tests/encryption.key
new file mode 100644
index 00000000000..4ee962145c2
--- /dev/null
+++ b/apps/files_encryption/tests/encryption.key
Binary files differ
diff --git a/apps/files_encryption/tests/keymanager.php b/apps/files_encryption/tests/keymanager.php
new file mode 100644
index 00000000000..40ae1659a55
--- /dev/null
+++ b/apps/files_encryption/tests/keymanager.php
@@ -0,0 +1,245 @@
+<?php
+/**
+ * Copyright (c) 2012 Sam Tuke <samtuke@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+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_Keymanager
+ */
+class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
+
+ public $userId;
+ public $pass;
+ public $stateFilesTrashbin;
+ /**
+ * @var OC_FilesystemView
+ */
+ public $view;
+ public $randomKey;
+ public $dataShort;
+
+ public static function setUpBeforeClass() {
+ // reset backend
+ \OC_User::clearBackends();
+ \OC_User::useBackend('database');
+
+ // Filesystem related hooks
+ \OCA\Encryption\Helper::registerFilesystemHooks();
+
+ // clear and register hooks
+ \OC_FileProxy::clearProxies();
+ \OC_FileProxy::register(new OCA\Encryption\Proxy());
+
+ // disable file proxy by default
+ \OC_FileProxy::$enabled = false;
+
+ // setup filesystem
+ \OC_Util::tearDownFS();
+ \OC_User::setUserId('');
+ \OC\Files\Filesystem::tearDown();
+ \OC_Util::setupFS('admin');
+ \OC_User::setUserId('admin');
+
+ // login admin
+ $params['uid'] = 'admin';
+ $params['password'] = 'admin';
+ OCA\Encryption\Hooks::login($params);
+ }
+
+ function setUp() {
+ // 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');
+ $this->legacyData = realpath(dirname(__FILE__) . '/legacy-text.txt');
+ $this->legacyEncryptedData = realpath(dirname(__FILE__) . '/legacy-encrypted-text.txt');
+ $this->randomKey = Encryption\Crypt::generateKey();
+
+ $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';
+
+ $userHome = \OC_User::getHome($this->userId);
+ $this->dataDir = str_replace('/' . $this->userId, '', $userHome);
+
+ // 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');
+ }
+
+ function tearDown() {
+ // reset app files_trashbin
+ if ($this->stateFilesTrashbin) {
+ OC_App::enable('files_trashbin');
+ }
+ else {
+ OC_App::disable('files_trashbin');
+ }
+ }
+
+ public static function tearDownAfterClass() {
+ \OC_FileProxy::$enabled = true;
+ }
+
+ function testGetPrivateKey() {
+
+ $key = Encryption\Keymanager::getPrivateKey($this->view, $this->userId);
+
+ $privateKey = Encryption\Crypt::symmetricDecryptFileContent($key, $this->pass);
+
+ $res = openssl_pkey_get_private($privateKey);
+
+ $this->assertTrue(is_resource($res));
+
+ $sslInfo = openssl_pkey_get_details($res);
+
+ $this->assertArrayHasKey('key', $sslInfo);
+
+ }
+
+ function testGetPublicKey() {
+
+ $publiceKey = Encryption\Keymanager::getPublicKey($this->view, $this->userId);
+
+ $res = openssl_pkey_get_public($publiceKey);
+
+ $this->assertTrue(is_resource($res));
+
+ $sslInfo = openssl_pkey_get_details($res);
+
+ $this->assertArrayHasKey('key', $sslInfo);
+ }
+
+ function testSetFileKey() {
+
+ # NOTE: This cannot be tested until we are able to break out
+ # of the FileSystemView data directory root
+
+ $key = Encryption\Crypt::symmetricEncryptFileContentKeyfile($this->randomKey, 'hat');
+
+ $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, $file, $this->userId, $key['key']);
+
+ // enable encryption proxy
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = true;
+
+ // cleanup
+ $this->view->unlink('/' . $this->userId . '/files/' . $file);
+
+ // change encryption proxy to previous state
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ }
+
+ function testGetUserKeys() {
+
+ $keys = Encryption\Keymanager::getUserKeys($this->view, $this->userId);
+
+ $resPublic = openssl_pkey_get_public($keys['publicKey']);
+
+ $this->assertTrue(is_resource($resPublic));
+
+ $sslInfoPublic = openssl_pkey_get_details($resPublic);
+
+ $this->assertArrayHasKey('key', $sslInfoPublic);
+
+ $privateKey = Encryption\Crypt::symmetricDecryptFileContent($keys['privateKey'], $this->pass);
+
+ $resPrivate = openssl_pkey_get_private($privateKey);
+
+ $this->assertTrue(is_resource($resPrivate));
+
+ $sslInfoPrivate = openssl_pkey_get_details($resPrivate);
+
+ $this->assertArrayHasKey('key', $sslInfoPrivate);
+ }
+
+ function testFixPartialFilePath() {
+
+ $partFilename = 'testfile.txt.part';
+ $filename = 'testfile.txt';
+
+ $this->assertTrue(Encryption\Keymanager::isPartialFilePath($partFilename));
+
+ $this->assertEquals('testfile.txt', Encryption\Keymanager::fixPartialFilePath($partFilename));
+
+ $this->assertFalse(Encryption\Keymanager::isPartialFilePath($filename));
+
+ $this->assertEquals('testfile.txt', Encryption\Keymanager::fixPartialFilePath($filename));
+ }
+
+ function testRecursiveDelShareKeys() {
+
+ // generate filename
+ $filename = '/tmp-' . time() . '.txt';
+
+ // create folder structure
+ $this->view->mkdir('/admin/files/folder1');
+ $this->view->mkdir('/admin/files/folder1/subfolder');
+ $this->view->mkdir('/admin/files/folder1/subfolder/subsubfolder');
+
+ // enable encryption proxy
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = true;
+
+ // save file with content
+ $cryptedFile = file_put_contents('crypt:///folder1/subfolder/subsubfolder/' . $filename, $this->dataShort);
+
+ // test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile));
+
+ // change encryption proxy to previous state
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ // recursive delete keys
+ Encryption\Keymanager::delShareKey($this->view, array('admin'), '/folder1/');
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists(
+ '/admin/files_encryption/share-keys/folder1/subfolder/subsubfolder/' . $filename . '.admin.shareKey'));
+
+ // enable encryption proxy
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = true;
+
+ // cleanup
+ $this->view->unlink('/admin/files/folder1');
+
+ // change encryption proxy to previous state
+ \OC_FileProxy::$enabled = $proxyStatus;
+ }
+}
diff --git a/apps/files_encryption/tests/legacy-encrypted-text.txt b/apps/files_encryption/tests/legacy-encrypted-text.txt
new file mode 100644
index 00000000000..1f5087178cd
--- /dev/null
+++ b/apps/files_encryption/tests/legacy-encrypted-text.txt
@@ -0,0 +1 @@
+ð˜¯5–¡‹Ç¡i›òë³Zg§ESlÁF=Àªð \ No newline at end of file
diff --git a/apps/files_encryption/test/proxy.php b/apps/files_encryption/tests/proxy.php
index 709730f7609..5a2d851ff7c 100644
--- a/apps/files_encryption/test/proxy.php
+++ b/apps/files_encryption/tests/proxy.php
@@ -52,7 +52,7 @@
// $this->userId = 'admin';
// $this->pass = 'admin';
//
-// $this->session = new Encryption\Session();
+// $this->session = new Encryption\Session( $view ); // FIXME: Provide a $view object for use here
//
// $this->session->setPrivateKey(
// '-----BEGIN PRIVATE KEY-----
diff --git a/apps/files_encryption/tests/share.php b/apps/files_encryption/tests/share.php
new file mode 100755
index 00000000000..6d92881ceb0
--- /dev/null
+++ b/apps/files_encryption/tests/share.php
@@ -0,0 +1,911 @@
+<?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');
+require_once realpath(dirname(__FILE__) . '/util.php');
+
+use OCA\Encryption;
+
+/**
+ * Class Test_Encryption_Share
+ */
+class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
+
+ const TEST_ENCRYPTION_SHARE_USER1 = "test-share-user1";
+ const TEST_ENCRYPTION_SHARE_USER2 = "test-share-user2";
+ const TEST_ENCRYPTION_SHARE_USER3 = "test-share-user3";
+ const TEST_ENCRYPTION_SHARE_USER4 = "test-share-user4";
+ const TEST_ENCRYPTION_SHARE_GROUP1 = "test-share-group1";
+
+ public $stateFilesTrashbin;
+ public $filename;
+ public $dataShort;
+ /**
+ * @var OC_FilesystemView
+ */
+ public $view;
+ public $folder1;
+ public $subfolder;
+ public $subsubfolder;
+
+ public static function setUpBeforeClass() {
+ // reset backend
+ \OC_User::clearBackends();
+ \OC_User::useBackend('database');
+
+ // 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();
+
+ // clear and register hooks
+ \OC_FileProxy::clearProxies();
+ \OC_FileProxy::register(new OCA\Encryption\Proxy());
+
+ // create users
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1, true);
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, true);
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3, true);
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4, true);
+
+ // create group and assign users
+ \OC_Group::createGroup(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1);
+ \OC_Group::addToGroup(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1);
+ \OC_Group::addToGroup(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1);
+ }
+
+ function setUp() {
+ $this->dataShort = 'hats';
+ $this->view = new \OC_FilesystemView('/');
+
+ $this->folder1 = '/folder1';
+ $this->subfolder = '/subfolder1';
+ $this->subsubfolder = '/subsubfolder1';
+
+ $this->filename = 'share-tmp.test';
+
+ // we don't want to tests with app files_trashbin enabled
+ \OC_App::disable('files_trashbin');
+
+ // remember files_trashbin state
+ $this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
+ }
+
+ function tearDown() {
+ // reset app files_trashbin
+ if ($this->stateFilesTrashbin) {
+ OC_App::enable('files_trashbin');
+ }
+ else {
+ OC_App::disable('files_trashbin');
+ }
+ }
+
+ public static function tearDownAfterClass() {
+ // clean group
+ \OC_Group::deleteGroup(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1);
+
+ // cleanup users
+ \OC_User::deleteUser(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+ \OC_User::deleteUser(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+ \OC_User::deleteUser(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
+ \OC_User::deleteUser(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4);
+ }
+
+ /**
+ * @param bool $withTeardown
+ */
+ function testShareFile($withTeardown = true) {
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // 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(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/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, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, OCP\PERMISSION_ALL);
+
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // check if share key for user1 exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
+
+ // login as user1
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+
+ // get file contents
+ $retrievedCryptedFile = $this->view->file_get_contents(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/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
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // unshare the file
+ \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
+
+ // cleanup
+ $this->view->unlink(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '.shareKey'));
+ }
+ }
+
+ /**
+ * @param bool $withTeardown
+ */
+ function testReShareFile($withTeardown = true) {
+ $this->testShareFile(false);
+
+ // login as user1
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+
+ // get the file info
+ $fileInfo = $this->view->getFileInfo(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/Shared/' . $this->filename);
+
+ // share the file with user2
+ \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3, OCP\PERMISSION_ALL);
+
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // check if share key for user2 exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey'));
+
+ // login as user2
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
+
+ // get file contents
+ $retrievedCryptedFile = $this->view->file_get_contents(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '/files/Shared/' . $this->filename);
+
+ // check if data is the same as previously written
+ $this->assertEquals($this->dataShort, $retrievedCryptedFile);
+
+ // cleanup
+ if ($withTeardown) {
+
+ // login as user1
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+
+ // unshare the file with user2
+ \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
+
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey'));
+
+ // unshare the file with user1
+ \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
+
+ // cleanup
+ $this->view->unlink(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '.shareKey'));
+ }
+ }
+
+ /**
+ * @param bool $withTeardown
+ * @return array
+ */
+ function testShareFolder($withTeardown = true) {
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // create folder structure
+ $this->view->mkdir('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files' . $this->folder1);
+ $this->view->mkdir(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files' . $this->folder1 . $this->subfolder);
+ $this->view->mkdir(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/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(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/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, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, OCP\PERMISSION_ALL);
+
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // check if share key for user1 exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys' . $this->folder1
+ . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
+
+ // login as user1
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+
+ // get file contents
+ $retrievedCryptedFile = $this->view->file_get_contents(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/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
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // unshare the folder with user1
+ \OCP\Share::unshare('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys'
+ . $this->folder1 . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
+
+ // cleanup
+ $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files' . $this->folder1);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys'
+ . $this->folder1 . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '.shareKey'));
+ }
+
+ return $fileInfo;
+ }
+
+ /**
+ * @param bool $withTeardown
+ */
+ function testReShareFolder($withTeardown = true) {
+ $fileInfoFolder1 = $this->testShareFolder(false);
+
+ // login as user1
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+
+ // 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(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/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, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3, OCP\PERMISSION_ALL);
+
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // check if share key for user2 exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys' . $this->folder1
+ . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey'));
+
+ // login as user2
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
+
+ // get file contents
+ $retrievedCryptedFile = $this->view->file_get_contents(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '/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(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '/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, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4, OCP\PERMISSION_ALL);
+
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // check if share key for user3 exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys' . $this->folder1
+ . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4 . '.shareKey'));
+
+ // login as user3
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4);
+
+ // get file contents
+ $retrievedCryptedFile = $this->view->file_get_contents(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4 . '/files/Shared/' . $this->filename);
+
+ // check if data is the same
+ $this->assertEquals($this->dataShort, $retrievedCryptedFile);
+
+ // cleanup
+ if ($withTeardown) {
+
+ // login as user2
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
+
+ // unshare the file with user3
+ \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys'
+ . $this->folder1 . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4 . '.shareKey'));
+
+ // login as user1
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+
+ // unshare the folder with user2
+ \OCP\Share::unshare('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys'
+ . $this->folder1 . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey'));
+
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // unshare the folder1 with user1
+ \OCP\Share::unshare('folder', $fileInfoFolder1['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys'
+ . $this->folder1 . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
+
+ // cleanup
+ $this->view->unlink(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files' . $this->folder1 . $this->subfolder
+ . $this->subsubfolder . '/' . $this->filename);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys'
+ . $this->folder1 . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '.shareKey'));
+ }
+ }
+
+ function testPublicShareFile() {
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // 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(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/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, false, OCP\PERMISSION_ALL);
+
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ $publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId');
+
+ // check if share key for public exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . $publicShareKeyId . '.shareKey'));
+
+ // some hacking to simulate public link
+ $GLOBALS['app'] = 'files_sharing';
+ $GLOBALS['fileOwner'] = \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1;
+ \OC_User::setUserId('');
+
+ // 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
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // 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(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . $publicShareKeyId . '.shareKey'));
+
+ // cleanup
+ $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '.shareKey'));
+ }
+
+ function testShareFileWithGroup() {
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // 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(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/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_GROUP, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1, OCP\PERMISSION_ALL);
+
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // check if share key for user2 and user3 exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey'));
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4 . '.shareKey'));
+
+ // login as user1
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
+
+ // get file contents
+ $retrievedCryptedFile = $this->view->file_get_contents(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '/files/Shared/' . $this->filename);
+
+ // check if data is the same as we previously written
+ $this->assertEquals($this->dataShort, $retrievedCryptedFile);
+
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // unshare the file
+ \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey'));
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4 . '.shareKey'));
+
+ // cleanup
+ $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '.shareKey'));
+
+ }
+
+ function testRecoveryFile() {
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ \OCA\Encryption\Helper::adminEnableRecovery(null, 'test123');
+ $recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId');
+
+ // check if control file created
+ $this->assertTrue($this->view->file_exists('/control-file/controlfile.enc'));
+
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ $util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // check if recovery password match
+ $this->assertTrue($util->checkRecoveryPassword('test123'));
+
+ // enable recovery for admin
+ $this->assertTrue($util->setRecoveryForUser(1));
+
+ // create folder structure
+ $this->view->mkdir('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files' . $this->folder1);
+ $this->view->mkdir(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files' . $this->folder1 . $this->subfolder);
+ $this->view->mkdir(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files' . $this->folder1 . $this->subfolder
+ . $this->subsubfolder);
+
+ // save file with content
+ $cryptedFile1 = file_put_contents('crypt://' . $this->filename, $this->dataShort);
+ $cryptedFile2 = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename, $this->dataShort);
+
+ // test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile1));
+ $this->assertTrue(is_int($cryptedFile2));
+
+ // check if share key for admin and recovery exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '.shareKey'));
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/' . $this->folder1
+ . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '.shareKey'));
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/' . $this->folder1
+ . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
+
+ // disable recovery for admin
+ $this->assertTrue($util->setRecoveryForUser(0));
+
+ // remove all recovery keys
+ $util->removeRecoveryKeys('/');
+
+ // check if share key for recovery not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/' . $this->folder1
+ . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
+
+ // enable recovery for admin
+ $this->assertTrue($util->setRecoveryForUser(1));
+
+ // remove all recovery keys
+ $util->addRecoveryKeys('/');
+
+ // check if share key for admin and recovery exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/' . $this->folder1
+ . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
+
+ // cleanup
+ $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
+ $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->folder1);
+
+ // check if share key for recovery not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/' . $this->folder1
+ . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
+
+ $this->assertTrue(\OCA\Encryption\Helper::adminEnableRecovery(null, 'test123'));
+ $this->assertTrue(\OCA\Encryption\Helper::adminDisableRecovery('test123'));
+ $this->assertEquals(0, \OC_Appconfig::getValue('files_encryption', 'recoveryAdminEnabled'));
+ }
+
+ function testRecoveryForUser() {
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ \OCA\Encryption\Helper::adminEnableRecovery(null, 'test123');
+ $recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId');
+
+ // check if control file created
+ $this->assertTrue($this->view->file_exists('/control-file/controlfile.enc'));
+
+ // login as user1
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+
+ $util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
+
+ // enable recovery for admin
+ $this->assertTrue($util->setRecoveryForUser(1));
+
+ // create folder structure
+ $this->view->mkdir('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1);
+ $this->view->mkdir(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1 . $this->subfolder);
+ $this->view->mkdir(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1 . $this->subfolder
+ . $this->subsubfolder);
+
+ // save file with content
+ $cryptedFile1 = file_put_contents('crypt://' . $this->filename, $this->dataShort);
+ $cryptedFile2 = file_put_contents('crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename, $this->dataShort);
+
+ // test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile1));
+ $this->assertTrue(is_int($cryptedFile2));
+
+ // check if share key for user and recovery exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->folder1
+ . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->folder1
+ . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
+
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // change password
+ \OC_User::setPassword(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, 'test', 'test123');
+
+ // login as user1
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, false, 'test');
+
+ // get file contents
+ $retrievedCryptedFile1 = file_get_contents('crypt://' . $this->filename);
+ $retrievedCryptedFile2 = file_get_contents(
+ 'crypt://' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
+
+ // check if data is the same as we previously written
+ $this->assertEquals($this->dataShort, $retrievedCryptedFile1);
+ $this->assertEquals($this->dataShort, $retrievedCryptedFile2);
+
+ // cleanup
+ $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1);
+ $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->filename);
+
+ // check if share key for user and recovery exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->folder1
+ . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files_encryption/share-keys/' . $this->folder1
+ . $this->subfolder . $this->subsubfolder . '/'
+ . $this->filename . '.' . $recoveryKeyId . '.shareKey'));
+
+ // enable recovery for admin
+ $this->assertTrue($util->setRecoveryForUser(0));
+
+ \OCA\Encryption\Helper::adminDisableRecovery('test123');
+ $this->assertEquals(0, \OC_Appconfig::getValue('files_encryption', 'recoveryAdminEnabled'));
+ }
+
+ function testFailShareFile() {
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // 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(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/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']);
+
+ // break users public key
+ $this->view->rename('/public-keys/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.public.key',
+ '/public-keys/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.public.key_backup');
+
+ // re-enable the file proxy
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ // share the file
+ \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1, OCP\PERMISSION_ALL);
+
+ // login as admin
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
+
+ // check if share key for user1 not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey'));
+
+ // disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ // break user1 public key
+ $this->view->rename(
+ '/public-keys/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.public.key_backup',
+ '/public-keys/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.public.key');
+
+ // remove share file
+ $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3
+ . '.shareKey');
+
+ // re-enable the file proxy
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ // unshare the file with user1
+ \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1);
+
+ // check if share key not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey'));
+
+ // cleanup
+ $this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
+ }
+
+}
diff --git a/apps/files_encryption/tests/stream.php b/apps/files_encryption/tests/stream.php
new file mode 100644
index 00000000000..3d978767542
--- /dev/null
+++ b/apps/files_encryption/tests/stream.php
@@ -0,0 +1,180 @@
+<?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__) . '/../../../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__) . '/../appinfo/app.php');
+require_once realpath(dirname(__FILE__) . '/util.php');
+
+use OCA\Encryption;
+
+/**
+ * Class Test_Encryption_Stream
+ * @brief this class provide basic stream tests
+ */
+class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
+
+ const TEST_ENCRYPTION_STREAM_USER1 = "test-stream-user1";
+
+ public $userId;
+ public $pass;
+ /**
+ * @var \OC_FilesystemView
+ */
+ public $view;
+ public $dataShort;
+ public $stateFilesTrashbin;
+
+ public static function setUpBeforeClass() {
+ // reset backend
+ \OC_User::clearBackends();
+ \OC_User::useBackend('database');
+
+ // Filesystem related hooks
+ \OCA\Encryption\Helper::registerFilesystemHooks();
+
+ // clear and register hooks
+ \OC_FileProxy::clearProxies();
+ \OC_FileProxy::register(new OCA\Encryption\Proxy());
+
+ // create test user
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Stream::TEST_ENCRYPTION_STREAM_USER1, true);
+ }
+
+ function setUp() {
+ // set user id
+ \OC_User::setUserId(\Test_Encryption_Stream::TEST_ENCRYPTION_STREAM_USER1);
+ $this->userId = \Test_Encryption_Stream::TEST_ENCRYPTION_STREAM_USER1;
+ $this->pass = \Test_Encryption_Stream::TEST_ENCRYPTION_STREAM_USER1;
+
+ // init filesystem view
+ $this->view = new \OC_FilesystemView('/');
+
+ // init short data
+ $this->dataShort = 'hats';
+
+ // 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');
+ }
+
+ function tearDown() {
+ // reset app files_trashbin
+ if ($this->stateFilesTrashbin) {
+ OC_App::enable('files_trashbin');
+ }
+ else {
+ OC_App::disable('files_trashbin');
+ }
+ }
+
+ public static function tearDownAfterClass() {
+ // cleanup test user
+ \OC_User::deleteUser(\Test_Encryption_Stream::TEST_ENCRYPTION_STREAM_USER1);
+ }
+
+ function testStreamOptions() {
+ $filename = '/tmp-' . time();
+ $view = new \OC\Files\View('/' . $this->userId . '/files');
+
+ // Save short data as encrypted file using stream wrapper
+ $cryptedFile = $view->file_put_contents($filename, $this->dataShort);
+
+ // Test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile));
+
+ $handle = $view->fopen($filename, 'r');
+
+ // check if stream is at position zero
+ $this->assertEquals(0, ftell($handle));
+
+ // set stream options
+ $this->assertTrue(flock($handle, LOCK_SH));
+ $this->assertTrue(flock($handle, LOCK_UN));
+
+ // tear down
+ $view->unlink($filename);
+ }
+
+ function testStreamSetBlocking() {
+ $filename = '/tmp-' . time();
+ $view = new \OC\Files\View('/' . $this->userId . '/files');
+
+ // Save short data as encrypted file using stream wrapper
+ $cryptedFile = $view->file_put_contents($filename, $this->dataShort);
+
+ // Test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile));
+
+ $handle = $view->fopen($filename, 'r');
+
+ // set stream options
+ $this->assertTrue(stream_set_blocking($handle, 1));
+
+ // tear down
+ $view->unlink($filename);
+ }
+
+ function testStreamSetTimeout() {
+ $filename = '/tmp-' . time();
+ $view = new \OC\Files\View('/' . $this->userId . '/files');
+
+ // Save short data as encrypted file using stream wrapper
+ $cryptedFile = $view->file_put_contents($filename, $this->dataShort);
+
+ // Test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile));
+
+ $handle = $view->fopen($filename, 'r');
+
+ // set stream options
+ $this->assertFalse(stream_set_timeout($handle, 1));
+
+ // tear down
+ $view->unlink($filename);
+ }
+
+ function testStreamSetWriteBuffer() {
+ $filename = '/tmp-' . time();
+ $view = new \OC\Files\View('/' . $this->userId . '/files');
+
+ // Save short data as encrypted file using stream wrapper
+ $cryptedFile = $view->file_put_contents($filename, $this->dataShort);
+
+ // Test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile));
+
+ $handle = $view->fopen($filename, 'r');
+
+ // set stream options
+ $this->assertEquals(0, stream_set_write_buffer($handle, 1024));
+
+ // tear down
+ $view->unlink($filename);
+ }
+} \ No newline at end of file
diff --git a/apps/files_encryption/tests/trashbin.php b/apps/files_encryption/tests/trashbin.php
new file mode 100755
index 00000000000..29f8fb5a396
--- /dev/null
+++ b/apps/files_encryption/tests/trashbin.php
@@ -0,0 +1,300 @@
+<?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__) . '/../../../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__) . '/../appinfo/app.php');
+require_once realpath(dirname(__FILE__) . '/../../files_trashbin/appinfo/app.php');
+require_once realpath(dirname(__FILE__) . '/util.php');
+
+use OCA\Encryption;
+
+/**
+ * Class Test_Encryption_Trashbin
+ * @brief this class provide basic trashbin app tests
+ */
+class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
+
+ const TEST_ENCRYPTION_TRASHBIN_USER1 = "test-trashbin-user1";
+
+ public $userId;
+ public $pass;
+ /**
+ * @var \OC_FilesystemView
+ */
+ public $view;
+ public $dataShort;
+ public $stateFilesTrashbin;
+ public $folder1;
+ public $subfolder;
+ public $subsubfolder;
+
+ public static function setUpBeforeClass() {
+ // reset backend
+ \OC_User::clearBackends();
+ \OC_User::useBackend('database');
+
+ \OC_Hook::clear('OC_Filesystem');
+ \OC_Hook::clear('OC_User');
+
+ // trashbin hooks
+ \OCA\Files_Trashbin\Trashbin::registerHooks();
+
+ // Filesystem related hooks
+ \OCA\Encryption\Helper::registerFilesystemHooks();
+
+ // clear and register hooks
+ \OC_FileProxy::clearProxies();
+ \OC_FileProxy::register(new OCA\Encryption\Proxy());
+
+ // create test user
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1, true);
+ }
+
+ function setUp() {
+ // set user id
+ \OC_User::setUserId(\Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1);
+ $this->userId = \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1;
+ $this->pass = \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1;
+
+ // init filesystem view
+ $this->view = new \OC_FilesystemView('/');
+
+ // init short data
+ $this->dataShort = 'hats';
+
+ $this->folder1 = '/folder1';
+ $this->subfolder = '/subfolder1';
+ $this->subsubfolder = '/subsubfolder1';
+
+ // remember files_trashbin state
+ $this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
+
+ // we want to tests with app files_trashbin enabled
+ \OC_App::enable('files_trashbin');
+ }
+
+ function tearDown() {
+ // reset app files_trashbin
+ if ($this->stateFilesTrashbin) {
+ OC_App::enable('files_trashbin');
+ }
+ else {
+ OC_App::disable('files_trashbin');
+ }
+ }
+
+ public static function tearDownAfterClass() {
+ // cleanup test user
+ \OC_User::deleteUser(\Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1);
+ }
+
+ /**
+ * @brief test delete file
+ */
+ function testDeleteFile() {
+
+ // generate filename
+ $filename = 'tmp-' . time() . '.txt';
+
+ // save file with content
+ $cryptedFile = file_put_contents('crypt:///' . $filename, $this->dataShort);
+
+ // test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile));
+
+ // check if key for admin exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename
+ . '.key'));
+
+ // check if share key for admin exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
+ . $filename . '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
+
+ // delete file
+ \OC\FIles\Filesystem::unlink($filename);
+
+ // check if file not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename));
+
+ // check if key for admin not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename
+ . '.key'));
+
+ // check if share key for admin not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
+ . $filename . '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
+
+ // get files
+ $trashFiles = $this->view->getDirectoryContent(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/files/');
+
+ $trashFileSuffix = null;
+ // find created file with timestamp
+ foreach ($trashFiles as $file) {
+ if (strncmp($file['path'], $filename, strlen($filename))) {
+ $path_parts = pathinfo($file['name']);
+ $trashFileSuffix = $path_parts['extension'];
+ }
+ }
+
+ // check if we found the file we created
+ $this->assertNotNull($trashFileSuffix);
+
+ // check if key for admin not exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/keyfiles/' . $filename
+ . '.key.' . $trashFileSuffix));
+
+ // check if share key for admin not exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/share-keys/' . $filename
+ . '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey.' . $trashFileSuffix));
+
+ // return filename for next test
+ return $filename . '.' . $trashFileSuffix;
+ }
+
+ /**
+ * @brief test restore file
+ *
+ * @depends testDeleteFile
+ */
+ function testRestoreFile($filename) {
+
+ // prepare file information
+ $path_parts = pathinfo($filename);
+ $trashFileSuffix = $path_parts['extension'];
+ $timestamp = str_replace('d', '', $trashFileSuffix);
+ $fileNameWithoutSuffix = str_replace('.' . $trashFileSuffix, '', $filename);
+
+ // restore file
+ $this->assertTrue(\OCA\Files_Trashbin\Trashbin::restore($filename, $fileNameWithoutSuffix, $timestamp));
+
+ // check if file exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $fileNameWithoutSuffix));
+
+ // check if key for admin exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/'
+ . $fileNameWithoutSuffix . '.key'));
+
+ // check if share key for admin exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
+ . $fileNameWithoutSuffix . '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
+ }
+
+ /**
+ * @brief test delete file forever
+ */
+ function testPermanentDeleteFile() {
+
+ // generate filename
+ $filename = 'tmp-' . time() . '.txt';
+
+ // save file with content
+ $cryptedFile = file_put_contents('crypt:///' . $filename, $this->dataShort);
+
+ // test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile));
+
+ // check if key for admin exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename
+ . '.key'));
+
+ // check if share key for admin exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
+ . $filename . '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
+
+ // delete file
+ \OC\FIles\Filesystem::unlink($filename);
+
+ // check if file not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename));
+
+ // check if key for admin not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename
+ . '.key'));
+
+ // check if share key for admin not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
+ . $filename . '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
+
+ // find created file with timestamp
+ $query = \OC_DB::prepare('SELECT `timestamp`,`type` FROM `*PREFIX*files_trash`'
+ . ' WHERE `id`=?');
+ $result = $query->execute(array($filename))->fetchRow();
+
+ $this->assertTrue(is_array($result));
+
+ // build suffix
+ $trashFileSuffix = 'd' . $result['timestamp'];
+
+ // check if key for admin exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/keyfiles/' . $filename
+ . '.key.' . $trashFileSuffix));
+
+ // check if share key for admin exists
+ $this->assertTrue($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/share-keys/' . $filename
+ . '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey.' . $trashFileSuffix));
+
+ // get timestamp from file
+ $timestamp = str_replace('d', '', $trashFileSuffix);
+
+ // delete file forever
+ $this->assertGreaterThan(0, \OCA\Files_Trashbin\Trashbin::delete($filename, $timestamp));
+
+ // check if key for admin not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/files/' . $filename . '.'
+ . $trashFileSuffix));
+
+ // check if key for admin not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/keyfiles/' . $filename
+ . '.key.' . $trashFileSuffix));
+
+ // check if share key for admin not exists
+ $this->assertFalse($this->view->file_exists(
+ '/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/share-keys/' . $filename
+ . '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey.' . $trashFileSuffix));
+ }
+
+} \ No newline at end of file
diff --git a/apps/files_encryption/tests/util.php b/apps/files_encryption/tests/util.php
new file mode 100755
index 00000000000..0dc452a41c8
--- /dev/null
+++ b/apps/files_encryption/tests/util.php
@@ -0,0 +1,317 @@
+<?php
+/**
+ * Copyright (c) 2012 Sam Tuke <samtuke@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+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__) . '/../appinfo/app.php');
+
+use OCA\Encryption;
+
+/**
+ * Class Test_Encryption_Util
+ */
+class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
+
+ const TEST_ENCRYPTION_UTIL_USER1 = "test-util-user1";
+ const TEST_ENCRYPTION_UTIL_LEGACY_USER = "test-legacy-user";
+
+ public $userId;
+ public $encryptionDir;
+ public $publicKeyDir;
+ public $pass;
+ /**
+ * @var OC_FilesystemView
+ */
+ public $view;
+ public $keyfilesPath;
+ public $publicKeyPath;
+ public $privateKeyPath;
+ /**
+ * @var \OCA\Encryption\Util
+ */
+ public $util;
+ public $dataShort;
+ public $legacyEncryptedData;
+ public $legacyEncryptedDataKey;
+ public $legacyKey;
+ public $stateFilesTrashbin;
+
+ public static function setUpBeforeClass() {
+ // reset backend
+ \OC_User::clearBackends();
+ \OC_User::useBackend('database');
+
+ // Filesystem related hooks
+ \OCA\Encryption\Helper::registerFilesystemHooks();
+
+ // clear and register hooks
+ \OC_FileProxy::clearProxies();
+ \OC_FileProxy::register(new OCA\Encryption\Proxy());
+
+ // create test user
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1, true);
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER, true);
+ }
+
+
+ function setUp() {
+ \OC_User::setUserId(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
+ $this->userId = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1;
+ $this->pass = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1;
+
+ // 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->legacyEncryptedDataKey = realpath(dirname(__FILE__) . '/encryption.key');
+ $this->legacyKey = '30943623843030686906';
+
+ $keypair = Encryption\Crypt::createKeypair();
+
+ $this->genPublicKey = $keypair['publicKey'];
+ $this->genPrivateKey = $keypair['privateKey'];
+
+ $this->publicKeyDir = '/' . 'public-keys';
+ $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption';
+ $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->util = new Encryption\Util($this->view, $this->userId);
+
+ // 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');
+ }
+
+ function tearDown() {
+ // reset app files_trashbin
+ if ($this->stateFilesTrashbin) {
+ OC_App::enable('files_trashbin');
+ }
+ else {
+ OC_App::disable('files_trashbin');
+ }
+ }
+
+ public static function tearDownAfterClass() {
+ // cleanup test user
+ \OC_User::deleteUser(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
+ \OC_User::deleteUser(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER);
+ }
+
+ /**
+ * @brief test that paths set during User construction are correct
+ */
+ function testKeyPaths() {
+ $util = new Encryption\Util($this->view, $this->userId);
+
+ $this->assertEquals($this->publicKeyDir, $util->getPath('publicKeyDir'));
+ $this->assertEquals($this->encryptionDir, $util->getPath('encryptionDir'));
+ $this->assertEquals($this->keyfilesPath, $util->getPath('keyfilesPath'));
+ $this->assertEquals($this->publicKeyPath, $util->getPath('publicKeyPath'));
+ $this->assertEquals($this->privateKeyPath, $util->getPath('privateKeyPath'));
+
+ }
+
+ /**
+ * @brief test setup of encryption directories
+ */
+ function testSetupServerSide() {
+ $this->assertEquals(true, $this->util->setupServerSide($this->pass));
+ }
+
+ /**
+ * @brief test checking whether account is ready for encryption,
+ */
+ function testUserIsReady() {
+ $this->assertEquals(true, $this->util->ready());
+ }
+
+ /**
+ * @brief test checking whether account is not ready for encryption,
+ */
+// function testUserIsNotReady() {
+// $this->view->unlink($this->publicKeyDir);
+//
+// $params['uid'] = $this->userId;
+// $params['password'] = $this->pass;
+// $this->assertFalse(OCA\Encryption\Hooks::login($params));
+//
+// $this->view->unlink($this->privateKeyPath);
+// }
+
+ /**
+ * @brief test checking whether account is not ready for encryption,
+ */
+ function testIsLegacyUser() {
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER);
+
+ $userView = new \OC_FilesystemView('/' . \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER);
+
+ // Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ $encryptionKeyContent = file_get_contents($this->legacyEncryptedDataKey);
+ $userView->file_put_contents('/encryption.key', $encryptionKeyContent);
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ $params['uid'] = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER;
+ $params['password'] = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER;
+
+ $util = new Encryption\Util($this->view, \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER);
+ $util->setMigrationStatus(0);
+
+ $this->assertTrue(OCA\Encryption\Hooks::login($params));
+
+ $this->assertEquals($this->legacyKey, \OC::$session->get('legacyKey'));
+ }
+
+ 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->recoveryEnabledForUser();
+
+ $this->assertTrue($util->setRecoveryForUser(1));
+
+ $this->assertEquals(1, $util->recoveryEnabledForUser());
+
+ $this->assertTrue($util->setRecoveryForUser(0));
+
+ $this->assertEquals(0, $util->recoveryEnabledForUser());
+
+ // Return the setting to it's previous state
+ $this->assertTrue($util->setRecoveryForUser($enabled));
+
+ }
+
+ function testGetUidAndFilename() {
+
+ \OC_User::setUserId(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
+
+ $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(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1, $fileOwnerUid);
+
+ $this->assertEquals($file, $filename);
+
+ $this->view->unlink($this->userId . '/files/' . $filename);
+ }
+
+ function testIsSharedPath() {
+ $sharedPath = '/user1/files/Shared/test';
+ $path = '/user1/files/test';
+
+ $this->assertTrue($this->util->isSharedPath($sharedPath));
+
+ $this->assertFalse($this->util->isSharedPath($path));
+ }
+
+ function testEncryptLegacyFiles() {
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER);
+
+ $userView = new \OC_FilesystemView('/' . \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER);
+ $view = new \OC_FilesystemView('/' . \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER . '/files');
+
+ // Disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ $encryptionKeyContent = file_get_contents($this->legacyEncryptedDataKey);
+ $userView->file_put_contents('/encryption.key', $encryptionKeyContent);
+
+ $legacyEncryptedData = file_get_contents($this->legacyEncryptedData);
+ $view->mkdir('/test/');
+ $view->mkdir('/test/subtest/');
+ $view->file_put_contents('/test/subtest/legacy-encrypted-text.txt', $legacyEncryptedData);
+
+ $fileInfo = $view->getFileInfo('/test/subtest/legacy-encrypted-text.txt');
+ $fileInfo['encrypted'] = true;
+ $view->putFileInfo('/test/subtest/legacy-encrypted-text.txt', $fileInfo);
+
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ $params['uid'] = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER;
+ $params['password'] = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER;
+
+ $util = new Encryption\Util($this->view, \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER);
+ $util->setMigrationStatus(0);
+
+ $this->assertTrue(OCA\Encryption\Hooks::login($params));
+
+ $this->assertEquals($this->legacyKey, \OC::$session->get('legacyKey'));
+
+ $files = $util->findEncFiles('/' . \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER . '/files/');
+
+ $this->assertTrue(is_array($files));
+
+ $found = false;
+ foreach ($files['encrypted'] as $encryptedFile) {
+ if ($encryptedFile['name'] === 'legacy-encrypted-text.txt') {
+ $found = true;
+ break;
+ }
+ }
+
+ $this->assertTrue($found);
+ }
+
+ /**
+ * @param $user
+ * @param bool $create
+ * @param bool $password
+ */
+ public static function loginHelper($user, $create = false, $password = false) {
+ if ($create) {
+ \OC_User::createUser($user, $user);
+ }
+
+ if ($password === false) {
+ $password = $user;
+ }
+
+ \OC_Util::tearDownFS();
+ \OC_User::setUserId('');
+ \OC\Files\Filesystem::tearDown();
+ \OC_Util::setupFS($user);
+ \OC_User::setUserId($user);
+
+ $params['uid'] = $user;
+ $params['password'] = $password;
+ OCA\Encryption\Hooks::login($params);
+ }
+}
diff --git a/apps/files_encryption/tests/webdav.php b/apps/files_encryption/tests/webdav.php
new file mode 100755
index 00000000000..1d406789f0c
--- /dev/null
+++ b/apps/files_encryption/tests/webdav.php
@@ -0,0 +1,262 @@
+<?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__) . '/../../../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__) . '/../appinfo/app.php');
+require_once realpath(dirname(__FILE__) . '/util.php');
+
+use OCA\Encryption;
+
+/**
+ * Class Test_Encryption_Webdav
+ * @brief this class provide basic webdav tests for PUT,GET and DELETE
+ */
+class Test_Encryption_Webdav extends \PHPUnit_Framework_TestCase {
+
+ const TEST_ENCRYPTION_WEBDAV_USER1 = "test-webdav-user1";
+
+ public $userId;
+ public $pass;
+ /**
+ * @var \OC_FilesystemView
+ */
+ public $view;
+ public $dataShort;
+ public $stateFilesTrashbin;
+
+ public static function setUpBeforeClass() {
+ // reset backend
+ \OC_User::clearBackends();
+ \OC_User::useBackend('database');
+
+ // Filesystem related hooks
+ \OCA\Encryption\Helper::registerFilesystemHooks();
+
+ // Filesystem related hooks
+ \OCA\Encryption\Helper::registerUserHooks();
+
+ // clear and register hooks
+ \OC_FileProxy::clearProxies();
+ \OC_FileProxy::register(new OCA\Encryption\Proxy());
+
+ // create test user
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Webdav::TEST_ENCRYPTION_WEBDAV_USER1, true);
+ }
+
+ function setUp() {
+ // reset backend
+ \OC_User::useBackend('database');
+
+ // set user id
+ \OC_User::setUserId(\Test_Encryption_Webdav::TEST_ENCRYPTION_WEBDAV_USER1);
+ $this->userId = \Test_Encryption_Webdav::TEST_ENCRYPTION_WEBDAV_USER1;
+ $this->pass = \Test_Encryption_Webdav::TEST_ENCRYPTION_WEBDAV_USER1;
+
+ // init filesystem view
+ $this->view = new \OC_FilesystemView('/');
+
+ // init short data
+ $this->dataShort = 'hats';
+
+ // 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 test user
+ \Test_Encryption_Util::loginHelper(\Test_Encryption_Webdav::TEST_ENCRYPTION_WEBDAV_USER1);
+ }
+
+ function tearDown() {
+ // reset app files_trashbin
+ if ($this->stateFilesTrashbin) {
+ OC_App::enable('files_trashbin');
+ }
+ else {
+ OC_App::disable('files_trashbin');
+ }
+ }
+
+ public static function tearDownAfterClass() {
+ // cleanup test user
+ \OC_User::deleteUser(\Test_Encryption_Webdav::TEST_ENCRYPTION_WEBDAV_USER1);
+ }
+
+ /**
+ * @brief test webdav put random file
+ */
+ function testWebdavPUT() {
+
+ // generate filename
+ $filename = '/tmp-' . time() . '.txt';
+
+ // set server vars
+ $_SERVER['REQUEST_METHOD'] = 'OPTIONS';
+
+ $_SERVER['REQUEST_METHOD'] = 'PUT';
+ $_SERVER['REQUEST_URI'] = '/remote.php/webdav' . $filename;
+ $_SERVER['HTTP_AUTHORIZATION'] = 'Basic dGVzdC13ZWJkYXYtdXNlcjE6dGVzdC13ZWJkYXYtdXNlcjE=';
+ $_SERVER['CONTENT_TYPE'] = 'application/octet-stream';
+ $_SERVER['PATH_INFO'] = '/webdav' . $filename;
+ $_SERVER['CONTENT_LENGTH'] = strlen($this->dataShort);
+
+ // handle webdav request
+ $this->handleWebdavRequest($this->dataShort);
+
+ // check if file was created
+ $this->assertTrue($this->view->file_exists('/' . $this->userId . '/files' . $filename));
+
+ // check if key-file was created
+ $this->assertTrue($this->view->file_exists(
+ '/' . $this->userId . '/files_encryption/keyfiles/' . $filename . '.key'));
+
+ // check if shareKey-file was created
+ $this->assertTrue($this->view->file_exists(
+ '/' . $this->userId . '/files_encryption/share-keys/' . $filename . '.' . $this->userId . '.shareKey'));
+
+ // disable encryption proxy to prevent recursive calls
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ // get encrypted file content
+ $encryptedContent = $this->view->file_get_contents('/' . $this->userId . '/files' . $filename);
+
+ // restore proxy state
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ // check if encrypted content is valid
+ $this->assertTrue(Encryption\Crypt::isCatfileContent($encryptedContent));
+
+ // get decrypted file contents
+ $decrypt = file_get_contents('crypt://' . $filename);
+
+ // check if file content match with the written content
+ $this->assertEquals($this->dataShort, $decrypt);
+
+ // return filename for next test
+ return $filename;
+ }
+
+ /**
+ * @brief test webdav get random file
+ *
+ * @depends testWebdavPUT
+ */
+ function testWebdavGET($filename) {
+
+ // set server vars
+ $_SERVER['REQUEST_METHOD'] = 'GET';
+ $_SERVER['REQUEST_URI'] = '/remote.php/webdav' . $filename;
+ $_SERVER['HTTP_AUTHORIZATION'] = 'Basic dGVzdC13ZWJkYXYtdXNlcjE6dGVzdC13ZWJkYXYtdXNlcjE=';
+ $_SERVER['PATH_INFO'] = '/webdav' . $filename;
+
+ // handle webdav request
+ $content = $this->handleWebdavRequest();
+
+ // check if file content match with the written content
+ $this->assertEquals($this->dataShort, $content);
+
+ // return filename for next test
+ return $filename;
+ }
+
+ /**
+ * @brief test webdav delete random file
+ * @depends testWebdavGET
+ */
+ function testWebdavDELETE($filename) {
+ // set server vars
+ $_SERVER['REQUEST_METHOD'] = 'DELETE';
+ $_SERVER['REQUEST_URI'] = '/remote.php/webdav' . $filename;
+ $_SERVER['HTTP_AUTHORIZATION'] = 'Basic dGVzdC13ZWJkYXYtdXNlcjE6dGVzdC13ZWJkYXYtdXNlcjE=';
+ $_SERVER['PATH_INFO'] = '/webdav' . $filename;
+
+ // handle webdav request
+ $content = $this->handleWebdavRequest();
+
+ // check if file was removed
+ $this->assertFalse($this->view->file_exists('/' . $this->userId . '/files' . $filename));
+
+ // check if key-file was removed
+ $this->assertFalse($this->view->file_exists(
+ '/' . $this->userId . '/files_encryption/keyfiles' . $filename . '.key'));
+
+ // check if shareKey-file was removed
+ $this->assertFalse($this->view->file_exists(
+ '/' . $this->userId . '/files_encryption/share-keys' . $filename . '.' . $this->userId . '.shareKey'));
+ }
+
+ /**
+ * @brief handle webdav request
+ *
+ * @param bool $body
+ *
+ * @note this init procedure is copied from /apps/files/appinfo/remote.php
+ */
+ function handleWebdavRequest($body = false) {
+ // Backends
+ $authBackend = new OC_Connector_Sabre_Auth();
+ $lockBackend = new OC_Connector_Sabre_Locks();
+ $requestBackend = new OC_Connector_Sabre_Request();
+
+ // Create ownCloud Dir
+ $publicDir = new OC_Connector_Sabre_Directory('');
+
+ // Fire up server
+ $server = new Sabre_DAV_Server($publicDir);
+ $server->httpRequest = $requestBackend;
+ $server->setBaseUri('/remote.php/webdav/');
+
+ // Load plugins
+ $server->addPlugin(new Sabre_DAV_Auth_Plugin($authBackend, 'ownCloud'));
+ $server->addPlugin(new Sabre_DAV_Locks_Plugin($lockBackend));
+ $server->addPlugin(new Sabre_DAV_Browser_Plugin(false)); // Show something in the Browser, but no upload
+ $server->addPlugin(new OC_Connector_Sabre_QuotaPlugin());
+ $server->addPlugin(new OC_Connector_Sabre_MaintenancePlugin());
+
+ // And off we go!
+ if ($body) {
+ $server->httpRequest->setBody($body);
+ }
+
+ // turn on output buffering
+ ob_start();
+
+ // handle request
+ $server->exec();
+
+ // file content is written in the output buffer
+ $content = ob_get_contents();
+
+ // flush the output buffer and turn off output buffering
+ ob_end_clean();
+
+ // return captured content
+ return $content;
+ }
+} \ No newline at end of file
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