aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files_encryption/lib
diff options
context:
space:
mode:
authorBjoern Schiessle <schiessle@owncloud.com>2015-03-30 17:29:07 +0200
committerThomas Müller <thomas.mueller@tmit.eu>2015-04-07 13:30:28 +0200
commite7a68d1c21c52a39ddec59579ab7701dfef82b2a (patch)
treef18553183eee730b754f89bf2b5a2a1ce5facade /apps/files_encryption/lib
parent0eee3a2618235bcb59ce1bcb98526a7592de4578 (diff)
downloadnextcloud-server-e7a68d1c21c52a39ddec59579ab7701dfef82b2a.tar.gz
nextcloud-server-e7a68d1c21c52a39ddec59579ab7701dfef82b2a.zip
remove old encryption app
Diffstat (limited to 'apps/files_encryption/lib')
-rw-r--r--apps/files_encryption/lib/capabilities.php39
-rw-r--r--apps/files_encryption/lib/crypt.php581
-rw-r--r--apps/files_encryption/lib/helper.php532
-rw-r--r--apps/files_encryption/lib/hooks.php625
-rw-r--r--apps/files_encryption/lib/keymanager.php500
-rw-r--r--apps/files_encryption/lib/migration.php302
-rw-r--r--apps/files_encryption/lib/proxy.php401
-rw-r--r--apps/files_encryption/lib/session.php203
-rw-r--r--apps/files_encryption/lib/stream.php700
-rw-r--r--apps/files_encryption/lib/util.php1700
10 files changed, 0 insertions, 5583 deletions
diff --git a/apps/files_encryption/lib/capabilities.php b/apps/files_encryption/lib/capabilities.php
deleted file mode 100644
index 0ed696fc7cb..00000000000
--- a/apps/files_encryption/lib/capabilities.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-/**
- * @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Tom Needham <tom@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\Files_Encryption;
-
-class Capabilities {
-
- public static function getCapabilities() {
- return new \OC_OCS_Result(array(
- 'capabilities' => array(
- 'files' => array(
- 'encryption' => true,
- ),
- ),
- ));
- }
-
-}
diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php
deleted file mode 100644
index 784121c7ed1..00000000000
--- a/apps/files_encryption/lib/crypt.php
+++ /dev/null
@@ -1,581 +0,0 @@
-<?php
-/**
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Florin Peter <github@florin-peter.de>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Owen Winkler <a_github@midnightcircus.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- * @author Sam Tuke <mail@samtuke.com>
- * @author Scott Arciszewski <scott@arciszewski.me>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\Files_Encryption;
-
-/**
- * Class for common cryptography functionality
- */
-
-class Crypt {
-
- const ENCRYPTION_UNKNOWN_ERROR = -1;
- const ENCRYPTION_NOT_INITIALIZED_ERROR = 1;
- const ENCRYPTION_PRIVATE_KEY_NOT_VALID_ERROR = 2;
- const ENCRYPTION_NO_SHARE_KEY_FOUND = 3;
-
- const BLOCKSIZE = 8192; // block size will always be 8192 for a PHP stream https://bugs.php.net/bug.php?id=21641
- const DEFAULT_CIPHER = 'AES-256-CFB';
-
- const HEADERSTART = 'HBEGIN';
- const HEADEREND = 'HEND';
-
- /**
- * return encryption mode client or server side encryption
- * @param string $user name (use system wide setting if name=null)
- * @return string 'client' or 'server'
- * @note at the moment we only support server side encryption
- */
- public static function mode($user = null) {
-
- return 'server';
-
- }
-
- /**
- * Create a new encryption keypair
- * @return array publicKey, privatekey
- */
- public static function createKeypair() {
-
- $return = false;
-
- $res = Helper::getOpenSSLPkey();
-
- if ($res === false) {
- \OCP\Util::writeLog('Encryption library', 'couldn\'t generate users key-pair for ' . \OCP\User::getUser(), \OCP\Util::ERROR);
- while ($msg = openssl_error_string()) {
- \OCP\Util::writeLog('Encryption library', 'openssl_pkey_new() fails: ' . $msg, \OCP\Util::ERROR);
- }
- } elseif (openssl_pkey_export($res, $privateKey, null, Helper::getOpenSSLConfig())) {
- // Get public key
- $keyDetails = openssl_pkey_get_details($res);
- $publicKey = $keyDetails['key'];
-
- $return = array(
- 'publicKey' => $publicKey,
- 'privateKey' => $privateKey
- );
- } else {
- \OCP\Util::writeLog('Encryption library', 'couldn\'t export users private key, please check your servers openSSL configuration.' . \OCP\User::getUser(), \OCP\Util::ERROR);
- while($errMsg = openssl_error_string()) {
- \OCP\Util::writeLog('Encryption library', $errMsg, \OCP\Util::ERROR);
- }
- }
-
- return $return;
- }
-
- /**
- * Add arbitrary padding to encrypted data
- * @param string $data data to be padded
- * @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.
- */
- private static function addPadding($data) {
-
- $padded = $data . 'xx';
-
- return $padded;
-
- }
-
- /**
- * Remove arbitrary padding to encrypted data
- * @param string $padded padded data to remove padding from
- * @return string unpadded data on success, false on error
- */
- private static function removePadding($padded) {
-
- if (substr($padded, -2) === 'xx') {
-
- $data = substr($padded, 0, -2);
-
- return $data;
-
- } else {
-
- // TODO: log the fact that unpadded data was submitted for removal of padding
- return false;
-
- }
-
- }
-
- /**
- * Check if a file's contents contains an IV and is symmetrically encrypted
- * @param string $content
- * @return boolean
- * @note see also \OCA\Files_Encryption\Util->isEncryptedPath()
- */
- public static function isCatfileContent($content) {
-
- if (!$content) {
-
- return false;
-
- }
-
- $noPadding = self::removePadding($content);
-
- // Fetch encryption metadata from end of file
- $meta = substr($noPadding, -22);
-
- // Fetch identifier from start of metadata
- $identifier = substr($meta, 0, 6);
-
- if ($identifier === '00iv00') {
-
- return true;
-
- } else {
-
- return false;
-
- }
-
- }
-
- /**
- * Check if a file is encrypted according to database file cache
- * @param string $path
- * @return bool
- */
- 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);
-
- // Return encryption status
- return isset($metadata['encrypted']) && ( bool )$metadata['encrypted'];
-
- }
-
- /**
- * Symmetrically encrypt a string
- * @param string $plainContent
- * @param string $iv
- * @param string $passphrase
- * @param string $cypher used for encryption, currently we support AES-128-CFB and AES-256-CFB
- * @return string encrypted file content
- * @throws \OCA\Files_Encryption\Exception\EncryptionException
- */
- private static function encrypt($plainContent, $iv, $passphrase = '', $cipher = Crypt::DEFAULT_CIPHER) {
-
- $encryptedContent = openssl_encrypt($plainContent, $cipher, $passphrase, false, $iv);
-
- if (!$encryptedContent) {
- $error = "Encryption (symmetric) of content failed: " . openssl_error_string();
- \OCP\Util::writeLog('Encryption library', $error, \OCP\Util::ERROR);
- throw new Exception\EncryptionException($error, Exception\EncryptionException::ENCRYPTION_FAILED);
- }
-
- return $encryptedContent;
-
- }
-
- /**
- * Symmetrically decrypt a string
- * @param string $encryptedContent
- * @param string $iv
- * @param string $passphrase
- * @param string $cipher cipher user for decryption, currently we support aes128 and aes256
- * @throws \Exception
- * @return string decrypted file content
- */
- private static function decrypt($encryptedContent, $iv, $passphrase, $cipher = Crypt::DEFAULT_CIPHER) {
-
- $plainContent = openssl_decrypt($encryptedContent, $cipher, $passphrase, false, $iv);
-
- if ($plainContent) {
- return $plainContent;
- } else {
- throw new \Exception('Encryption library: Decryption (symmetric) of content failed');
- }
-
- }
-
- /**
- * Concatenate encrypted data with its IV and padding
- * @param string $content content to be concatenated
- * @param string $iv IV to be concatenated
- * @return string concatenated content
- */
- private static function concatIv($content, $iv) {
-
- $combined = $content . '00iv00' . $iv;
-
- return $combined;
-
- }
-
- /**
- * Split concatenated data and IV into respective parts
- * @param string $catFile concatenated data to be split
- * @return array keys: encrypted, iv
- */
- private static function splitIv($catFile) {
-
- // Fetch encryption metadata from end of file
- $meta = substr($catFile, -22);
-
- // Fetch IV from end of file
- $iv = substr($meta, -16);
-
- // Remove IV and IV identifier text to expose encrypted content
- $encrypted = substr($catFile, 0, -22);
-
- $split = array(
- 'encrypted' => $encrypted,
- 'iv' => $iv
- );
-
- return $split;
-
- }
-
- /**
- * Symmetrically encrypts a string and returns keyfile content
- * @param string $plainContent content to be encrypted in keyfile
- * @param string $passphrase
- * @param string $cypher used for encryption, currently we support AES-128-CFB and AES-256-CFB
- * @return false|string encrypted content combined with IV
- * @note IV need not be specified, as it will be stored in the returned keyfile
- * and remain accessible therein.
- */
- public static function symmetricEncryptFileContent($plainContent, $passphrase = '', $cipher = Crypt::DEFAULT_CIPHER) {
-
- if (!$plainContent) {
- \OCP\Util::writeLog('Encryption library', 'symmetrically encryption failed, no content given.', \OCP\Util::ERROR);
- return false;
- }
-
- $iv = self::generateIv();
-
- try {
- $encryptedContent = self::encrypt($plainContent, $iv, $passphrase, $cipher);
- // Combine content to encrypt with IV identifier and actual IV
- $catfile = self::concatIv($encryptedContent, $iv);
- $padded = self::addPadding($catfile);
-
- return $padded;
- } catch (Exception\EncryptionException $e) {
- $message = 'Could not encrypt file content (code: ' . $e->getCode() . '): ';
- \OCP\Util::writeLog('files_encryption', $message . $e->getMessage(), \OCP\Util::ERROR);
- return false;
- }
-
- }
-
-
- /**
- * Symmetrically decrypts keyfile content
- * @param string $keyfileContent
- * @param string $passphrase
- * @param string $cipher cipher used for decryption, currently aes128 and aes256 is supported.
- * @throws \Exception
- * @return string|false
- * @internal param string $source
- * @internal param string $target
- * @internal param string $key the decryption key
- * @return string decrypted content
- *
- * This function decrypts a file
- */
- public static function symmetricDecryptFileContent($keyfileContent, $passphrase = '', $cipher = Crypt::DEFAULT_CIPHER) {
-
- if (!$keyfileContent) {
-
- throw new \Exception('Encryption library: no data provided for decryption');
-
- }
-
- // Remove padding
- $noPadding = self::removePadding($keyfileContent);
-
- // Split into enc data and catfile
- $catfile = self::splitIv($noPadding);
-
- if ($plainContent = self::decrypt($catfile['encrypted'], $catfile['iv'], $passphrase, $cipher)) {
-
- return $plainContent;
-
- } else {
- return false;
- }
-
- }
-
- /**
- * Decrypt private key and check if the result is a valid keyfile
- *
- * @param string $encryptedKey encrypted keyfile
- * @param string $passphrase to decrypt keyfile
- * @return string|false encrypted private key or false
- *
- * This function decrypts a file
- */
- public static function decryptPrivateKey($encryptedKey, $passphrase) {
-
- $header = self::parseHeader($encryptedKey);
- $cipher = self::getCipher($header);
-
- // if we found a header we need to remove it from the key we want to decrypt
- if (!empty($header)) {
- $encryptedKey = substr($encryptedKey, strpos($encryptedKey, self::HEADEREND) + strlen(self::HEADEREND));
- }
-
- $plainKey = self::symmetricDecryptFileContent($encryptedKey, $passphrase, $cipher);
-
- // check if this a valid private key
- $res = openssl_pkey_get_private($plainKey);
- if (is_resource($res)) {
- $sslInfo = openssl_pkey_get_details($res);
- if (!isset($sslInfo['key'])) {
- $plainKey = false;
- }
- } else {
- $plainKey = false;
- }
-
- return $plainKey;
-
- }
-
- /**
- * Create asymmetrically encrypted keyfile content using a generated key
- * @param string $plainContent content to be encrypted
- * @param array $publicKeys array keys must be the userId of corresponding user
- * @return array keys: keys (array, key = userId), data
- * @throws \OCA\Files_Encryption\Exception\MultiKeyEncryptException if encryption failed
- * @note symmetricDecryptFileContent() can decrypt files created using this method
- */
- 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\MultiKeyEncryptException('Cannot multiKeyEncrypt empty plain content', Exception\MultiKeyEncryptException::EMPTY_DATA);
- }
-
- // Set empty vars to be set by openssl by reference
- $sealed = '';
- $shareKeys = array();
- $mappedShareKeys = array();
-
- 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' => $mappedShareKeys,
- 'data' => $sealed
- );
-
- } else {
- throw new Exception\MultiKeyEncryptException('multi key encryption failed: ' . openssl_error_string(),
- Exception\MultiKeyEncryptException::OPENSSL_SEAL_FAILED);
- }
-
- }
-
- /**
- * Asymmetrically encrypt a file using multiple public keys
- * @param string $encryptedContent
- * @param string $shareKey
- * @param mixed $privateKey
- * @throws \OCA\Files_Encryption\Exception\MultiKeyDecryptException if decryption failed
- * @internal param string $plainContent contains decrypted content
- * @return 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, $shareKey, $privateKey) {
-
- if (!$encryptedContent) {
- throw new Exception\MultiKeyDecryptException('Cannot mutliKeyDecrypt empty plain content',
- Exception\MultiKeyDecryptException::EMPTY_DATA);
- }
-
- if (openssl_open($encryptedContent, $plainContent, $shareKey, $privateKey)) {
-
- return $plainContent;
-
- } else {
- throw new Exception\MultiKeyDecryptException('multiKeyDecrypt with share-key' . $shareKey . 'failed: ' . openssl_error_string(),
- Exception\MultiKeyDecryptException::OPENSSL_OPEN_FAILED);
- }
-
- }
-
- /**
- * Generates a pseudo random initialisation vector
- * @return String $iv generated IV
- */
- private static function generateIv() {
-
- if ($random = openssl_random_pseudo_bytes(12, $strong)) {
-
- if (!$strong) {
-
- // If OpenSSL indicates randomness is insecure, log error
- \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);
-
- return $iv;
-
- } else {
-
- throw new \Exception('Generating IV failed');
-
- }
-
- }
-
- /**
- * Generate a pseudo random 256-bit ASCII key, used as file key
- * @return string|false Generated key
- */
- public static function generateKey() {
-
- // Generate key
- if ($key = base64_encode(openssl_random_pseudo_bytes(32, $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()');
-
- }
-
- return $key;
-
- } else {
-
- return false;
-
- }
-
- }
-
- /**
- * read header into array
- *
- * @param string $data
- * @return array
- */
- public static function parseHeader($data) {
-
- $result = array();
-
- if (substr($data, 0, strlen(self::HEADERSTART)) === self::HEADERSTART) {
- $endAt = strpos($data, self::HEADEREND);
- $header = substr($data, 0, $endAt + strlen(self::HEADEREND));
-
- // +1 to not start with an ':' which would result in empty element at the beginning
- $exploded = explode(':', substr($header, strlen(self::HEADERSTART)+1));
-
- $element = array_shift($exploded);
- while ($element !== self::HEADEREND) {
-
- $result[$element] = array_shift($exploded);
-
- $element = array_shift($exploded);
-
- }
- }
-
- return $result;
- }
-
- /**
- * check if data block is the header
- *
- * @param string $data
- * @return boolean
- */
- public static function isHeader($data) {
-
- if (substr($data, 0, strlen(self::HEADERSTART)) === self::HEADERSTART) {
- return true;
- }
-
- return false;
- }
-
- /**
- * get chiper from header
- *
- * @param array $header
- * @throws \OCA\Files_Encryption\Exception\EncryptionException
- */
- public static function getCipher($header) {
- $cipher = isset($header['cipher']) ? $header['cipher'] : 'AES-128-CFB';
-
- if ($cipher !== 'AES-256-CFB' && $cipher !== 'AES-128-CFB') {
-
- throw new Exception\EncryptionException('file header broken, no supported cipher defined',
- Exception\EncryptionException::UNKNOWN_CIPHER);
- }
-
- return $cipher;
- }
-
- /**
- * generate header for encrypted file
- */
- public static function generateHeader() {
- $cipher = Helper::getCipher();
- $header = self::HEADERSTART . ':cipher:' . $cipher . ':' . self::HEADEREND;
-
- return $header;
- }
-
-}
diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php
deleted file mode 100644
index 1ae161ce99e..00000000000
--- a/apps/files_encryption/lib/helper.php
+++ /dev/null
@@ -1,532 +0,0 @@
-<?php
-/**
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Florin Peter <github@florin-peter.de>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Owen Winkler <a_github@midnightcircus.com>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\Files_Encryption;
-
-/**
- * Class to manage registration of hooks an various helper methods
- * @package OCA\Files_Encryption
- */
-class Helper {
-
- private static $tmpFileMapping; // Map tmp files to files in data/user/files
-
- /**
- * register share related hooks
- *
- */
- public static function registerShareHooks() {
-
- \OCP\Util::connectHook('OCP\Share', 'pre_shared', 'OCA\Files_Encryption\Hooks', 'preShared');
- \OCP\Util::connectHook('OCP\Share', 'post_shared', 'OCA\Files_Encryption\Hooks', 'postShared');
- \OCP\Util::connectHook('OCP\Share', 'post_unshare', 'OCA\Files_Encryption\Hooks', 'postUnshare');
- }
-
- /**
- * register user related hooks
- *
- */
- public static function registerUserHooks() {
-
- \OCP\Util::connectHook('OC_User', 'post_login', 'OCA\Files_Encryption\Hooks', 'login');
- \OCP\Util::connectHook('OC_User', 'logout', 'OCA\Files_Encryption\Hooks', 'logout');
- \OCP\Util::connectHook('OC_User', 'post_setPassword', 'OCA\Files_Encryption\Hooks', 'setPassphrase');
- \OCP\Util::connectHook('OC_User', 'pre_setPassword', 'OCA\Files_Encryption\Hooks', 'preSetPassphrase');
- \OCP\Util::connectHook('OC_User', 'post_createUser', 'OCA\Files_Encryption\Hooks', 'postCreateUser');
- \OCP\Util::connectHook('OC_User', 'post_deleteUser', 'OCA\Files_Encryption\Hooks', 'postDeleteUser');
- }
-
- /**
- * register filesystem related hooks
- *
- */
- public static function registerFilesystemHooks() {
-
- \OCP\Util::connectHook('OC_Filesystem', 'rename', 'OCA\Files_Encryption\Hooks', 'preRename');
- \OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Files_Encryption\Hooks', 'postRenameOrCopy');
- \OCP\Util::connectHook('OC_Filesystem', 'copy', 'OCA\Files_Encryption\Hooks', 'preCopy');
- \OCP\Util::connectHook('OC_Filesystem', 'post_copy', 'OCA\Files_Encryption\Hooks', 'postRenameOrCopy');
- \OCP\Util::connectHook('OC_Filesystem', 'post_delete', 'OCA\Files_Encryption\Hooks', 'postDelete');
- \OCP\Util::connectHook('OC_Filesystem', 'delete', 'OCA\Files_Encryption\Hooks', 'preDelete');
- \OCP\Util::connectHook('\OC\Core\LostPassword\Controller\LostController', 'post_passwordReset', 'OCA\Files_Encryption\Hooks', 'postPasswordReset');
- \OCP\Util::connectHook('OC_Filesystem', 'post_umount', 'OCA\Files_Encryption\Hooks', 'postUnmount');
- \OCP\Util::connectHook('OC_Filesystem', 'umount', 'OCA\Files_Encryption\Hooks', 'preUnmount');
- }
-
- /**
- * register app management related hooks
- *
- */
- public static function registerAppHooks() {
-
- \OCP\Util::connectHook('OC_App', 'pre_disable', 'OCA\Files_Encryption\Hooks', 'preDisable');
- \OCP\Util::connectHook('OC_App', 'post_disable', 'OCA\Files_Encryption\Hooks', 'postEnable');
- }
-
- /**
- * setup user for files_encryption
- *
- * @param Util $util
- * @param string $password
- * @return bool
- */
- public static function setupUser(Util $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;
- }
-
- /**
- * get recovery key id
- *
- * @return string|bool recovery key ID or false
- */
- public static function getRecoveryKeyId() {
- $appConfig = \OC::$server->getAppConfig();
- $key = $appConfig->getValue('files_encryption', 'recoveryKeyId');
-
- return ($key === null) ? false : $key;
- }
-
- public static function getPublicShareKeyId() {
- $appConfig = \OC::$server->getAppConfig();
- $key = $appConfig->getValue('files_encryption', 'publicShareKeyId');
-
- return ($key === null) ? false : $key;
- }
-
- /**
- * enable recovery
- *
- * @param string $recoveryKeyId
- * @param string $recoveryPassword
- * @return bool
- */
- public static function adminEnableRecovery($recoveryKeyId, $recoveryPassword) {
-
- $view = new \OC\Files\View('/');
- $appConfig = \OC::$server->getAppConfig();
-
- if ($recoveryKeyId === null) {
- $recoveryKeyId = 'recovery_' . substr(md5(time()), 0, 8);
- $appConfig->setValue('files_encryption', 'recoveryKeyId', $recoveryKeyId);
- }
-
- if (!Keymanager::recoveryKeyExists($view)) {
-
- $keypair = Crypt::createKeypair();
-
- // Save public key
- Keymanager::setPublicKey($keypair['publicKey'], $recoveryKeyId);
-
- $cipher = Helper::getCipher();
- $encryptedKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $recoveryPassword, $cipher);
- if ($encryptedKey) {
- Keymanager::setPrivateSystemKey($encryptedKey, $recoveryKeyId);
- // Set recoveryAdmin as enabled
- $appConfig->setValue('files_encryption', 'recoveryAdminEnabled', 1);
- $return = true;
- }
-
- } else { // get recovery key and check the password
- $util = new Util(new \OC\Files\View('/'), \OCP\User::getUser());
- $return = $util->checkRecoveryPassword($recoveryPassword);
- if ($return) {
- $appConfig->setValue('files_encryption', 'recoveryAdminEnabled', 1);
- }
- }
-
- return $return;
- }
-
- /**
- * 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) {
-
- $extension = pathinfo($path, PATHINFO_EXTENSION);
- if ( $extension === 'part') {
- return true;
- } else {
- return false;
- }
-
- }
-
-
- /**
- * 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 stripPartialFileExtension($path) {
- $extension = pathinfo($path, PATHINFO_EXTENSION);
-
- if ( $extension === 'part') {
-
- $newLength = strlen($path) - 5; // 5 = strlen(".part") = strlen(".etmp")
- $fPath = substr($path, 0, $newLength);
-
- // if path also contains a transaction id, we remove it too
- $extension = pathinfo($fPath, PATHINFO_EXTENSION);
- if(substr($extension, 0, 12) === 'ocTransferId') { // 12 = strlen("ocTransferId")
- $newLength = strlen($fPath) - strlen($extension) -1;
- $fPath = substr($fPath, 0, $newLength);
- }
- return $fPath;
-
- } else {
- return $path;
- }
- }
-
- /**
- * disable recovery
- *
- * @param string $recoveryPassword
- * @return bool
- */
- public static function adminDisableRecovery($recoveryPassword) {
- $util = new Util(new \OC\Files\View('/'), \OCP\User::getUser());
- $return = $util->checkRecoveryPassword($recoveryPassword);
-
- if ($return) {
- // Set recoveryAdmin as disabled
- \OC::$server->getAppConfig()->setValue('files_encryption', 'recoveryAdminEnabled', 0);
- }
-
- return $return;
- }
-
- /**
- * checks if access is public/anonymous user
- * @return bool
- */
- public static function isPublicAccess() {
- if (\OCP\User::getUser() === false) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * 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) {
- $split = self::splitPath($path);
-
- // it is not a file relative to data/user/files
- if (count($split) < 4 || $split[2] !== 'files') {
- return false;
- }
-
- $sliced = array_slice($split, 3);
- $relPath = implode('/', $sliced);
-
- return $relPath;
- }
-
- /**
- * try to get the user from the path if no user is logged in
- * @param string $path
- * @return string user
- */
- public static function getUser($path) {
-
- $user = \OCP\User::getUser();
-
-
- // if we are logged in, then we return the userid
- if ($user) {
- return $user;
- }
-
- // if no user is logged in we try to access a publicly shared files.
- // In this case we need to try to get the user from the path
- return self::getUserFromPath($path);
- }
-
- /**
- * extract user from path
- *
- * @param string $path
- * @return string user id
- * @throws Exception\EncryptionException
- */
- public static function getUserFromPath($path) {
- $split = self::splitPath($path);
-
- if (count($split) > 2 && (
- $split[2] === 'files' || $split[2] === 'files_versions' || $split[2] === 'cache' || $split[2] === 'files_trashbin')) {
-
- $user = $split[1];
-
- if (\OCP\User::userExists($user)) {
- return $user;
- }
- }
-
- throw new Exception\EncryptionException('Could not determine user', Exception\EncryptionException::GENERIC);
- }
-
- /**
- * get path to the corresponding file in data/user/files if path points
- * to a file in cache
- *
- * @param string $path path to a file in cache
- * @return string path to corresponding file relative to data/user/files
- * @throws Exception\EncryptionException
- */
- public static function getPathFromCachedFile($path) {
- $split = self::splitPath($path);
-
- if (count($split) < 5) {
- throw new Exception\EncryptionException('no valid cache file path', Exception\EncryptionException::GENERIC);
- }
-
- // we skip /user/cache/transactionId
- $sliced = array_slice($split, 4);
-
- return implode('/', $sliced);
- }
-
-
- /**
- * get path to the corresponding file in data/user/files for a version
- *
- * @param string $path path to a version
- * @return string path to corresponding file relative to data/user/files
- * @throws Exception\EncryptionException
- */
- public static function getPathFromVersion($path) {
- $split = self::splitPath($path);
-
- if (count($split) < 4) {
- throw new Exception\EncryptionException('no valid path to a version', Exception\EncryptionException::GENERIC);
- }
-
- // we skip user/files_versions
- $sliced = array_slice($split, 3);
- $relPath = implode('/', $sliced);
- //remove the last .v
- $realPath = substr($relPath, 0, strrpos($relPath, '.v'));
-
- return $realPath;
- }
-
- /**
- * create directory recursively
- *
- * @param string $path
- * @param \OC\Files\View $view
- */
- public static function mkdirr($path, \OC\Files\View $view) {
- $dirParts = self::splitPath(dirname($path));
- $dir = "";
- foreach ($dirParts as $part) {
- $dir = $dir . '/' . $part;
- if (!$view->file_exists($dir)) {
- $view->mkdir($dir);
- }
- }
- }
-
- /**
- * redirect to a error page
- * @param Session $session
- * @param int|null $errorCode
- * @throws \Exception
- */
- public static function redirectToErrorPage(Session $session, $errorCode = null) {
-
- if ($errorCode === null) {
- $init = $session->getInitialized();
- switch ($init) {
- case Session::INIT_EXECUTED:
- $errorCode = Crypt::ENCRYPTION_PRIVATE_KEY_NOT_VALID_ERROR;
- break;
- case Session::NOT_INITIALIZED:
- $errorCode = Crypt::ENCRYPTION_NOT_INITIALIZED_ERROR;
- break;
- default:
- $errorCode = Crypt::ENCRYPTION_UNKNOWN_ERROR;
- }
- }
-
- $location = \OCP\Util::linkToAbsolute('apps/files_encryption/files', 'error.php');
- $post = 0;
- if(count($_POST) > 0) {
- $post = 1;
- }
-
- if(defined('PHPUNIT_RUN') and PHPUNIT_RUN) {
- throw new \Exception("Encryption error: $errorCode");
- }
-
- header('Location: ' . $location . '?p=' . $post . '&errorCode=' . $errorCode);
- exit();
- }
-
- /**
- * check requirements for encryption app.
- * @return bool true if requirements are met
- */
- public static function checkRequirements() {
-
- //openssl extension needs to be loaded
- return extension_loaded("openssl");
-
- }
-
- /**
- * check some common errors if the server isn't configured properly for encryption
- * @return bool true if configuration seems to be OK
- */
- public static function checkConfiguration() {
- if(self::getOpenSSLPkey()) {
- return true;
- } else {
- while ($msg = openssl_error_string()) {
- \OCP\Util::writeLog('Encryption library', 'openssl_pkey_new() fails: ' . $msg, \OCP\Util::ERROR);
- }
- return false;
- }
- }
-
- /**
- * Create an openssl pkey with config-supplied settings
- * WARNING: This initializes a new private keypair, which is computationally expensive
- * @return resource The pkey resource created
- */
- public static function getOpenSSLPkey() {
- return openssl_pkey_new(self::getOpenSSLConfig());
- }
-
- /**
- * Return an array of OpenSSL config options, default + config
- * Used for multiple OpenSSL functions
- * @return array The combined defaults and config settings
- */
- public static function getOpenSSLConfig() {
- $config = array('private_key_bits' => 4096);
- $config = array_merge(\OC::$server->getConfig()->getSystemValue('openssl', array()), $config);
- return $config;
- }
-
- /**
- * remember from which file the tmp file (getLocalFile() call) was created
- * @param string $tmpFile path of tmp file
- * @param string $originalFile path of the original file relative to data/
- */
- public static function addTmpFileToMapper($tmpFile, $originalFile) {
- self::$tmpFileMapping[$tmpFile] = $originalFile;
- }
-
- /**
- * get the path of the original file
- * @param string $tmpFile path of the tmp file
- * @return string|false path of the original file or false
- */
- public static function getPathFromTmpFile($tmpFile) {
- if (isset(self::$tmpFileMapping[$tmpFile])) {
- return self::$tmpFileMapping[$tmpFile];
- }
-
- return false;
- }
-
- /**
- * detect file type, encryption can read/write regular files, versions
- * and cached files
- *
- * @param string $path
- * @return int
- * @throws Exception\EncryptionException
- */
- public static function detectFileType($path) {
- $parts = self::splitPath($path);
-
- if (count($parts) > 2) {
- switch ($parts[2]) {
- case 'files':
- return Util::FILE_TYPE_FILE;
- case 'files_versions':
- return Util::FILE_TYPE_VERSION;
- case 'cache':
- return Util::FILE_TYPE_CACHE;
- }
- }
-
- // thow exception if we couldn't detect a valid file type
- throw new Exception\EncryptionException('Could not detect file type', Exception\EncryptionException::GENERIC);
- }
-
- /**
- * read the cipher used for encryption from the config.php
- *
- * @return string
- */
- public static function getCipher() {
-
- $cipher = \OC::$server->getConfig()->getSystemValue('cipher', Crypt::DEFAULT_CIPHER);
-
- if ($cipher !== 'AES-256-CFB' && $cipher !== 'AES-128-CFB') {
- \OCP\Util::writeLog('files_encryption',
- 'wrong cipher defined in config.php, only AES-128-CFB and AES-256-CFB is supported. Fall back ' . Crypt::DEFAULT_CIPHER,
- \OCP\Util::WARN);
-
- $cipher = Crypt::DEFAULT_CIPHER;
- }
-
- return $cipher;
- }
-
- public static function splitPath($path) {
- $normalized = \OC\Files\Filesystem::normalizePath($path);
- return explode('/', $normalized);
- }
-
-}
-
diff --git a/apps/files_encryption/lib/hooks.php b/apps/files_encryption/lib/hooks.php
deleted file mode 100644
index 4a29ffaaedf..00000000000
--- a/apps/files_encryption/lib/hooks.php
+++ /dev/null
@@ -1,625 +0,0 @@
-<?php
-/**
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\Files_Encryption;
-
-/**
- * Class for hook specific logic
- */
-class Hooks {
-
- // file for which we want to rename the keys after the rename operation was successful
- private static $renamedFiles = array();
- // file for which we want to delete the keys after the delete operation was successful
- private static $deleteFiles = array();
- // file for which we want to delete the keys after the delete operation was successful
- private static $unmountedFiles = array();
-
- /**
- * Startup encryption backend upon user login
- * @note This method should never be called for users using client side encryption
- */
- public static function login($params) {
-
- if (\OCP\App::isEnabled('files_encryption') === false) {
- return true;
- }
-
-
- $l = new \OC_L10N('files_encryption');
-
- $view = new \OC\Files\View('/');
-
- // ensure filesystem is loaded
- if (!\OC\Files\Filesystem::$loaded) {
- \OC_Util::setupFS($params['uid']);
- }
-
- $privateKey = Keymanager::getPrivateKey($view, $params['uid']);
-
- // if no private key exists, check server configuration
- if (!$privateKey) {
- //check if all requirements are met
- if (!Helper::checkRequirements() || !Helper::checkConfiguration()) {
- $error_msg = $l->t("Missing requirements.");
- $hint = $l->t('Please make sure that OpenSSL together with the PHP extension is enabled and configured properly. For now, the encryption app has been disabled.');
- \OC_App::disable('files_encryption');
- \OCP\Util::writeLog('Encryption library', $error_msg . ' ' . $hint, \OCP\Util::ERROR);
- \OCP\Template::printErrorPage($error_msg, $hint);
- }
- }
-
- $util = new Util($view, $params['uid']);
-
- // setup user, if user not ready force relogin
- if (Helper::setupUser($util, $params['password']) === false) {
- return false;
- }
-
- $session = $util->initEncryption($params);
-
- // Check if first-run file migration has already been performed
- $ready = false;
- $migrationStatus = $util->getMigrationStatus();
- if ($migrationStatus === Util::MIGRATION_OPEN && $session !== false) {
- $ready = $util->beginMigration();
- } elseif ($migrationStatus === Util::MIGRATION_IN_PROGRESS) {
- // refuse login as long as the initial encryption is running
- sleep(5);
- \OCP\User::logout();
- return false;
- }
-
- $result = true;
-
- // If migration not yet done
- if ($ready) {
-
- // Encrypt existing user files
- try {
- $result = $util->encryptAll('/' . $params['uid'] . '/' . 'files');
- } catch (\Exception $ex) {
- \OCP\Util::writeLog('Encryption library', 'Initial encryption failed! Error: ' . $ex->getMessage(), \OCP\Util::FATAL);
- $result = false;
- }
-
- if ($result) {
- \OC_Log::write(
- 'Encryption library', 'Encryption of existing files belonging to "' . $params['uid'] . '" completed'
- , \OC_Log::INFO
- );
- // Register successful migration in DB
- $util->finishMigration();
- } else {
- \OCP\Util::writeLog('Encryption library', 'Initial encryption failed!', \OCP\Util::FATAL);
- $util->resetMigrationStatus();
- \OCP\User::logout();
- }
- }
-
- return $result;
- }
-
- /**
- * remove keys from session during logout
- */
- public static function logout() {
- $session = new Session(new \OC\Files\View());
- $session->removeKeys();
- }
-
- /**
- * setup encryption backend upon user created
- * @note This method should never be called for users using client side encryption
- */
- public static function postCreateUser($params) {
-
- if (\OCP\App::isEnabled('files_encryption')) {
- $view = new \OC\Files\View('/');
- $util = new Util($view, $params['uid']);
- Helper::setupUser($util, $params['password']);
- }
- }
-
- /**
- * cleanup encryption backend upon user deleted
- * @note This method should never be called for users using client side encryption
- */
- public static function postDeleteUser($params) {
-
- if (\OCP\App::isEnabled('files_encryption')) {
- Keymanager::deletePublicKey(new \OC\Files\View(), $params['uid']);
- }
- }
-
- /**
- * If the password can't be changed within ownCloud, than update the key password in advance.
- */
- public static function preSetPassphrase($params) {
- if (\OCP\App::isEnabled('files_encryption')) {
- if ( ! \OC_User::canUserChangePassword($params['uid']) ) {
- self::setPassphrase($params);
- }
- }
- }
-
- /**
- * Change a user's encryption passphrase
- * @param array $params keys: uid, password
- */
- public static function setPassphrase($params) {
- if (\OCP\App::isEnabled('files_encryption') === false) {
- return true;
- }
-
- // 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') {
-
- $view = new \OC\Files\View('/');
- $session = new Session($view);
-
- // Get existing decrypted private key
- $privateKey = $session->getPrivateKey();
-
- if ($params['uid'] === \OCP\User::getUser() && $privateKey) {
-
- // Encrypt private key with new user pwd as passphrase
- $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($privateKey, $params['password'], Helper::getCipher());
-
- // Save private key
- if ($encryptedPrivateKey) {
- Keymanager::setPrivateKey($encryptedPrivateKey, \OCP\User::getUser());
- } else {
- \OCP\Util::writeLog('files_encryption', 'Could not update users encryption password', \OCP\Util::ERROR);
- }
-
- // NOTE: Session does not need to be updated as the
- // private key has not changed, only the passphrase
- // 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'];
- $util = new Util($view, $user);
- $recoveryPassword = isset($params['recoveryPassword']) ? $params['recoveryPassword'] : null;
-
- // we generate new keys if...
- // ...we have a recovery password and the user enabled the recovery key
- // ...encryption was activated for the first time (no keys exists)
- // ...the user doesn't have any files
- if (($util->recoveryEnabledForUser() && $recoveryPassword)
- || !$util->userKeysExists()
- || !$view->file_exists($user . '/files')) {
-
- // backup old keys
- $util->backupAllKeys('recovery');
-
- $newUserPassword = $params['password'];
-
- // 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
- Keymanager::setPublicKey($keypair['publicKey'], $user);
-
- // Encrypt private key with new password
- $encryptedKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $newUserPassword, Helper::getCipher());
- if ($encryptedKey) {
- Keymanager::setPrivateKey($encryptedKey, $user);
-
- if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files
- $util = new Util($view, $user);
- $util->recoverUsersFiles($recoveryPassword);
- }
- } else {
- \OCP\Util::writeLog('files_encryption', 'Could not update users encryption password', \OCP\Util::ERROR);
- }
-
- \OC_FileProxy::$enabled = $proxyStatus;
- }
- }
- }
- }
-
- /**
- * after password reset we create a new key pair for the user
- *
- * @param array $params
- */
- public static function postPasswordReset($params) {
- $uid = $params['uid'];
- $password = $params['password'];
-
- $util = new Util(new \OC\Files\View(), $uid);
- $util->replaceUserKeys($password);
- }
-
- /*
- * check if files can be encrypted to every user.
- */
- /**
- * @param array $params
- */
- public static function preShared($params) {
-
- if (\OCP\App::isEnabled('files_encryption') === false) {
- return true;
- }
-
- $l = new \OC_L10N('files_encryption');
- $users = array();
- $view = new \OC\Files\View('/');
-
- 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;
- }
-
- $notConfigured = array();
- foreach ($users as $user) {
- if (!Keymanager::publicKeyExists($view, $user)) {
- $notConfigured[] = $user;
- }
- }
-
- if (count($notConfigured) > 0) {
- $params['run'] = false;
- $params['error'] = $l->t('Following users are not set up for encryption:') . ' ' . join(', ' , $notConfigured);
- }
-
- }
-
- /**
- * update share keys if a file was shared
- */
- public static function postShared($params) {
-
- if (\OCP\App::isEnabled('files_encryption') === false) {
- return true;
- }
-
- if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
-
- $path = \OC\Files\Filesystem::getPath($params['fileSource']);
-
- self::updateKeyfiles($path);
- }
- }
-
- /**
- * update keyfiles and share keys recursively
- *
- * @param string $path to the file/folder
- */
- private static function updateKeyfiles($path) {
- $view = new \OC\Files\View('/');
- $userId = \OCP\User::getUser();
- $session = new Session($view);
- $util = new Util($view, $userId);
- $sharingEnabled = \OCP\Share::isEnabled();
-
- $mountManager = \OC\Files\Filesystem::getMountManager();
- $mount = $mountManager->find('/' . $userId . '/files' . $path);
- $mountPoint = $mount->getMountPoint();
-
- // if a folder was shared, get a list of all (sub-)folders
- if ($view->is_dir('/' . $userId . '/files' . $path)) {
- $allFiles = $util->getAllFiles($path, $mountPoint);
- } else {
- $allFiles = array($path);
- }
-
- foreach ($allFiles as $path) {
- $usersSharing = $util->getSharingUsersArray($sharingEnabled, $path);
- $util->setSharedFileKeyfiles($session, $usersSharing, $path);
- }
- }
-
- /**
- * unshare file/folder from a user with whom you shared the file before
- */
- public static function postUnshare($params) {
-
- if (\OCP\App::isEnabled('files_encryption') === false) {
- return true;
- }
-
- if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
-
- $view = new \OC\Files\View('/');
- $userId = $params['uidOwner'];
- $userView = new \OC\Files\View('/' . $userId . '/files');
- $util = new Util($view, $userId);
- $path = $userView->getPath($params['fileSource']);
-
- // 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 || $params['shareType'] === \OCP\Share::SHARE_TYPE_REMOTE) {
- $userIds = array($util->getPublicShareKeyId());
- } else {
- $userIds = array($params['shareWith']);
- }
- }
-
- $mountManager = \OC\Files\Filesystem::getMountManager();
- $mount = $mountManager->find('/' . $userId . '/files' . $path);
- $mountPoint = $mount->getMountPoint();
-
- // if we unshare a folder we need a list of all (sub-)files
- if ($params['itemType'] === 'folder') {
- $allFiles = $util->getAllFiles($path, $mountPoint);
- } 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);
- $keyPath = Keymanager::getKeyPath($view, $util, $path);
-
- // delete share key
- Keymanager::delShareKey($view, $delUsers, $keyPath, $userId, $path);
- }
-
- }
- }
-
- /**
- * mark file as renamed so that we know the original source after the file was renamed
- * @param array $params with the old path and the new path
- */
- public static function preRename($params) {
- self::preRenameOrCopy($params, 'rename');
- }
-
- /**
- * mark file as copied so that we know the original source after the file was copied
- * @param array $params with the old path and the new path
- */
- public static function preCopy($params) {
- self::preRenameOrCopy($params, 'copy');
- }
-
- private static function preRenameOrCopy($params, $operation) {
- $user = \OCP\User::getUser();
- $view = new \OC\Files\View('/');
- $util = new Util($view, $user);
-
- // we only need to rename the keys if the rename happens on the same mountpoint
- // otherwise we perform a stream copy, so we get a new set of keys
- $oldPath = \OC\Files\Filesystem::normalizePath('/' . $user . '/files/' . $params['oldpath']);
- $newPath = \OC\Files\Filesystem::normalizePath('/' . $user . '/files/' . $params['newpath']);
- $mp1 = $view->getMountPoint($oldPath);
- $mp2 = $view->getMountPoint($newPath);
-
- $oldKeysPath = Keymanager::getKeyPath($view, $util, $params['oldpath']);
-
- if ($mp1 === $mp2) {
- self::$renamedFiles[$params['oldpath']] = array(
- 'operation' => $operation,
- 'oldKeysPath' => $oldKeysPath,
- );
- } elseif ($mp1 !== $oldPath . '/') {
- self::$renamedFiles[$params['oldpath']] = array(
- 'operation' => 'cleanup',
- 'oldKeysPath' => $oldKeysPath,
- );
- }
- }
-
- /**
- * after a file is renamed/copied, rename/copy its keyfile and share-keys also fix the file size and fix also the sharing
- *
- * @param array $params array with oldpath and newpath
- */
- public static function postRenameOrCopy($params) {
-
- if (\OCP\App::isEnabled('files_encryption') === false) {
- return true;
- }
-
- $view = new \OC\Files\View('/');
- $userId = \OCP\User::getUser();
- $util = new Util($view, $userId);
-
- if (isset(self::$renamedFiles[$params['oldpath']]['operation']) &&
- isset(self::$renamedFiles[$params['oldpath']]['oldKeysPath'])) {
- $operation = self::$renamedFiles[$params['oldpath']]['operation'];
- $oldKeysPath = self::$renamedFiles[$params['oldpath']]['oldKeysPath'];
- unset(self::$renamedFiles[$params['oldpath']]);
- if ($operation === 'cleanup') {
- return $view->unlink($oldKeysPath);
- }
- } else {
- \OCP\Util::writeLog('Encryption library', "can't get path and owner from the file before it was renamed", \OCP\Util::DEBUG);
- return false;
- }
-
- list($ownerNew, $pathNew) = $util->getUidAndFilename($params['newpath']);
-
- if ($util->isSystemWideMountPoint($pathNew)) {
- $newKeysPath = 'files_encryption/keys/' . $pathNew;
- } else {
- $newKeysPath = $ownerNew . '/files_encryption/keys/' . $pathNew;
- }
-
- // create key folders if it doesn't exists
- if (!$view->file_exists(dirname($newKeysPath))) {
- $view->mkdir(dirname($newKeysPath));
- }
-
- $view->$operation($oldKeysPath, $newKeysPath);
-
- // update sharing-keys
- self::updateKeyfiles($params['newpath']);
- }
-
- /**
- * set migration status and the init status back to '0' so that all new files get encrypted
- * if the app gets enabled again
- * @param array $params contains the app ID
- */
- public static function preDisable($params) {
- if ($params['app'] === 'files_encryption') {
-
- \OC::$server->getConfig()->deleteAppFromAllUsers('files_encryption');
-
- $session = new Session(new \OC\Files\View('/'));
- $session->setInitialized(Session::NOT_INITIALIZED);
- }
- }
-
- /**
- * set the init status to 'NOT_INITIALIZED' (0) if the app gets enabled
- * @param array $params contains the app ID
- */
- public static function postEnable($params) {
- if ($params['app'] === 'files_encryption') {
- $session = new Session(new \OC\Files\View('/'));
- $session->setInitialized(Session::NOT_INITIALIZED);
- }
- }
-
- /**
- * if the file was really deleted we remove the encryption keys
- * @param array $params
- * @return boolean|null
- */
- public static function postDelete($params) {
-
- $path = $params[\OC\Files\Filesystem::signal_param_path];
-
- if (!isset(self::$deleteFiles[$path])) {
- return true;
- }
-
- $deletedFile = self::$deleteFiles[$path];
- $keyPath = $deletedFile['keyPath'];
-
- // we don't need to remember the file any longer
- unset(self::$deleteFiles[$path]);
-
- $view = new \OC\Files\View('/');
-
- // return if the file still exists and wasn't deleted correctly
- if ($view->file_exists('/' . \OCP\User::getUser() . '/files/' . $path)) {
- return true;
- }
-
- // Delete keyfile & shareKey so it isn't orphaned
- $view->unlink($keyPath);
-
- }
-
- /**
- * remember the file which should be deleted and it's owner
- * @param array $params
- * @return boolean|null
- */
- public static function preDelete($params) {
- $view = new \OC\Files\View('/');
- $path = $params[\OC\Files\Filesystem::signal_param_path];
-
- // skip this method if the trash bin is enabled or if we delete a file
- // outside of /data/user/files
- if (\OCP\App::isEnabled('files_trashbin')) {
- return true;
- }
-
- $util = new Util($view, \OCP\USER::getUser());
-
- $keysPath = Keymanager::getKeyPath($view, $util, $path);
-
- self::$deleteFiles[$path] = array(
- 'keyPath' => $keysPath);
- }
-
- /**
- * unmount file from yourself
- * remember files/folders which get unmounted
- */
- public static function preUnmount($params) {
- $view = new \OC\Files\View('/');
- $user = \OCP\User::getUser();
- $path = $params[\OC\Files\Filesystem::signal_param_path];
-
- $util = new Util($view, $user);
- list($owner, $ownerPath) = $util->getUidAndFilename($path);
-
- $keysPath = Keymanager::getKeyPath($view, $util, $path);
-
- self::$unmountedFiles[$path] = array(
- 'keyPath' => $keysPath,
- 'owner' => $owner,
- 'ownerPath' => $ownerPath
- );
- }
-
- /**
- * unmount file from yourself
- */
- public static function postUnmount($params) {
-
- $path = $params[\OC\Files\Filesystem::signal_param_path];
- $user = \OCP\User::getUser();
-
- if (!isset(self::$unmountedFiles[$path])) {
- return true;
- }
-
- $umountedFile = self::$unmountedFiles[$path];
- $keyPath = $umountedFile['keyPath'];
- $owner = $umountedFile['owner'];
- $ownerPath = $umountedFile['ownerPath'];
-
- $view = new \OC\Files\View();
-
- // we don't need to remember the file any longer
- unset(self::$unmountedFiles[$path]);
-
- // check if the user still has access to the file, otherwise delete share key
- $sharingUsers = \OCP\Share::getUsersSharingFile($path, $user);
- if (!in_array($user, $sharingUsers['users'])) {
- Keymanager::delShareKey($view, array($user), $keyPath, $owner, $ownerPath);
- }
- }
-
-}
diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php
deleted file mode 100644
index 5e33372e9c6..00000000000
--- a/apps/files_encryption/lib/keymanager.php
+++ /dev/null
@@ -1,500 +0,0 @@
-<?php
-/**
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Florin Peter <github@florin-peter.de>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- * @author Sam Tuke <mail@samtuke.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\Files_Encryption;
-
-/**
- * Class to manage storage and retrieval of encryption keys
- * @note Where a method requires a view object, it's root must be '/'
- */
-class Keymanager {
-
- // base dir where all the file related keys are stored
- private static $keys_base_dir = '/files_encryption/keys/';
- private static $encryption_base_dir = '/files_encryption';
- private static $public_key_dir = '/files_encryption/public_keys';
-
- private static $key_cache = array(); // cache keys
-
- /**
- * read key from hard disk
- *
- * @param string $path to key
- * @param \OC\Files\View $view
- * @return string|bool either the key or false
- */
- private static function getKey($path, $view) {
-
- $key = false;
-
- if (isset(self::$key_cache[$path])) {
- $key = self::$key_cache[$path];
- } else {
-
- /** @var \OCP\Files\Storage $storage */
- list($storage, $internalPath) = $view->resolvePath($path);
-
- if ($storage->file_exists($internalPath)) {
- $key = $storage->file_get_contents($internalPath);
- self::$key_cache[$path] = $key;
- }
-
- }
-
- return $key;
- }
-
- /**
- * write key to disk
- *
- *
- * @param string $path path to key directory
- * @param string $name key name
- * @param string $key key
- * @param \OC\Files\View $view
- * @return bool
- */
- private static function setKey($path, $name, $key, $view) {
- self::keySetPreparation($view, $path);
-
- /** @var \OCP\Files\Storage $storage */
- $pathToKey = \OC\Files\Filesystem::normalizePath($path . '/' . $name);
- list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($pathToKey);
- $result = $storage->file_put_contents($internalPath, $key);
-
- if (is_int($result) && $result > 0) {
- self::$key_cache[$pathToKey] = $key;
- return true;
- }
-
- return false;
- }
-
- /**
- * retrieve the ENCRYPTED private key from a user
- *
- * @param \OC\Files\View $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\Files\View $view, $user) {
- $path = '/' . $user . '/' . 'files_encryption' . '/' . $user . '.privateKey';
- return self::getKey($path, $view);
- }
-
- /**
- * retrieve public key for a specified user
- * @param \OC\Files\View $view
- * @param string $userId
- * @return string public key or false
- */
- public static function getPublicKey(\OC\Files\View $view, $userId) {
- $path = self::$public_key_dir . '/' . $userId . '.publicKey';
- return self::getKey($path, $view);
- }
-
- public static function getPublicKeyPath() {
- return self::$public_key_dir;
- }
-
- /**
- * Retrieve a user's public and private key
- * @param \OC\Files\View $view
- * @param string $userId
- * @return array keys: privateKey, publicKey
- */
- public static function getUserKeys(\OC\Files\View $view, $userId) {
-
- return array(
- 'publicKey' => self::getPublicKey($view, $userId),
- 'privateKey' => self::getPrivateKey($view, $userId)
- );
-
- }
-
- /**
- * Retrieve public keys for given users
- * @param \OC\Files\View $view
- * @param array $userIds
- * @return array of public keys for the specified users
- */
- public static function getPublicKeys(\OC\Files\View $view, array $userIds) {
-
- $keys = array();
- foreach ($userIds as $userId) {
- $keys[$userId] = self::getPublicKey($view, $userId);
- }
-
- return $keys;
-
- }
-
- /**
- * store file encryption key
- *
- * @param \OC\Files\View $view
- * @param \OCA\Files_Encryption\Util $util
- * @param string $path relative path of the file, including filename
- * @param string $catfile keyfile content
- * @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 setFileKey(\OC\Files\View $view, $util, $path, $catfile) {
- $path = self::getKeyPath($view, $util, $path);
- return self::setKey($path, 'fileKey', $catfile, $view);
-
- }
-
- /**
- * get path to key folder for a given file
- *
- * @param \OC\Files\View $view relative to data directory
- * @param \OCA\Files_Encryption\Util $util
- * @param string $path path to the file, relative to the users file directory
- * @return string
- */
- public static function getKeyPath($view, $util, $path) {
-
- if ($view->is_dir('/' . \OCP\User::getUser() . '/' . $path)) {
- throw new Exception\EncryptionException('file was expected but directoy was given', Exception\EncryptionException::GENERIC);
- }
-
- list($owner, $filename) = $util->getUidAndFilename($path);
- $filename = Helper::stripPartialFileExtension($filename);
- $filePath_f = ltrim($filename, '/');
-
- // in case of system wide mount points the keys are stored directly in the data directory
- if ($util->isSystemWideMountPoint($filename)) {
- $keyPath = self::$keys_base_dir . $filePath_f . '/';
- } else {
- $keyPath = '/' . $owner . self::$keys_base_dir . $filePath_f . '/';
- }
-
- return $keyPath;
- }
-
- /**
- * get path to file key for a given file
- *
- * @param \OC\Files\View $view relative to data directory
- * @param \OCA\Files_Encryption\Util $util
- * @param string $path path to the file, relative to the users file directory
- * @return string
- */
- public static function getFileKeyPath($view, $util, $path) {
- $keyDir = self::getKeyPath($view, $util, $path);
- return $keyDir . 'fileKey';
- }
-
- /**
- * get path to share key for a given user
- *
- * @param \OC\Files\View $view relateive to data directory
- * @param \OCA\Files_Encryption\Util $util
- * @param string $path path to file relative to the users files directoy
- * @param string $uid user for whom we want the share-key path
- * @retrun string
- */
- public static function getShareKeyPath($view, $util, $path, $uid) {
- $keyDir = self::getKeyPath($view, $util, $path);
- return $keyDir . $uid . '.shareKey';
- }
-
- /**
- * delete key
- *
- * @param \OC\Files\View $view
- * @param string $path
- * @return boolean
- */
- private static function deleteKey($view, $path) {
- $normalizedPath = \OC\Files\Filesystem::normalizePath($path);
- $result = $view->unlink($normalizedPath);
-
- if ($result) {
- unset(self::$key_cache[$normalizedPath]);
- return true;
- }
-
- return false;
- }
-
- /**
- * delete public key from a given user
- *
- * @param \OC\Files\View $view
- * @param string $uid user
- * @return bool
- */
- public static function deletePublicKey($view, $uid) {
-
- $result = false;
-
- if (!\OCP\User::userExists($uid)) {
- $publicKey = self::$public_key_dir . '/' . $uid . '.publicKey';
- self::deleteKey($view, $publicKey);
- }
-
- return $result;
- }
-
- /**
- * check if public key for user exists
- *
- * @param \OC\Files\View $view
- * @param string $uid
- */
- public static function publicKeyExists($view, $uid) {
- return $view->file_exists(self::$public_key_dir . '/'. $uid . '.publicKey');
- }
-
-
-
- /**
- * retrieve keyfile for an encrypted file
- * @param \OC\Files\View $view
- * @param \OCA\Files_Encryption\Util $util
- * @param string|false $filePath
- * @return string file key or false
- * @note The keyfile returned is asymmetrically encrypted. Decryption
- * of the keyfile must be performed by client code
- */
- public static function getFileKey($view, $util, $filePath) {
- $path = self::getFileKeyPath($view, $util, $filePath);
- return self::getKey($path, $view);
- }
-
- /**
- * store private key from the user
- * @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, $user = '') {
-
- $user = $user === '' ? \OCP\User::getUser() : $user;
- $path = '/' . $user . '/files_encryption';
- $header = Crypt::generateHeader();
-
- return self::setKey($path, $user . '.privateKey', $header . $key, new \OC\Files\View());
-
- }
-
- /**
- * check if recovery key exists
- *
- * @param \OC\Files\View $view
- * @return bool
- */
- public static function recoveryKeyExists($view) {
-
- $result = false;
-
- $recoveryKeyId = Helper::getRecoveryKeyId();
- if ($recoveryKeyId) {
- $result = ($view->file_exists(self::$public_key_dir . '/' . $recoveryKeyId . ".publicKey")
- && $view->file_exists(self::$encryption_base_dir . '/' . $recoveryKeyId . ".privateKey"));
- }
-
- return $result;
- }
-
- public static function publicShareKeyExists($view) {
- $result = false;
-
- $publicShareKeyId = Helper::getPublicShareKeyId();
- if ($publicShareKeyId) {
- $result = ($view->file_exists(self::$public_key_dir . '/' . $publicShareKeyId . ".publicKey")
- && $view->file_exists(self::$encryption_base_dir . '/' . $publicShareKeyId . ".privateKey"));
-
- }
-
- return $result;
- }
-
- /**
- * store public key from the user
- * @param string $key
- * @param string $user
- *
- * @return bool
- */
- public static function setPublicKey($key, $user = '') {
-
- $user = $user === '' ? \OCP\User::getUser() : $user;
-
- return self::setKey(self::$public_key_dir, $user . '.publicKey', $key, new \OC\Files\View('/'));
- }
-
- /**
- * write private system key (recovery and public share key) to disk
- *
- * @param string $key encrypted key
- * @param string $keyName name of the key
- * @return boolean
- */
- public static function setPrivateSystemKey($key, $keyName) {
-
- $keyName = $keyName . '.privateKey';
- $header = Crypt::generateHeader();
-
- return self::setKey(self::$encryption_base_dir, $keyName,$header . $key, new \OC\Files\View());
- }
-
- /**
- * read private system key (recovery and public share key) from disk
- *
- * @param string $keyName name of the key
- * @return string|boolean private system key or false
- */
- public static function getPrivateSystemKey($keyName) {
- $path = $keyName . '.privateKey';
- return self::getKey($path, new \OC\Files\View(self::$encryption_base_dir));
- }
-
- /**
- * store multiple share keys for a single file
- * @param \OC\Files\View $view
- * @param \OCA\Files_Encryption\Util $util
- * @param string $path
- * @param array $shareKeys
- * @return bool
- */
- public static function setShareKeys($view, $util, $path, array $shareKeys) {
-
- // in case of system wide mount points the keys are stored directly in the data directory
- $basePath = Keymanager::getKeyPath($view, $util, $path);
-
- self::keySetPreparation($view, $basePath);
-
- $result = true;
-
- foreach ($shareKeys as $userId => $shareKey) {
- if (!self::setKey($basePath, $userId . '.shareKey', $shareKey, $view)) {
- // If any of the keys are not set, flag false
- $result = false;
- }
- }
-
- // Returns false if any of the keys weren't set
- return $result;
- }
-
- /**
- * retrieve shareKey for an encrypted file
- * @param \OC\Files\View $view
- * @param string $userId
- * @param \OCA\Files_Encryption\Util $util
- * @param string $filePath
- * @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 getShareKey($view, $userId, $util, $filePath) {
- $path = self::getShareKeyPath($view, $util, $filePath, $userId);
- return self::getKey($path, $view);
- }
-
- /**
- * Delete a single user's shareKey for a single file
- *
- * @param \OC\Files\View $view relative to data/
- * @param array $userIds list of users we want to remove
- * @param string $keyPath
- * @param string $owner the owner of the file
- * @param string $ownerPath the owners name of the file for which we want to remove the users relative to data/user/files
- */
- public static function delShareKey($view, $userIds, $keysPath, $owner, $ownerPath) {
-
- $key = array_search($owner, $userIds, true);
- if ($key !== false && $view->file_exists('/' . $owner . '/files/' . $ownerPath)) {
- unset($userIds[$key]);
- }
-
- self::recursiveDelShareKeys($keysPath, $userIds, $view);
-
- }
-
- /**
- * recursively delete share keys from given users
- *
- * @param string $dir directory
- * @param array $userIds user ids for which the share keys should be deleted
- * @param \OC\Files\View $view view relative to data/
- */
- private static function recursiveDelShareKeys($dir, $userIds, $view) {
-
- $dirContent = $view->opendir($dir);
-
- if (is_resource($dirContent)) {
- while (($file = readdir($dirContent)) !== false) {
- if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
- if ($view->is_dir($dir . '/' . $file)) {
- self::recursiveDelShareKeys($dir . '/' . $file, $userIds, $view);
- } else {
- foreach ($userIds as $userId) {
- if ($userId . '.shareKey' === $file) {
- \OCP\Util::writeLog('files_encryption', 'recursiveDelShareKey: delete share key: ' . $file, \OCP\Util::DEBUG);
- self::deleteKey($view, $dir . '/' . $file);
- }
- }
- }
- }
- }
- closedir($dirContent);
- }
- }
-
- /**
- * Make preparations to vars and filesystem for saving a keyfile
- *
- * @param \OC\Files\View $view
- * @param string $path relatvie to the views root
- * @param string $basePath
- */
- protected static function keySetPreparation($view, $path) {
- // If the file resides within a subdirectory, create it
- if (!$view->file_exists($path)) {
- $sub_dirs = explode('/', $path);
- $dir = '';
- foreach ($sub_dirs as $sub_dir) {
- $dir .= '/' . $sub_dir;
- if (!$view->is_dir($dir)) {
- $view->mkdir($dir);
- }
- }
- }
- }
-
-}
diff --git a/apps/files_encryption/lib/migration.php b/apps/files_encryption/lib/migration.php
deleted file mode 100644
index 3f8ca9f4e23..00000000000
--- a/apps/files_encryption/lib/migration.php
+++ /dev/null
@@ -1,302 +0,0 @@
-<?php
-/**
- * @author Arthur Schiwon <blizzz@owncloud.com>
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\Files_Encryption;
-
-
-class Migration {
-
- /**
- * @var \OC\Files\View
- */
- private $view;
- private $public_share_key_id;
- private $recovery_key_id;
-
- public function __construct() {
- $this->view = new \OC\Files\View();
- $this->view->getUpdater()->disable();
- $this->public_share_key_id = Helper::getPublicShareKeyId();
- $this->recovery_key_id = Helper::getRecoveryKeyId();
- }
-
- public function reorganizeFolderStructure() {
- $this->reorganizeSystemFolderStructure();
-
- $limit = 500;
- $offset = 0;
- do {
- $users = \OCP\User::getUsers('', $limit, $offset);
- foreach ($users as $user) {
- $this->reorganizeFolderStructureForUser($user);
- }
- $offset += $limit;
- } while (count($users) >= $limit);
- }
-
- public function reorganizeSystemFolderStructure() {
-
- $this->createPathForKeys('/files_encryption');
-
- // backup system wide folders
- $this->backupSystemWideKeys();
-
- // rename public keys
- $this->renamePublicKeys();
-
- // rename system wide mount point
- $this->renameFileKeys('', '/files_encryption/keyfiles');
-
- // rename system private keys
- $this->renameSystemPrivateKeys();
-
- // delete old system wide folders
- $this->view->deleteAll('/public-keys');
- $this->view->deleteAll('/owncloud_private_key');
- $this->view->deleteAll('/files_encryption/share-keys');
- $this->view->deleteAll('/files_encryption/keyfiles');
- $storage = $this->view->getMount('')->getStorage();
- $storage->getScanner()->scan('files_encryption');
- $storage->getCache()->remove('owncloud_private_key');
- $storage->getCache()->remove('public-keys');
- }
-
-
- public function reorganizeFolderStructureForUser($user) {
- // backup all keys
- \OC_Util::tearDownFS();
- \OC_Util::setupFS($user);
- if ($this->backupUserKeys($user)) {
- // create new 'key' folder
- $this->view->mkdir($user . '/files_encryption/keys');
- // rename users private key
- $this->renameUsersPrivateKey($user);
- // rename file keys
- $path = $user . '/files_encryption/keyfiles';
- $this->renameFileKeys($user, $path);
- $trashPath = $user . '/files_trashbin/keyfiles';
- if (\OC_App::isEnabled('files_trashbin') && $this->view->is_dir($trashPath)) {
- $this->renameFileKeys($user, $trashPath, true);
- $this->view->deleteAll($trashPath);
- $this->view->deleteAll($user . '/files_trashbin/share-keys');
- }
- // delete old folders
- $this->deleteOldKeys($user);
- $this->view->getMount('/' . $user)->getStorage()->getScanner()->scan('files_encryption');
- }
- }
-
- private function backupSystemWideKeys() {
- $backupDir = 'encryption_migration_backup_' . date("Y-m-d_H-i-s");
- $this->view->mkdir($backupDir);
- $this->view->copy('owncloud_private_key', $backupDir . '/owncloud_private_key');
- $this->view->copy('public-keys', $backupDir . '/public-keys');
- $this->view->copy('files_encryption', $backupDir . '/files_encryption');
- }
-
- private function backupUserKeys($user) {
- $encryptionDir = $user . '/files_encryption';
- if ($this->view->is_dir($encryptionDir)) {
- $backupDir = $user . '/encryption_migration_backup_' . date("Y-m-d_H-i-s");
- $this->view->mkdir($backupDir);
- $this->view->copy($encryptionDir, $backupDir);
- return true;
- }
- return false;
- }
-
- private function renamePublicKeys() {
- $dh = $this->view->opendir('public-keys');
-
- $this->createPathForKeys('files_encryption/public_keys');
-
- if (is_resource($dh)) {
- while (($oldPublicKey = readdir($dh)) !== false) {
- if (!\OC\Files\Filesystem::isIgnoredDir($oldPublicKey)) {
- $newPublicKey = substr($oldPublicKey, 0, strlen($oldPublicKey) - strlen('.public.key')) . '.publicKey';
- $this->view->rename('public-keys/' . $oldPublicKey, 'files_encryption/public_keys/' . $newPublicKey);
- }
- }
- closedir($dh);
- }
- }
-
- private function renameSystemPrivateKeys() {
- $dh = $this->view->opendir('owncloud_private_key');
-
- if (is_resource($dh)) {
- while (($oldPrivateKey = readdir($dh)) !== false) {
- if (!\OC\Files\Filesystem::isIgnoredDir($oldPrivateKey)) {
- $newPrivateKey = substr($oldPrivateKey, 0, strlen($oldPrivateKey) - strlen('.private.key')) . '.privateKey';
- $this->view->rename('owncloud_private_key/' . $oldPrivateKey, 'files_encryption/' . $newPrivateKey);
- }
- }
- closedir($dh);
- }
- }
-
- private function renameUsersPrivateKey($user) {
- $oldPrivateKey = $user . '/files_encryption/' . $user . '.private.key';
- $newPrivateKey = substr($oldPrivateKey, 0, strlen($oldPrivateKey) - strlen('.private.key')) . '.privateKey';
-
- $this->view->rename($oldPrivateKey, $newPrivateKey);
- }
-
- private function getFileName($file, $trash) {
-
- $extLength = strlen('.key');
-
- if ($trash) {
- $parts = explode('.', $file);
- if ($parts[count($parts) - 1] !== 'key') {
- $extLength = $extLength + strlen('.' . $parts[count($parts) - 1]);
- }
- }
-
- $filename = substr($file, 0, strlen($file) - $extLength);
-
- return $filename;
- }
-
- private function getExtension($file, $trash) {
-
- $extension = '';
-
- if ($trash) {
- $parts = explode('.', $file);
- if ($parts[count($parts) - 1] !== 'key') {
- $extension = '.' . $parts[count($parts) - 1];
- }
- }
-
- return $extension;
- }
-
- private function getFilePath($path, $user, $trash) {
- $offset = $trash ? strlen($user . '/files_trashbin/keyfiles') : strlen($user . '/files_encryption/keyfiles');
- return substr($path, $offset);
- }
-
- private function getTargetDir($user, $filePath, $filename, $extension, $trash) {
- if ($trash) {
- $targetDir = $user . '/files_trashbin/keys/' . $filePath . '/' . $filename . $extension;
- } else {
- $targetDir = $user . '/files_encryption/keys/' . $filePath . '/' . $filename . $extension;
- }
-
- return $targetDir;
- }
-
- private function renameFileKeys($user, $path, $trash = false) {
-
- $dh = $this->view->opendir($path);
-
- if (is_resource($dh)) {
- while (($file = readdir($dh)) !== false) {
- if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
- if ($this->view->is_dir($path . '/' . $file)) {
- $this->renameFileKeys($user, $path . '/' . $file, $trash);
- } else {
- $filename = $this->getFileName($file, $trash);
- $filePath = $this->getFilePath($path, $user, $trash);
- $extension = $this->getExtension($file, $trash);
- $targetDir = $this->getTargetDir($user, $filePath, $filename, $extension, $trash);
- $this->createPathForKeys($targetDir);
- $this->view->rename($path . '/' . $file, $targetDir . '/fileKey');
- $this->renameShareKeys($user, $filePath, $filename, $targetDir, $trash);
- }
- }
- }
- closedir($dh);
- }
- }
-
- private function getOldShareKeyPath($user, $filePath, $trash) {
- if ($trash) {
- $oldShareKeyPath = $user . '/files_trashbin/share-keys/' . $filePath;
- } else {
- $oldShareKeyPath = $user . '/files_encryption/share-keys/' . $filePath;
- }
-
- return $oldShareKeyPath;
- }
-
- private function getUidFromShareKey($file, $filename, $trash) {
- $extLength = strlen('.shareKey');
- if ($trash) {
- $parts = explode('.', $file);
- if ($parts[count($parts) - 1] !== 'shareKey') {
- $extLength = $extLength + strlen('.' . $parts[count($parts) - 1]);
- }
- }
-
- $uid = substr($file, strlen($filename) + 1, $extLength * -1);
-
- return $uid;
- }
-
- private function renameShareKeys($user, $filePath, $filename, $target, $trash) {
- $oldShareKeyPath = $this->getOldShareKeyPath($user, $filePath, $trash);
- $dh = $this->view->opendir($oldShareKeyPath);
-
- if (is_resource($dh)) {
- while (($file = readdir($dh)) !== false) {
- if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
- if ($this->view->is_dir($oldShareKeyPath . '/' . $file)) {
- continue;
- } else {
- if (substr($file, 0, strlen($filename) + 1) === $filename . '.') {
-
- $uid = $this->getUidFromShareKey($file, $filename, $trash);
- $this->view->rename($oldShareKeyPath . '/' . $file, $target . '/' . $uid . '.shareKey');
- }
- }
-
- }
- }
- closedir($dh);
- }
- }
-
- private function deleteOldKeys($user) {
- $this->view->deleteAll($user . '/files_encryption/keyfiles');
- $this->view->deleteAll($user . '/files_encryption/share-keys');
- }
-
- private function createPathForKeys($path) {
- if (!$this->view->file_exists($path)) {
- $sub_dirs = explode('/', $path);
- $dir = '';
- foreach ($sub_dirs as $sub_dir) {
- $dir .= '/' . $sub_dir;
- if (!$this->view->is_dir($dir)) {
- $this->view->mkdir($dir);
- }
- }
- }
- }
-}
diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php
deleted file mode 100644
index b452c0d4e27..00000000000
--- a/apps/files_encryption/lib/proxy.php
+++ /dev/null
@@ -1,401 +0,0 @@
-<?php
-/**
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Florin Peter <github@florin-peter.de>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- * @author Sam Tuke <mail@samtuke.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-/**
- * Encryption proxy which handles filesystem operations before and after
- * execution and encrypts, and handles keyfiles accordingly. Used for
- * webui.
- */
-
-namespace OCA\Files_Encryption;
-
-/**
- * Class Proxy
- * @package OCA\Files_Encryption
- */
-class Proxy extends \OC_FileProxy {
-
- private static $unencryptedSizes = array(); // remember unencrypted size
- private static $fopenMode = array(); // remember the fopen mode
- private static $enableEncryption = false; // Enable encryption for the given path
-
-
- /**
- * check if path is excluded from encryption
- *
- * @param string $path relative to data/
- * @return boolean
- */
- protected function isExcludedPath($path) {
-
- $view = new \OC\Files\View();
-
- $normalizedPath = \OC\Files\Filesystem::normalizePath($path);
-
- $parts = explode('/', $normalizedPath);
-
- // we only encrypt/decrypt files in the files and files_versions folder
- if (sizeof($parts) < 3) {
- /**
- * Less then 3 parts means, we can't match:
- * - /{$uid}/files/* nor
- * - /{$uid}/files_versions/*
- * So this is not a path we are looking for.
- */
- return true;
- }
- if(
- !($parts[2] === 'files' && \OCP\User::userExists($parts[1])) &&
- !($parts[2] === 'files_versions' && \OCP\User::userExists($parts[1]))) {
-
- return true;
- }
-
- if (!$view->file_exists($normalizedPath)) {
- $normalizedPath = dirname($normalizedPath);
- }
-
- // we don't encrypt server-to-server shares
- list($storage, ) = \OC\Files\Filesystem::resolvePath($normalizedPath);
- /**
- * @var \OCP\Files\Storage $storage
- */
- if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Check if a file requires encryption
- * @param string $path
- * @param string $mode type of access
- * @return bool
- *
- * Tests if server side encryption is enabled, and if we should call the
- * crypt stream wrapper for the given file
- */
- private function shouldEncrypt($path, $mode = 'w') {
-
- // don't call the crypt stream wrapper, if...
- if (
- Crypt::mode() !== 'server' // we are not in server-side-encryption mode
- || $this->isExcludedPath($path) // if path is excluded from encryption
- || substr($path, 0, 8) === 'crypt://' // we are already in crypt mode
- ) {
- return false;
- }
-
- $userId = Helper::getUser($path);
- $view = new \OC\Files\View('');
- $util = new Util($view, $userId);
-
- // for write operation we always encrypt the files, for read operations
- // we check if the existing file is encrypted or not decide if it needs to
- // decrypt it.
- if (($mode !== 'r' && $mode !== 'rb') || $util->isEncryptedPath($path)) {
- return true;
- }
-
- return false;
- }
-
- /**
- * @param string $path
- * @param string $data
- * @return bool
- */
- public function preFile_put_contents($path, &$data) {
-
- if ($this->shouldEncrypt($path)) {
-
- if (!is_resource($data)) {
-
- // get root view
- $view = new \OC\Files\View('/');
-
- // get relative path
- $relativePath = Helper::stripUserFilesPath($path);
-
- if (!isset($relativePath)) {
- return true;
- }
-
- // create random cache folder
- $cacheFolder = rand();
- $path_slices = explode('/', \OC\Files\Filesystem::normalizePath($path));
- $path_slices[2] = "cache/".$cacheFolder;
- $tmpPath = implode('/', $path_slices);
-
- $handle = fopen('crypt://' . $tmpPath, '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($tmpPath);
-
- // store new unenecrypted size so that it can be updated
- // in the post proxy
- $tmpFileInfo = $view->getFileInfo($tmpPath);
- if ( isset($tmpFileInfo['unencrypted_size']) ) {
- self::$unencryptedSizes[\OC\Files\Filesystem::normalizePath($path)] = $tmpFileInfo['unencrypted_size'];
- }
-
- // remove our temp file
- $view->deleteAll('/' . \OCP\User::getUser() . '/cache/' . $cacheFolder);
-
- // re-enable proxy - our work is done
- \OC_FileProxy::$enabled = $proxyStatus;
- } else {
- return false;
- }
- }
- }
-
- return true;
-
- }
-
- /**
- * update file cache with the new unencrypted size after file was written
- * @param string $path
- * @param mixed $result
- * @return mixed
- */
- public function postFile_put_contents($path, $result) {
- $normalizedPath = \OC\Files\Filesystem::normalizePath($path);
- if ( isset(self::$unencryptedSizes[$normalizedPath]) ) {
- $view = new \OC\Files\View('/');
- $view->putFileInfo($normalizedPath,
- array('encrypted' => true, 'unencrypted_size' => self::$unencryptedSizes[$normalizedPath]));
- unset(self::$unencryptedSizes[$normalizedPath]);
- }
-
- return $result;
- }
-
- /**
- * @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) {
-
- $plainData = null;
-
- // If data is a catfile
- if (
- Crypt::mode() === 'server'
- && $this->shouldEncrypt($path)
- && Crypt::isCatfileContent($data)
- ) {
-
- $handle = fopen('crypt://' . $path, 'r');
-
- if (is_resource($handle)) {
- while (($plainDataChunk = fgets($handle, 8192)) !== false) {
- $plainData .= $plainDataChunk;
- }
- }
-
- }
-
- if (!isset($plainData)) {
-
- $plainData = $data;
-
- }
-
- return $plainData;
-
- }
-
- /**
- * remember initial fopen mode because sometimes it gets changed during the request
- * @param string $path path
- * @param string $mode type of access
- */
- public function preFopen($path, $mode) {
-
- self::$fopenMode[$path] = $mode;
- self::$enableEncryption = $this->shouldEncrypt($path, $mode);
-
- }
-
-
- /**
- * @param string $path
- * @param resource $result
- * @return resource
- */
- public function postFopen($path, $result) {
-
- $path = \OC\Files\Filesystem::normalizePath($path);
-
- if (!$result || self::$enableEncryption === false) {
-
- return $result;
-
- }
-
- // if we remember the mode from the pre proxy we re-use it
- // otherwise we fall back to stream_get_meta_data()
- if (isset(self::$fopenMode[$path])) {
- $mode = self::$fopenMode[$path];
- unset(self::$fopenMode[$path]);
- } else {
- $meta = stream_get_meta_data($result);
- $mode = $meta['mode'];
- }
-
- // Close the original encrypted file
- fclose($result);
-
- // Open the file using the crypto stream wrapper
- // protocol and let it do the decryption work instead
- $result = fopen('crypt://' . $path, $mode);
-
- return $result;
-
- }
-
- /**
- * @param string $path
- * @param array $data
- * @return array
- */
- public function postGetFileInfo($path, $data) {
-
- // if path is a folder do nothing
- if (\OCP\App::isEnabled('files_encryption') && $data !== false && 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'], $data);
-
- // Re-enable the proxy
- \OC_FileProxy::$enabled = $proxyStatus;
- }
-
- return $data;
- }
-
- /**
- * @param string $path
- * @param int $size
- * @return int|bool
- */
- public function postFileSize($path, $size, $fileInfo = null) {
-
- $view = new \OC\Files\View('/');
-
- $userId = Helper::getUser($path);
- $util = new Util($view, $userId);
-
- // if encryption is no longer enabled or if the files aren't migrated yet
- // we return the default file size
- if(!\OCP\App::isEnabled('files_encryption') ||
- $util->getMigrationStatus() !== Util::MIGRATION_COMPLETED) {
- return $size;
- }
-
- // if path is a folder do nothing
- if ($view->is_dir($path)) {
- $proxyState = \OC_FileProxy::$enabled;
- \OC_FileProxy::$enabled = false;
- $fileInfo = $view->getFileInfo($path);
- \OC_FileProxy::$enabled = $proxyState;
- if (isset($fileInfo['unencrypted_size']) && $fileInfo['unencrypted_size'] > 0) {
- return $fileInfo['unencrypted_size'];
- }
- return $size;
- }
-
- // get relative path
- $relativePath = Helper::stripUserFilesPath($path);
-
- // if path is empty we cannot resolve anything
- if (empty($relativePath)) {
- return $size;
- }
-
- // get file info from database/cache
- if (empty($fileInfo)) {
- $proxyState = \OC_FileProxy::$enabled;
- \OC_FileProxy::$enabled = false;
- $fileInfo = $view->getFileInfo($path);
- \OC_FileProxy::$enabled = $proxyState;
- }
-
- // if file is encrypted return real file size
- if (isset($fileInfo['encrypted']) && $fileInfo['encrypted'] === true) {
- // try to fix unencrypted file size if it doesn't look plausible
- if ((int)$fileInfo['size'] > 0 && (int)$fileInfo['unencrypted_size'] === 0 ) {
- $fixSize = $util->getFileSize($path);
- $fileInfo['unencrypted_size'] = $fixSize;
- // put file info if not .part file
- if (!Helper::isPartialFilePath($relativePath)) {
- $view->putFileInfo($path, array('unencrypted_size' => $fixSize));
- }
- }
- $size = $fileInfo['unencrypted_size'];
- } else {
-
- $fileInfoUpdates = array();
-
- $fixSize = $util->getFileSize($path);
- if ($fixSize > 0) {
- $size = $fixSize;
-
- $fileInfoUpdates['encrypted'] = true;
- $fileInfoUpdates['unencrypted_size'] = $size;
-
- // put file info if not .part file
- if (!Helper::isPartialFilePath($relativePath)) {
- $view->putFileInfo($path, $fileInfoUpdates);
- }
- }
-
- }
- return $size;
- }
-
-}
diff --git a/apps/files_encryption/lib/session.php b/apps/files_encryption/lib/session.php
deleted file mode 100644
index 10e4c061b30..00000000000
--- a/apps/files_encryption/lib/session.php
+++ /dev/null
@@ -1,203 +0,0 @@
-<?php
-/**
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Florin Peter <github@florin-peter.de>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- * @author Sam Tuke <mail@samtuke.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\Files_Encryption;
-
-/**
- * Class for handling encryption related session data
- */
-
-class Session {
-
- private $view;
- private static $publicShareKey = false;
-
- const NOT_INITIALIZED = '0';
- const INIT_EXECUTED = '1';
- const INIT_SUCCESSFUL = '2';
-
-
- /**
- * if session is started, check if ownCloud key pair is set up, if not create it
- * @param \OC\Files\View $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('files_encryption')) {
-
- $this->view->mkdir('files_encryption');
-
- }
-
- $appConfig = \OC::$server->getAppConfig();
-
- $publicShareKeyId = Helper::getPublicShareKeyId();
-
- if ($publicShareKeyId === false) {
- $publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8);
- $appConfig->setValue('files_encryption', 'publicShareKeyId', $publicShareKeyId);
- }
-
- if (!Keymanager::publicShareKeyExists($view)) {
-
- $keypair = Crypt::createKeypair();
-
-
- // Save public key
- Keymanager::setPublicKey($keypair['publicKey'], $publicShareKeyId);
-
- // Encrypt private key empty passphrase
- $cipher = Helper::getCipher();
- $encryptedKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], '', $cipher);
- if ($encryptedKey) {
- Keymanager::setPrivateSystemKey($encryptedKey, $publicShareKeyId);
- } else {
- \OCP\Util::writeLog('files_encryption', 'Could not create public share keys', \OCP\Util::ERROR);
- }
-
- }
-
- if (Helper::isPublicAccess() && !self::getPublicSharePrivateKey()) {
- // Disable encryption proxy to prevent recursive calls
- $proxyStatus = \OC_FileProxy::$enabled;
- \OC_FileProxy::$enabled = false;
-
- $encryptedKey = Keymanager::getPrivateSystemKey($publicShareKeyId);
- $privateKey = Crypt::decryptPrivateKey($encryptedKey, '');
- self::setPublicSharePrivateKey($privateKey);
-
- \OC_FileProxy::$enabled = $proxyStatus;
- }
- }
-
- /**
- * Sets user private key to session
- * @param string $privateKey
- * @return bool
- *
- * @note this should only be set on login
- */
- public function setPrivateKey($privateKey) {
-
- \OC::$server->getSession()->set('privateKey', $privateKey);
-
- return true;
-
- }
-
- /**
- * remove keys from session
- */
- public function removeKeys() {
- \OC::$server->getSession()->remove('publicSharePrivateKey');
- \OC::$server->getSession()->remove('privateKey');
- }
-
- /**
- * Sets status of encryption app
- * @param string $init INIT_SUCCESSFUL, INIT_EXECUTED, NOT_INITIALIZED
- * @return bool
- *
- * @note this doesn not indicate of the init was successful, we just remeber the try!
- */
- public function setInitialized($init) {
-
- \OC::$server->getSession()->set('encryptionInitialized', $init);
-
- return true;
-
- }
-
- /**
- * remove encryption keys and init status from session
- */
- public function closeSession() {
- \OC::$server->getSession()->remove('encryptionInitialized');
- \OC::$server->getSession()->remove('privateKey');
- }
-
-
- /**
- * Gets status if we already tried to initialize the encryption app
- * @return string init status INIT_SUCCESSFUL, INIT_EXECUTED, NOT_INITIALIZED
- *
- * @note this doesn not indicate of the init was successful, we just remeber the try!
- */
- public function getInitialized() {
- if (!is_null(\OC::$server->getSession()->get('encryptionInitialized'))) {
- return \OC::$server->getSession()->get('encryptionInitialized');
- } else if (Helper::isPublicAccess() && self::getPublicSharePrivateKey()) {
- return self::INIT_SUCCESSFUL;
- } else {
- return self::NOT_INITIALIZED;
- }
- }
-
- /**
- * Gets user or public share private key from session
- * @return string $privateKey The user's plaintext private key
- *
- */
- public function getPrivateKey() {
- // return the public share private key if this is a public access
- if (Helper::isPublicAccess()) {
- return self::getPublicSharePrivateKey();
- } else {
- if (!is_null(\OC::$server->getSession()->get('privateKey'))) {
- return \OC::$server->getSession()->get('privateKey');
- } else {
- return false;
- }
- }
- }
-
- /**
- * Sets public user private key to session
- * @param string $privateKey
- * @return bool
- */
- private static function setPublicSharePrivateKey($privateKey) {
- self::$publicShareKey = $privateKey;
- return true;
- }
-
- /**
- * Gets public share private key from session
- * @return string $privateKey
- *
- */
- private static function getPublicSharePrivateKey() {
- return self::$publicShareKey;
- }
-
-}
diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php
deleted file mode 100644
index 4cbf9e4a4b7..00000000000
--- a/apps/files_encryption/lib/stream.php
+++ /dev/null
@@ -1,700 +0,0 @@
-<?php
-/**
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Florin Peter <github@florin-peter.de>
- * @author jknockaert <jasper@knockaert.nl>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- * @author Sam Tuke <mail@samtuke.com>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-/**
- * transparently encrypted filestream
- *
- * you can use it as wrapper around an existing stream by setting CryptStream::$sourceStreams['foo']=array('path'=>$path,'stream'=>$stream)
- * and then fopen('crypt://streams/foo');
- */
-
-namespace OCA\Files_Encryption;
-
-use OCA\Files_Encryption\Exception\EncryptionException;
-
-/**
- * Provides 'crypt://' stream wrapper protocol.
- * @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
- * 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
- * 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 {
-
- const PADDING_CHAR = '-';
-
- private $plainKey;
- private $encKeyfiles;
- private $rawPath; // The raw path relative to the data dir
- private $relPath; // rel path to users file dir
- private $userId;
- private $keyId;
- private $handle; // Resource returned by fopen
- private $meta = array(); // Header / meta for source stream
- private $cache; // Current block unencrypted
- private $position; // Current pointer position in the unencrypted stream
- private $writeFlag; // Flag to write current block when leaving it
- private $size;
- private $headerSize = 0; // Size of header
- private $unencryptedSize;
- private $publicKey;
- private $encKeyfile;
- private $newFile; // helper var, we only need to write the keyfile for new files
- private $isLocalTmpFile = false; // do we operate on a local tmp file
- private $localTmpFile; // path of local tmp file
- private $containHeader = false; // the file contain a header
- private $cipher; // cipher used for encryption/decryption
- /** @var \OCA\Files_Encryption\Util */
- private $util;
-
- /**
- * @var \OC\Files\View
- */
- private $rootView; // a fsview object set to '/'
-
- /**
- * @var \OCA\Files_Encryption\Session
- */
- private $session;
- private $privateKey;
-
- /**
- * @param string $path raw path relative to data/
- * @param string $mode
- * @param int $options
- * @param string $opened_path
- * @return bool
- * @throw \OCA\Files_Encryption\Exception\EncryptionException
- */
- public function stream_open($path, $mode, $options, &$opened_path) {
-
- // read default cipher from config
- $this->cipher = Helper::getCipher();
-
- // assume that the file already exist before we decide it finally in getKey()
- $this->newFile = false;
-
- $this->rootView = new \OC\Files\View('/');
-
- $this->session = new Session($this->rootView);
-
- $this->privateKey = $this->session->getPrivateKey();
- if ($this->privateKey === false) {
- throw new EncryptionException('Session does not contain a private key, maybe your login password changed?',
- EncryptionException::PRIVATE_KEY_MISSING);
- }
-
- $normalizedPath = \OC\Files\Filesystem::normalizePath(str_replace('crypt://', '', $path));
- $originalFile = Helper::getPathFromTmpFile($normalizedPath);
- if ($originalFile) {
- $this->rawPath = $originalFile;
- $this->isLocalTmpFile = true;
- $this->localTmpFile = $normalizedPath;
- } else {
- $this->rawPath = $normalizedPath;
- }
-
- $this->util = new Util($this->rootView, Helper::getUser($this->rawPath));
-
- // get the key ID which we want to use, can be the users key or the
- // public share key
- $this->keyId = $this->util->getKeyId();
-
- $fileType = Helper::detectFileType($this->rawPath);
-
- switch ($fileType) {
- case Util::FILE_TYPE_FILE:
- $this->relPath = Helper::stripUserFilesPath($this->rawPath);
- $user = \OC::$server->getUserSession()->getUser();
- $this->userId = $user ? $user->getUID() : Helper::getUserFromPath($this->rawPath);
- break;
- case Util::FILE_TYPE_VERSION:
- $this->relPath = Helper::getPathFromVersion($this->rawPath);
- $this->userId = Helper::getUserFromPath($this->rawPath);
- break;
- case Util::FILE_TYPE_CACHE:
- $this->relPath = Helper::getPathFromCachedFile($this->rawPath);
- Helper::mkdirr($this->rawPath, new \OC\Files\View('/'));
- $user = \OC::$server->getUserSession()->getUser();
- $this->userId = $user ? $user->getUID() : Helper::getUserFromPath($this->rawPath);
- break;
- default:
- \OCP\Util::writeLog('Encryption library', 'failed to open file "' . $this->rawPath . '" expecting a path to "files", "files_versions" or "cache"', \OCP\Util::ERROR);
- return false;
- }
-
- // 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;
-
- $this->position = 0;
- $this->cache = '';
- $this->writeFlag = 0;
-
- // Setting handle so it can be used for reading the header
- if ($this->isLocalTmpFile) {
- $this->handle = fopen($this->localTmpFile, $mode);
- } else {
- $this->handle = $this->rootView->fopen($this->rawPath, $mode);
- }
-
- 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;
- } else {
- $this->size = $this->rootView->filesize($this->rawPath);
- \OC_FileProxy::$enabled = true;
- $this->unencryptedSize = $this->rootView->filesize($this->rawPath);
- \OC_FileProxy::$enabled = false;
- $this->readHeader();
- }
-
- \OC_FileProxy::$enabled = $proxyStatus;
-
- if (!is_resource($this->handle)) {
-
- \OCP\Util::writeLog('Encryption library', 'failed to open file "' . $this->rawPath . '"', \OCP\Util::ERROR);
-
- } else {
-
- $this->meta = stream_get_meta_data($this->handle);
- // sometimes fopen changes the mode, e.g. for a url "r" convert to "r+"
- // but we need to remember the original access type
- $this->meta['mode'] = $mode;
-
- }
-
-
- return is_resource($this->handle);
-
- }
-
- private function readHeader() {
-
- if (is_resource($this->handle)) {
- $data = fread($this->handle, Crypt::BLOCKSIZE);
-
- $header = Crypt::parseHeader($data);
- $this->cipher = Crypt::getCipher($header);
-
- // remeber that we found a header
- if (!empty($header)) {
- $this->containHeader = true;
- $this->headerSize = Crypt::BLOCKSIZE;
- // if there's no header then decrypt the block and store it in the cache
- } else {
- if (!$this->getKey()) {
- throw new \Exception('Encryption key not found for "' . $this->rawPath . '" during attempted read via stream');
- } else {
- $this->cache = Crypt::symmetricDecryptFileContent($data, $this->plainKey, $this->cipher);
- }
- }
-
- }
- }
-
- /**
- * Returns the current position of the file pointer
- * @return int position of the file pointer
- */
- public function stream_tell() {
- return $this->position;
- }
-
- /**
- * @param int $offset
- * @param int $whence
- * @return bool true if fseek was successful, otherwise false
- */
-
- // seeking the stream tries to move the pointer on the encrypted stream to the beginning of the target block
- // if that works, it flushes the current block and changes the position in the unencrypted stream
- public function stream_seek($offset, $whence = SEEK_SET) {
- // this wrapper needs to return "true" for success.
- // the fseek call itself returns 0 on succeess
-
- $return=false;
-
- switch($whence) {
- case SEEK_SET:
- if($offset < $this->unencryptedSize && $offset >= 0) {
- $newPosition=$offset;
- }
- break;
- case SEEK_CUR:
- if($offset>=0) {
- $newPosition=$offset+$this->position;
- }
- break;
- case SEEK_END:
- if($this->unencryptedSize + $offset >= 0) {
- $newPosition=$this->unencryptedSize+$offset;
- }
- break;
- default:
- return $return;
- }
- $newFilePosition=floor($newPosition/6126)*Crypt::BLOCKSIZE+$this->headerSize;
- if (fseek($this->handle, $newFilePosition)===0) {
- $this->flush();
- $this->position=$newPosition;
- $return=true;
- }
- return $return;
-
- }
-
- /**
- * @param int $count
- * @return bool|string
- * @throws \OCA\Files_Encryption\Exception\EncryptionException
- */
- public function stream_read($count) {
-
- $result = '';
-
- // limit to the end of the unencrypted file; otherwise getFileSize will fail and it is good practise anyway
- $count=min($count,$this->unencryptedSize - $this->position);
-
- // loop over the 6126 sized unencrypted blocks
- while ($count > 0) {
-
- $remainingLength = $count;
-
- // update the cache of the current block
- $this->readCache();
-
- // determine the relative position in the current block
- $blockPosition=($this->position % 6126);
-
- // if entire read inside current block then only position needs to be updated
- if ($remainingLength<(6126 - $blockPosition)) {
- $result .= substr($this->cache,$blockPosition,$remainingLength);
- $this->position += $remainingLength;
- $count=0;
- // otherwise remainder of current block is fetched, the block is flushed and the position updated
- } else {
- $result .= substr($this->cache,$blockPosition);
- $this->flush();
- $this->position += (6126 - $blockPosition);
- $count -= (6126 - $blockPosition);
- }
-
- }
-
- return $result;
-
- }
-
- /**
- * 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 string encrypted data on success, false on failure
- */
- public function preWriteEncrypt($plainData, $key) {
-
- // Encrypt data to 'catfile', which includes IV
- if ($encrypted = Crypt::symmetricEncryptFileContent($plainData, $key, $this->cipher)) {
-
- return $encrypted;
-
- } else {
-
- return false;
-
- }
-
- }
-
- /**
- * 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() {
-
- // 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->util, $this->relPath);
-
- // If a keyfile already exists
- if ($this->encKeyfile) {
-
- $shareKey = Keymanager::getShareKey($this->rootView, $this->keyId, $this->util, $this->relPath);
-
- // if there is no valid private key return false
- if ($this->privateKey === false) {
- // if private key is not valid redirect user to a error page
- Helper::redirectToErrorPage($this->session);
- return false;
- }
-
- if ($shareKey === false) {
- // if no share key is available redirect user to a error page
- Helper::redirectToErrorPage($this->session, Crypt::ENCRYPTION_NO_SHARE_KEY_FOUND);
- return false;
- }
-
- $this->plainKey = Crypt::multiKeyDecrypt($this->encKeyfile, $shareKey, $this->privateKey);
-
- return true;
-
- } else {
-
- $this->newFile = true;
-
- return false;
-
- }
-
- }
-
- /**
- * write header at beginning of encrypted file
- *
- * @throws \OCA\Files_Encryption\Exception\EncryptionException
- */
- private function writeHeader() {
-
- $header = Crypt::generateHeader();
-
- if (strlen($header) > Crypt::BLOCKSIZE) {
- throw new EncryptionException('max header size exceeded', EncryptionException::ENCRYPTION_HEADER_TO_LARGE);
- }
-
- $paddedHeader = str_pad($header, Crypt::BLOCKSIZE, self::PADDING_CHAR, STR_PAD_RIGHT);
-
- fwrite($this->handle, $paddedHeader);
- $this->headerWritten = true;
- $this->containHeader = true;
- $this->headerSize = Crypt::BLOCKSIZE;
- $this->size += $this->headerSize;
- }
-
- /**
- * Handle plain data from the stream, and write it in 8192 byte blocks
- * @param string $data data to be written to disk
- * @note the data will be written to the path stored in the stream handle, set in stream_open()
- * @note $data is only ever be a maximum of 8192 bytes long. This is set by PHP internally. stream_write() is called multiple times in a loop on data larger than 8192 bytes
- * @note Because the encryption process used increases the length of $data, a cache is used to carry over data which would not fit in the required block size
- * @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) {
-
- // if there is no valid private key return false
- if ($this->privateKey === false) {
- $this->size = 0;
- return strlen($data);
- }
-
- if ($this->size === 0) {
- $this->writeHeader();
- }
-
- // 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->plainKey = Crypt::generateKey();
-
- }
-
- $length=0;
-
- // loop over $data to fit it in 6126 sized unencrypted blocks
- while (strlen($data) > 0) {
-
- $remainingLength = strlen($data);
-
- // set the cache to the current 6126 block
- $this->readCache();
-
- // only allow writes on seekable streams, or at the end of the encrypted stream
- // for seekable streams the pointer is moved back to the beginning of the encrypted block
- // flush will start writing there when the position moves to another block
- if((fseek($this->handle, floor($this->position/6126)*Crypt::BLOCKSIZE + $this->headerSize) === 0) || (floor($this->position/6126)*Crypt::BLOCKSIZE + $this->headerSize === $this->size)) {
-
- // switch the writeFlag so flush() will write the block
- $this->writeFlag=1;
-
- // determine the relative position in the current block
- $blockPosition=($this->position % 6126);
-
- // check if $data fits in current block
- // if so, overwrite existing data (if any)
- // update position and liberate $data
- if ($remainingLength<(6126 - $blockPosition)) {
- $this->cache=substr($this->cache,0,$blockPosition).$data.substr($this->cache,$blockPosition+$remainingLength);
- $this->position += $remainingLength;
- $length += $remainingLength;
- $data = '';
- // if $data doens't fit the current block, the fill the current block and reiterate
- // after the block is filled, it is flushed and $data is updated
- } else {
- $this->cache=substr($this->cache,0,$blockPosition).substr($data,0,6126-$blockPosition);
- $this->flush();
- $this->position += (6126 - $blockPosition);
- $length += (6126 - $blockPosition);
- $data = substr($data, 6126 - $blockPosition);
- }
-
- } else {
- $data='';
- }
- }
-
- $this->unencryptedSize = max($this->unencryptedSize,$this->position);
-
- return $length;
-
- }
-
-
- /**
- * @param int $option
- * @param int $arg1
- * @param int|null $arg2
- */
- public function stream_set_option($option, $arg1, $arg2) {
- $return = false;
- switch ($option) {
- case STREAM_OPTION_BLOCKING:
- $return = stream_set_blocking($this->handle, $arg1);
- break;
- case STREAM_OPTION_READ_TIMEOUT:
- $return = stream_set_timeout($this->handle, $arg1, $arg2);
- break;
- case STREAM_OPTION_WRITE_BUFFER:
- $return = stream_set_write_buffer($this->handle, $arg1);
- }
-
- return $return;
- }
-
- /**
- * @return array
- */
- public function stream_stat() {
- return fstat($this->handle);
- }
-
- /**
- * @param int $mode
- */
- public function stream_lock($mode) {
- return flock($this->handle, $mode);
- }
-
- /**
- * @return bool
- */
- public function stream_flush() {
-
- $this->flush();
- return fflush($this->handle);
- // Not a typo: http://php.net/manual/en/function.fflush.php
-
- }
-
- /**
- * @return bool
- */
- public function stream_eof() {
- return ($this->position>=$this->unencryptedSize);
- }
-
- private function flush() {
-
- // write to disk only when writeFlag was set to 1
- if ($this->writeFlag === 1) {
- // 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;
- // Set keyfile property for file in question
- $this->getKey();
- $encrypted = $this->preWriteEncrypt($this->cache, $this->plainKey);
- fwrite($this->handle, $encrypted);
- $this->writeFlag = 0;
- $this->size = max($this->size,ftell($this->handle));
- \OC_FileProxy::$enabled = $proxyStatus;
- }
- // always empty the cache (otherwise readCache() will not fill it with the new block)
- $this->cache = '';
- }
-
- private function readCache() {
- // cache should always be empty string when this function is called
- // don't try to fill the cache when trying to write at the end of the unencrypted file when it coincides with new block
- if ($this->cache === '' && !($this->position===$this->unencryptedSize && ($this->position % 6126)===0)) {
- // Get the data from the file handle
- $data = fread($this->handle, Crypt::BLOCKSIZE);
- $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');
- } else {
- // Decrypt data
- $result = Crypt::symmetricDecryptFileContent($data, $this->plainKey, $this->cipher);
- }
- }
- $this->cache = $result;
- }
- }
-
- /**
- * @return bool
- */
- public function stream_close() {
-
- $this->flush();
-
- // if there is no valid private key return false
- if ($this->privateKey === false) {
-
- // cleanup
- if ($this->meta['mode'] !== 'r' && $this->meta['mode'] !== 'rb' && !$this->isLocalTmpFile) {
-
- // Disable encryption proxy to prevent recursive calls
- $proxyStatus = \OC_FileProxy::$enabled;
- \OC_FileProxy::$enabled = false;
-
- if ($this->rootView->file_exists($this->rawPath) && $this->size === $this->headerSize) {
- fclose($this->handle);
- $this->rootView->unlink($this->rawPath);
- }
-
- // Re-enable proxy - our work is done
- \OC_FileProxy::$enabled = $proxyStatus;
- }
-
- // if private key is not valid redirect user to a error page
- Helper::redirectToErrorPage($this->session);
- }
-
- if (
- $this->meta['mode'] !== 'r' &&
- $this->meta['mode'] !== 'rb' &&
- $this->isLocalTmpFile === false &&
- $this->size > $this->headerSize &&
- $this->unencryptedSize > 0
- ) {
-
- // only write keyfiles if it was a new file
- if ($this->newFile === true) {
-
- // 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->keyId);
-
- // Check if OC sharing api is enabled
- $sharingEnabled = \OCP\Share::isEnabled();
-
- // Get all users sharing the file includes current user
- $uniqueUserIds = $this->util->getSharingUsersArray($sharingEnabled, $this->relPath);
- $checkedUserIds = $this->util->filterShareReadyUsers($uniqueUserIds);
-
- // Fetch public keys for all sharing users
- $publicKeys = Keymanager::getPublicKeys($this->rootView, $checkedUserIds['ready']);
-
- // Encrypt enc key for all sharing users
- $this->encKeyfiles = Crypt::multiKeyEncrypt($this->plainKey, $publicKeys);
-
- // Save the new encrypted file key
- Keymanager::setFileKey($this->rootView, $this->util, $this->relPath, $this->encKeyfiles['data']);
-
- // Save the sharekeys
- Keymanager::setShareKeys($this->rootView, $this->util, $this->relPath, $this->encKeyfiles['keys']);
-
- // Re-enable proxy - our work is done
- \OC_FileProxy::$enabled = $proxyStatus;
- }
-
- // we need to update the file info for the real file, not for the
- // part file.
- $path = Helper::stripPartialFileExtension($this->rawPath);
-
- $fileInfo = array(
- 'mimetype' => $this->rootView->getMimeType($this->rawPath),
- 'encrypted' => true,
- 'unencrypted_size' => $this->unencryptedSize,
- );
-
- // if we write a part file we also store the unencrypted size for
- // the part file so that it can be re-used later
- $this->rootView->putFileInfo($this->rawPath, $fileInfo);
- if ($path !== $this->rawPath) {
- $this->rootView->putFileInfo($path, $fileInfo);
- }
-
- }
-
- $result = fclose($this->handle);
-
- if ($result === false) {
- \OCP\Util::writeLog('Encryption library', 'Could not close stream, file could be corrupted', \OCP\Util::FATAL);
- }
-
- return $result;
-
- }
-
-}
diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php
deleted file mode 100644
index d8dd96d653f..00000000000
--- a/apps/files_encryption/lib/util.php
+++ /dev/null
@@ -1,1700 +0,0 @@
-<?php
-/**
- * @author Arthur Schiwon <blizzz@owncloud.com>
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Florin Peter <github@florin-peter.de>
- * @author jknockaert <jasper@knockaert.nl>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Markus Goetz <markus@woboq.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- * @author Sam Tuke <mail@samtuke.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\Files_Encryption;
-
-/**
- * Class for utilities relating to encrypted file storage system
- * @param \OC\Files\View $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 {
-
- const MIGRATION_COMPLETED = 1; // migration to new encryption completed
- const MIGRATION_IN_PROGRESS = -1; // migration is running
- const MIGRATION_OPEN = 0; // user still needs to be migrated
-
- const FILE_TYPE_FILE = 0;
- const FILE_TYPE_VERSION = 1;
- const FILE_TYPE_CACHE = 2;
-
- /**
- * @var \OC\Files\View
- */
- private $view; // OC\Files\View object for filesystem operations
-
- /**
- * @var string
- */
- private $userId; // ID of the user we use to encrypt/decrypt files
-
- /**
- * @var string
- */
- private $keyId; // ID of the key we want to manipulate
-
- /**
- * @var bool
- */
- private $client; // Client side encryption mode flag
-
- /**
- * @var string
- */
- private $publicKeyDir; // Dir containing all public user keys
-
- /**
- * @var string
- */
- private $encryptionDir; // Dir containing user's files_encryption
-
- /**
- * @var string
- */
- private $keysPath; // Dir containing all file related encryption keys
-
- /**
- * @var string
- */
- private $publicKeyPath; // Path to user's public key
-
- /**
- * @var string
- */
- private $privateKeyPath; // Path to user's private key
-
- /**
- * @var string
- */
- private $userFilesDir;
-
- /**
- * @var string
- */
- private $publicShareKeyId;
-
- /**
- * @var string
- */
- private $recoveryKeyId;
-
- /**
- * @var bool
- */
- private $isPublic;
-
- /**
- * @param \OC\Files\View $view
- * @param string $userId
- * @param bool $client
- */
- public function __construct($view, $userId, $client = false) {
-
- $this->view = $view;
- $this->client = $client;
- $this->userId = $userId;
-
- $appConfig = \OC::$server->getAppConfig();
-
- $this->publicShareKeyId = $appConfig->getValue('files_encryption', 'publicShareKeyId');
- $this->recoveryKeyId = $appConfig->getValue('files_encryption', 'recoveryKeyId');
-
- $this->userDir = '/' . $this->userId;
- $this->fileFolderName = 'files';
- $this->userFilesDir =
- '/' . $userId . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable?
- $this->publicKeyDir = Keymanager::getPublicKeyPath();
- $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption';
- $this->keysPath = $this->encryptionDir . '/' . 'keys';
- $this->publicKeyPath =
- $this->publicKeyDir . '/' . $this->userId . '.publicKey'; // e.g. data/public-keys/admin.publicKey
- $this->privateKeyPath =
- $this->encryptionDir . '/' . $this->userId . '.privateKey'; // e.g. data/admin/admin.privateKey
- // make sure that the owners home is mounted
- \OC\Files\Filesystem::initMountPoints($userId);
-
- if (Helper::isPublicAccess()) {
- $this->keyId = $this->publicShareKeyId;
- $this->isPublic = true;
- } else {
- $this->keyId = $this->userId;
- $this->isPublic = false;
- }
- }
-
- /**
- * @return bool
- */
- public function ready() {
-
- if (
- !$this->view->file_exists($this->encryptionDir)
- or !$this->view->file_exists($this->keysPath)
- or !$this->view->file_exists($this->publicKeyPath)
- or !$this->view->file_exists($this->privateKeyPath)
- ) {
- return false;
- } else {
- return true;
- }
- }
-
- /**
- * check if the users private & public key exists
- * @return boolean
- */
- public function userKeysExists() {
- if (
- $this->view->file_exists($this->privateKeyPath) &&
- $this->view->file_exists($this->publicKeyPath)) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * create a new public/private key pair for the user
- *
- * @param string $password password for the private key
- */
- public function replaceUserKeys($password) {
- $this->backupAllKeys('password_reset');
- $this->view->unlink($this->publicKeyPath);
- $this->view->unlink($this->privateKeyPath);
- $this->setupServerSide($password);
- }
-
- /**
- * 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->publicKeyDir,
- $this->encryptionDir,
- $this->keysPath
- );
-
- // Check / create all necessary dirs
- foreach ($setUpDirs as $dirPath) {
-
- if (!$this->view->file_exists($dirPath)) {
-
- $this->view->mkdir($dirPath);
-
- }
-
- }
-
- // Create user keypair
- // we should never override a keyfile
- if (
- !$this->view->file_exists($this->publicKeyPath)
- && !$this->view->file_exists($this->privateKeyPath)
- ) {
-
- // Generate keypair
- $keypair = Crypt::createKeypair();
-
- if ($keypair) {
-
- \OC_FileProxy::$enabled = false;
-
- // Encrypt private key with user pwd as passphrase
- $encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $passphrase, Helper::getCipher());
-
- // Save key-pair
- if ($encryptedPrivateKey) {
- $header = crypt::generateHeader();
- $this->view->file_put_contents($this->privateKeyPath, $header . $encryptedPrivateKey);
- $this->view->file_put_contents($this->publicKeyPath, $keypair['publicKey']);
- }
-
- \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->keyId . '"', \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->keyId . '"', \OCP\Util::FATAL);
- return false;
- }
- }
- }
-
- return true;
-
- }
-
- /**
- * @return string
- */
- public function getPublicShareKeyId() {
- return $this->publicShareKeyId;
- }
-
- /**
- * 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() {
-
- $recoveryMode = \OC::$server->getConfig()->getUserValue($this->userId, 'files_encryption', 'recovery_enabled', '0');
-
- return ($recoveryMode === '1') ? true : false;
-
- }
-
- /**
- * Enable / disable pwd recovery for a given user
- * @param bool $enabled Whether to enable or disable recovery
- * @return bool
- */
- public function setRecoveryForUser($enabled) {
-
- $value = $enabled ? '1' : '0';
- try {
- \OC::$server->getConfig()->setUserValue($this->userId, 'files_encryption', 'recovery_enabled', $value);
- return true;
- } catch(\OCP\PreConditionNotMetException $e) {
- return false;
- }
-
- }
-
- /**
- * 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 array keys: plain, encrypted, broken
- * @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 findEncFiles($directory, &$found = false) {
-
- // Disable proxy - we don't want files to be decrypted before
- // we handle them
- \OC_FileProxy::$enabled = false;
-
- if ($found === false) {
- $found = array(
- 'plain' => array(),
- 'encrypted' => array(),
- 'broken' => array(),
- );
- }
-
- if ($this->view->is_dir($directory) && $handle = $this->view->opendir($directory)){
- if (is_resource($handle)) {
- while (false !== ($file = readdir($handle))) {
-
- if ($file !== "." && $file !== "..") {
- // skip stray part files
- if (Helper::isPartialFilePath($file)) {
- continue;
- }
-
- $filePath = $directory . '/' . $this->view->getRelativePath('/' . $file);
- $relPath = Helper::stripUserFilesPath($filePath);
-
- // If the path is a directory, search
- // its contents
- 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;
-
- $isEncryptedPath = $this->isEncryptedPath($filePath);
- // If the file is encrypted
- // NOTE: If the userId is
- // empty or not set, file will
- // detected as plain
- // NOTE: This is inefficient;
- // scanning every file like this
- // will eat server resources :(
- if ($isEncryptedPath) {
-
- $fileKey = Keymanager::getFileKey($this->view, $this, $relPath);
- $shareKey = Keymanager::getShareKey($this->view, $this->userId, $this, $relPath);
- // if file is encrypted but now file key is available, throw exception
- if ($fileKey === false || $shareKey === false) {
- \OCP\Util::writeLog('encryption library', 'No keys available to decrypt the file: ' . $filePath, \OCP\Util::ERROR);
- $found['broken'][] = array(
- 'name' => $file,
- 'path' => $filePath,
- );
- } else {
- $found['encrypted'][] = array(
- 'name' => $file,
- 'path' => $filePath,
- );
- }
-
- // If the file is not encrypted
- } else {
-
- $found['plain'][] = array(
- 'name' => $file,
- 'path' => $relPath
- );
- }
- }
- }
- }
- }
- }
-
- \OC_FileProxy::$enabled = true;
-
- return $found;
- }
-
- /**
- * Check if a given path identifies an encrypted file
- * @param string $path
- * @return boolean
- */
- public function isEncryptedPath($path) {
-
- // Disable encryption proxy so data retrieved is in its
- // original form
- $proxyStatus = \OC_FileProxy::$enabled;
- \OC_FileProxy::$enabled = false;
-
- $data = '';
-
- // we only need 24 byte from the last chunk
- if ($this->view->file_exists($path)) {
- $handle = $this->view->fopen($path, 'r');
- if (is_resource($handle)) {
- // suppress fseek warining, we handle the case that fseek doesn't
- // work in the else branch
- if (@fseek($handle, -24, SEEK_END) === 0) {
- $data = fgets($handle);
- } else {
- // if fseek failed on the storage we create a local copy from the file
- // and read this one
- fclose($handle);
- $localFile = $this->view->getLocalFile($path);
- $handle = fopen($localFile, 'r');
- if (is_resource($handle) && fseek($handle, -24, SEEK_END) === 0) {
- $data = fgets($handle);
- }
- }
- fclose($handle);
- }
- }
-
- // re-enable proxy
- \OC_FileProxy::$enabled = $proxyStatus;
-
- return Crypt::isCatfileContent($data);
- }
-
- /**
- * 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);
-
- if (isset($pathParts[2]) && $pathParts[2] === 'files' && $this->view->file_exists($path)
- && $this->isEncryptedPath($path)
- ) {
-
- $cipher = 'AES-128-CFB';
- $realSize = 0;
-
- // get the size from filesystem
- $size = $this->view->filesize($path);
-
- // open stream
- $stream = $this->view->fopen($path, "r");
-
- if (is_resource($stream)) {
-
- // if the file contains a encryption header we
- // we set the cipher
- // and we update the size
- if ($this->containHeader($path)) {
- $data = fread($stream,Crypt::BLOCKSIZE);
- $header = Crypt::parseHeader($data);
- $cipher = Crypt::getCipher($header);
- $size -= Crypt::BLOCKSIZE;
- }
-
- // fast path, else the calculation for $lastChunkNr is bogus
- if ($size === 0) {
- \OC_FileProxy::$enabled = $proxyStatus;
- return 0;
- }
-
- // calculate last chunk nr
- // next highest is end of chunks, one subtracted is last one
- // we have to read the last chunk, we can't just calculate it (because of padding etc)
- $lastChunkNr = ceil($size/Crypt::BLOCKSIZE)-1;
-
- // calculate last chunk position
- $lastChunkPos = ($lastChunkNr * Crypt::BLOCKSIZE);
-
- // get the content of the last chunk
- if (@fseek($stream, $lastChunkPos, SEEK_CUR) === 0) {
- $realSize+=$lastChunkNr*6126;
- }
- $lastChunkContentEncrypted='';
- $count=Crypt::BLOCKSIZE;
- while ($count>0) {
- $data=fread($stream,Crypt::BLOCKSIZE);
- $count=strlen($data);
- $lastChunkContentEncrypted.=$data;
- if(strlen($lastChunkContentEncrypted)>Crypt::BLOCKSIZE) {
- $realSize+=6126;
- $lastChunkContentEncrypted=substr($lastChunkContentEncrypted,Crypt::BLOCKSIZE);
- }
- }
- fclose($stream);
- $relPath = Helper::stripUserFilesPath($path);
- $shareKey = Keymanager::getShareKey($this->view, $this->keyId, $this, $relPath);
- if($shareKey===false) {
- \OC_FileProxy::$enabled = $proxyStatus;
- return $result;
- }
- $session = new Session($this->view);
- $privateKey = $session->getPrivateKey();
- $plainKeyfile = $this->decryptKeyfile($relPath, $privateKey);
- $plainKey = Crypt::multiKeyDecrypt($plainKeyfile, $shareKey, $privateKey);
- $lastChunkContent=Crypt::symmetricDecryptFileContent($lastChunkContentEncrypted, $plainKey, $cipher);
-
- // calc the real file size with the size of the last chunk
- $realSize += strlen($lastChunkContent);
-
- // store file size
- $result = $realSize;
- }
- }
-
- \OC_FileProxy::$enabled = $proxyStatus;
-
- return $result;
- }
-
- /**
- * check if encrypted file contain a encryption header
- *
- * @param string $path
- * @return boolean
- */
- private function containHeader($path) {
- // Disable encryption proxy to read the raw data
- $proxyStatus = \OC_FileProxy::$enabled;
- \OC_FileProxy::$enabled = false;
-
- $isHeader = false;
- $handle = $this->view->fopen($path, 'r');
-
- if (is_resource($handle)) {
- $firstBlock = fread($handle, Crypt::BLOCKSIZE);
- $isHeader = Crypt::isHeader($firstBlock);
- }
-
- \OC_FileProxy::$enabled = $proxyStatus;
-
- return $isHeader;
- }
-
- /**
- * fix the file size of the encrypted file
- * @param string $path absolute path
- * @return boolean true / false if file is encrypted
- */
- 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;
- }
-
- /**
- * encrypt versions from given file
- * @param array $filelist list of encrypted files, relative to data/user/files
- * @return boolean
- */
- private function encryptVersions($filelist) {
-
- $successful = true;
-
- if (\OCP\App::isEnabled('files_versions')) {
-
- foreach ($filelist as $filename) {
-
- $versions = \OCA\Files_Versions\Storage::getVersions($this->userId, $filename);
- foreach ($versions as $version) {
-
- $path = '/' . $this->userId . '/files_versions/' . $version['path'] . '.v' . $version['version'];
-
- $encHandle = fopen('crypt://' . $path . '.part', 'wb');
-
- if ($encHandle === false) {
- \OCP\Util::writeLog('Encryption library', 'couldn\'t open "' . $path . '", decryption failed!', \OCP\Util::FATAL);
- $successful = false;
- continue;
- }
-
- $plainHandle = $this->view->fopen($path, 'rb');
- if ($plainHandle === false) {
- \OCP\Util::writeLog('Encryption library', 'couldn\'t open "' . $path . '.part", decryption failed!', \OCP\Util::FATAL);
- $successful = false;
- continue;
- }
-
- stream_copy_to_stream($plainHandle, $encHandle);
-
- fclose($encHandle);
- fclose($plainHandle);
-
- $this->view->rename($path . '.part', $path);
- }
- }
- }
-
- return $successful;
- }
-
- /**
- * decrypt versions from given file
- * @param string $filelist list of decrypted files, relative to data/user/files
- * @return boolean
- */
- private function decryptVersions($filelist) {
-
- $successful = true;
-
- if (\OCP\App::isEnabled('files_versions')) {
-
- foreach ($filelist as $filename) {
-
- $versions = \OCA\Files_Versions\Storage::getVersions($this->userId, $filename);
- foreach ($versions as $version) {
-
- $path = '/' . $this->userId . '/files_versions/' . $version['path'] . '.v' . $version['version'];
-
- $encHandle = fopen('crypt://' . $path, 'rb');
-
- if ($encHandle === false) {
- \OCP\Util::writeLog('Encryption library', 'couldn\'t open "' . $path . '", decryption failed!', \OCP\Util::FATAL);
- $successful = false;
- continue;
- }
-
- $plainHandle = $this->view->fopen($path . '.part', 'wb');
- if ($plainHandle === false) {
- \OCP\Util::writeLog('Encryption library', 'couldn\'t open "' . $path . '.part", decryption failed!', \OCP\Util::FATAL);
- $successful = false;
- continue;
- }
-
- stream_copy_to_stream($encHandle, $plainHandle);
-
- fclose($encHandle);
- fclose($plainHandle);
-
- $this->view->rename($path . '.part', $path);
- }
- }
- }
-
- return $successful;
- }
-
- /**
- * Decrypt all files
- * @return bool
- */
- public function decryptAll() {
-
- $found = $this->findEncFiles($this->userId . '/files');
-
- $successful = true;
-
- if ($found) {
-
- $versionStatus = \OCP\App::isEnabled('files_versions');
- \OC_App::disable('files_versions');
-
- $decryptedFiles = array();
-
- // Encrypt unencrypted files
- foreach ($found['encrypted'] as $encryptedFile) {
-
- //relative to data/<user>/file
- $relPath = Helper::stripUserFilesPath($encryptedFile['path']);
-
- //get file info
- $fileInfo = \OC\Files\Filesystem::getFileInfo($relPath);
-
- //relative to /data
- $rawPath = $encryptedFile['path'];
-
- //get timestamp
- $timestamp = $fileInfo['mtime'];
-
- //enable proxy to use OC\Files\View to access the original file
- \OC_FileProxy::$enabled = true;
-
- // Open enc file handle for binary reading
- $encHandle = $this->view->fopen($rawPath, 'rb');
-
- // Disable proxy to prevent file being encrypted again
- \OC_FileProxy::$enabled = false;
-
- if ($encHandle === false) {
- \OCP\Util::writeLog('Encryption library', 'couldn\'t open "' . $rawPath . '", decryption failed!', \OCP\Util::FATAL);
- $successful = false;
- continue;
- }
-
- // Open plain file handle for binary writing, with same filename as original plain file
- $plainHandle = $this->view->fopen($rawPath . '.part', 'wb');
- if ($plainHandle === false) {
- \OCP\Util::writeLog('Encryption library', 'couldn\'t open "' . $rawPath . '.part", decryption failed!', \OCP\Util::FATAL);
- $successful = false;
- continue;
- }
-
- // Move plain file to a temporary location
- $size = stream_copy_to_stream($encHandle, $plainHandle);
- if ($size === 0) {
- \OCP\Util::writeLog('Encryption library', 'Zero bytes copied of "' . $rawPath . '", decryption failed!', \OCP\Util::FATAL);
- $successful = false;
- continue;
- }
-
- fclose($encHandle);
- fclose($plainHandle);
-
- $fakeRoot = $this->view->getRoot();
- $this->view->chroot('/' . $this->userId . '/files');
-
- $this->view->rename($relPath . '.part', $relPath);
-
- //set timestamp
- $this->view->touch($relPath, $timestamp);
-
- $this->view->chroot($fakeRoot);
-
- // Add the file to the cache
- \OC\Files\Filesystem::putFileInfo($relPath, array(
- 'encrypted' => false,
- 'size' => $size,
- 'unencrypted_size' => 0,
- 'etag' => $fileInfo['etag']
- ));
-
- $decryptedFiles[] = $relPath;
-
- }
-
- if ($versionStatus) {
- \OC_App::enable('files_versions');
- }
-
- if (!$this->decryptVersions($decryptedFiles)) {
- $successful = false;
- }
-
- // if there are broken encrypted files than the complete decryption
- // was not successful
- if (!empty($found['broken'])) {
- $successful = false;
- }
-
- if ($successful) {
- $this->backupAllKeys('decryptAll', false, false);
- $this->view->deleteAll($this->keysPath);
- }
-
- \OC_FileProxy::$enabled = true;
- }
-
- return $successful;
- }
-
- /**
- * Encrypt all files in a directory
- * @param string $dirPath the directory whose files will be encrypted
- * @return bool
- * @note Encryption is recursive
- */
- public function encryptAll($dirPath) {
-
- $result = true;
-
- $found = $this->findEncFiles($dirPath);
-
- // Disable proxy to prevent file being encrypted twice
- \OC_FileProxy::$enabled = false;
-
- $versionStatus = \OCP\App::isEnabled('files_versions');
- \OC_App::disable('files_versions');
-
- $encryptedFiles = array();
-
- // Encrypt unencrypted files
- foreach ($found['plain'] as $plainFile) {
-
- //get file info
- $fileInfo = \OC\Files\Filesystem::getFileInfo($plainFile['path']);
-
- //relative to data/<user>/file
- $relPath = $plainFile['path'];
-
- //relative to /data
- $rawPath = '/' . $this->userId . '/files/' . $plainFile['path'];
-
- // keep timestamp
- $timestamp = $fileInfo['mtime'];
-
- // 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://' . $rawPath . '.part', 'wb');
-
- if (is_resource($encHandle) && is_resource($plainHandle)) {
- // Move plain file to a temporary location
- $size = stream_copy_to_stream($plainHandle, $encHandle);
-
- fclose($encHandle);
- fclose($plainHandle);
-
- $fakeRoot = $this->view->getRoot();
- $this->view->chroot('/' . $this->userId . '/files');
-
- $this->view->rename($relPath . '.part', $relPath);
-
- // set timestamp
- $this->view->touch($relPath, $timestamp);
-
- $encSize = $this->view->filesize($relPath);
-
- $this->view->chroot($fakeRoot);
-
- // Add the file to the cache
- \OC\Files\Filesystem::putFileInfo($relPath, array(
- 'encrypted' => true,
- 'size' => $encSize,
- 'unencrypted_size' => $size,
- 'etag' => $fileInfo['etag']
- ));
-
- $encryptedFiles[] = $relPath;
- } else {
- \OCP\Util::writeLog('files_encryption', 'initial encryption: could not encrypt ' . $rawPath, \OCP\Util::FATAL);
- $result = false;
- }
- }
-
- \OC_FileProxy::$enabled = true;
-
- if ($versionStatus) {
- \OC_App::enable('files_versions');
- }
-
- $result = $result && $this->encryptVersions($encryptedFiles);
-
- return $result;
-
- }
-
- /**
- * 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) {
-
- case 'publicKeyDir':
-
- return $this->publicKeyDir;
-
- break;
-
- case 'encryptionDir':
-
- return $this->encryptionDir;
-
- break;
-
- case 'keysPath':
-
- return $this->keysPath;
-
- break;
-
- case 'publicKeyPath':
-
- return $this->publicKeyPath;
-
- break;
-
- case 'privateKeyPath':
-
- return $this->privateKeyPath;
-
- break;
- }
-
- return false;
-
- }
-
- /**
- * Returns whether the given user is ready for encryption.
- * Also returns true if the given user is the public user
- * or the recovery key user.
- *
- * @param string $user user to check
- *
- * @return boolean true if the user is ready, false otherwise
- */
- private function isUserReady($user) {
- if ($user === $this->publicShareKeyId
- || $user === $this->recoveryKeyId
- ) {
- return true;
- }
- $util = new Util($this->view, $user);
- return $util->ready();
- }
-
- /**
- * 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) {
- // Check that the user is encryption capable, or is the
- // public system user (for public shares)
- if ($this->isUserReady($user)) {
-
- // 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
- );
-
- }
-
- /**
- * Decrypt a keyfile
- * @param string $filePath
- * @param string $privateKey
- * @return false|string
- */
- private function decryptKeyfile($filePath, $privateKey) {
-
- // Get the encrypted keyfile
- $encKeyfile = Keymanager::getFileKey($this->view, $this, $filePath);
-
- // The file has a shareKey and must use it for decryption
- $shareKey = Keymanager::getShareKey($this->view, $this->keyId, $this, $filePath);
-
- $plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey);
-
- return $plainKeyfile;
- }
-
- /**
- * 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();
-
- try {
- // Decrypt keyfile
- $plainKeyfile = $this->decryptKeyfile($filePath, $privateKey);
- // Re-enc keyfile to (additional) sharekeys
- $multiEncKey = Crypt::multiKeyEncrypt($plainKeyfile, $userPubKeys);
- } catch (Exception\EncryptionException $e) {
- $msg = 'set shareFileKeyFailed (code: ' . $e->getCode() . '): ' . $e->getMessage();
- \OCP\Util::writeLog('files_encryption', $msg, \OCP\Util::FATAL);
- return false;
- } catch (\Exception $e) {
- $msg = 'set shareFileKeyFailed (unknown error): ' . $e->getMessage();
- \OCP\Util::writeLog('files_encryption', $msg, \OCP\Util::FATAL);
- return false;
- }
-
- // Save the recrypted key to it's owner's keyfiles directory
- // Save new sharekeys to all necessary user directory
- if (
- !Keymanager::setFileKey($this->view, $this, $filePath, $multiEncKey['data'])
- || !Keymanager::setShareKeys($this->view, $this, $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;
- }
-
- /**
- * Find, sanitise and format users sharing a file
- * @note This wraps other methods into a portable bundle
- * @param boolean $sharingEnabled
- * @param string $filePath path relativ to current users files folder
- */
- public function getSharingUsersArray($sharingEnabled, $filePath) {
-
- $appConfig = \OC::$server->getAppConfig();
-
- // Check if key recovery is enabled
- if (
- $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);
-
- $ownerPath = Helper::stripPartialFileExtension($ownerPath);
-
- // always add owner to the list of users with access to the file
- $userIds = array($owner);
-
- if ($sharingEnabled) {
-
- // Find out who, if anyone, is sharing the file
- $result = \OCP\Share::getUsersSharingFile($ownerPath, $owner);
- $userIds = \array_merge($userIds, $result['users']);
- if ($result['public'] || $result['remote']) {
- $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 = $appConfig->getValue('files_encryption', 'recoveryKeyId');
- // Add recoveryAdmin to list of users sharing
- $userIds[] = $recoveryKeyId;
- }
-
- // check if it is a group mount
- if (\OCP\App::isEnabled("files_external")) {
- $mounts = \OC_Mount_Config::getSystemMountPoints();
- foreach ($mounts as $mount) {
- if ($mount['mountpoint'] == substr($ownerPath, 1, strlen($mount['mountpoint']))) {
- $userIds = array_merge($userIds, $this->getUserWithAccessToMountPoint($mount['applicable']['users'], $mount['applicable']['groups']));
- }
- }
- }
-
- // Remove duplicate UIDs
- $uniqueUserIds = array_unique($userIds);
-
- return $uniqueUserIds;
-
- }
-
- private function getUserWithAccessToMountPoint($users, $groups) {
- $result = array();
- if (in_array('all', $users)) {
- $result = \OCP\User::getUsers();
- } else {
- $result = array_merge($result, $users);
- foreach ($groups as $group) {
- $result = array_merge($result, \OC_Group::usersInGroup($group));
- }
- }
-
- return $result;
- }
-
- /**
- * set migration status
- * @param int $status
- * @param int $preCondition only update migration status if the previous value equals $preCondition
- * @return boolean
- */
- private function setMigrationStatus($status, $preCondition = null) {
-
- // convert to string if preCondition is set
- $preCondition = ($preCondition === null) ? null : (string)$preCondition;
-
- try {
- \OC::$server->getConfig()->setUserValue($this->userId, 'files_encryption', 'migration_status', (string)$status, $preCondition);
- return true;
- } catch(\OCP\PreConditionNotMetException $e) {
- return false;
- }
-
- }
-
- /**
- * start migration mode to initially encrypt users data
- * @return boolean
- */
- public function beginMigration() {
-
- $result = $this->setMigrationStatus(self::MIGRATION_IN_PROGRESS, self::MIGRATION_OPEN);
-
- if ($result) {
- \OCP\Util::writeLog('Encryption library', "Start migration to encryption mode for " . $this->userId, \OCP\Util::INFO);
- } else {
- \OCP\Util::writeLog('Encryption library', "Could not activate migration mode for " . $this->userId . ". Probably another process already started the initial encryption", \OCP\Util::WARN);
- }
-
- return $result;
- }
-
- public function resetMigrationStatus() {
- return $this->setMigrationStatus(self::MIGRATION_OPEN);
-
- }
-
- /**
- * close migration mode after users data has been encrypted successfully
- * @return boolean
- */
- public function finishMigration() {
- $result = $this->setMigrationStatus(self::MIGRATION_COMPLETED);
-
- if ($result) {
- \OCP\Util::writeLog('Encryption library', "Finish migration successfully for " . $this->userId, \OCP\Util::INFO);
- } else {
- \OCP\Util::writeLog('Encryption library', "Could not deactivate migration mode for " . $this->userId, \OCP\Util::WARN);
- }
-
- return $result;
- }
-
- /**
- * check if files are already migrated to the encryption system
- * @return int|false migration status, false = in case of 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() {
-
- $migrationStatus = false;
- if (\OCP\User::userExists($this->userId)) {
- $migrationStatus = \OC::$server->getConfig()->getUserValue($this->userId, 'files_encryption', 'migration_status', null);
- if ($migrationStatus === null) {
- \OC::$server->getConfig()->setUserValue($this->userId, 'files_encryption', 'migration_status', (string)self::MIGRATION_OPEN);
- $migrationStatus = self::MIGRATION_OPEN;
- }
- }
-
- return (int)$migrationStatus;
-
- }
-
- /**
- * 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) {
-
- $pathinfo = pathinfo($path);
- $partfile = false;
- $parentFolder = false;
- if (array_key_exists('extension', $pathinfo) && $pathinfo['extension'] === 'part') {
- // if the real file exists we check this file
- $filePath = $this->userFilesDir . '/' .$pathinfo['dirname'] . '/' . $pathinfo['filename'];
- if ($this->view->file_exists($filePath)) {
- $pathToCheck = $pathinfo['dirname'] . '/' . $pathinfo['filename'];
- } else { // otherwise we look for the parent
- $pathToCheck = $pathinfo['dirname'];
- $parentFolder = true;
- }
- $partfile = true;
- } else {
- $pathToCheck = $path;
- }
-
- $view = new \OC\Files\View($this->userFilesDir);
- $fileOwnerUid = $view->getOwner($pathToCheck);
-
- // handle public access
- if ($this->isPublic) {
- return array($this->userId, $path);
- } 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($pathToCheck);
- $ownerView = new \OC\Files\View('/' . $fileOwnerUid . '/files');
-
- // Fetch real file path from DB
- $filename = $ownerView->getPath($info['fileid']);
- if ($parentFolder) {
- $filename = $filename . '/'. $pathinfo['filename'];
- }
-
- if ($partfile) {
- $filename = $filename . '.' . $pathinfo['extension'];
- }
-
- }
-
- return array(
- $fileOwnerUid,
- \OC\Files\Filesystem::normalizePath($filename)
- );
- }
- }
-
- /**
- * 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, $mountPoint = '') {
- $result = array();
- $dirList = array($dir);
-
- while ($dirList) {
- $dir = array_pop($dirList);
- $content = $this->view->getDirectoryContent(\OC\Files\Filesystem::normalizePath(
- $this->userFilesDir . '/' . $dir));
-
- foreach ($content as $c) {
- // getDirectoryContent() returns the paths relative to the mount points, so we need
- // to re-construct the complete path
- $path = ($mountPoint !== '') ? $mountPoint . '/' . $c['path'] : $c['path'];
- $path = \OC\Files\Filesystem::normalizePath($path);
- if ($c['type'] === 'dir') {
- $dirList[] = substr($path, strlen('/' . \OCP\User::getUser() . "/files"));
- } else {
- $result[] = substr($path, strlen('/' . \OCP\User::getUser() . "/files"));
- }
- }
-
- }
-
- return $result;
- }
-
- /**
- * get owner of the shared files.
- * @param int $id 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 = null;
- if (\OCP\DB::isError($result)) {
- \OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
- } else {
- $source = $result->fetchRow();
- }
-
- $fileOwner = false;
-
- if ($source && 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 = null;
- if (\OCP\DB::isError($result)) {
- \OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
- } else {
- $item = $result->fetchRow();
- }
-
- if ($item && 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 getKeyId() {
- return $this->keyId;
- }
-
- /**
- * @return string
- */
- public function getUserFilesDir() {
- return $this->userFilesDir;
- }
-
- /**
- * @param string $password
- * @return bool
- */
- public function checkRecoveryPassword($password) {
-
- $result = false;
-
- $recoveryKey = Keymanager::getPrivateSystemKey($this->recoveryKeyId);
- $decryptedRecoveryKey = Crypt::decryptPrivateKey($recoveryKey, $password);
-
- if ($decryptedRecoveryKey) {
- $result = true;
- }
-
- return $result;
- }
-
- /**
- * @return string
- */
- public function getRecoveryKeyId() {
- return $this->recoveryKeyId;
- }
-
- /**
- * add recovery key to all encrypted files
- */
- public function addRecoveryKeys($path = '/') {
- $dirContent = $this->view->getDirectoryContent($this->keysPath . '/' . $path);
- foreach ($dirContent as $item) {
- // get relative path from files_encryption/keyfiles/
- $filePath = substr($item['path'], strlen('files_encryption/keys'));
- if ($this->view->is_dir($this->userFilesDir . '/' . $filePath)) {
- $this->addRecoveryKeys($filePath . '/');
- } else {
- $session = new Session(new \OC\Files\View('/'));
- $sharingEnabled = \OCP\Share::isEnabled();
- $usersSharing = $this->getSharingUsersArray($sharingEnabled, $filePath);
- $this->setSharedFileKeyfiles($session, $usersSharing, $filePath);
- }
- }
- }
-
- /**
- * remove recovery key to all encrypted files
- */
- public function removeRecoveryKeys($path = '/') {
- $dirContent = $this->view->getDirectoryContent($this->keysPath . '/' . $path);
- foreach ($dirContent as $item) {
- // get relative path from files_encryption/keyfiles
- $filePath = substr($item['path'], strlen('files_encryption/keys'));
- if ($this->view->is_dir($this->userFilesDir . '/' . $filePath)) {
- $this->removeRecoveryKeys($filePath . '/');
- } else {
- $this->view->unlink($this->keysPath . '/' . $filePath . '/' . $this->recoveryKeyId . '.shareKey');
- }
- }
- }
-
- /**
- * 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);
-
- //decrypt file key
- $encKeyfile = Keymanager::getFileKey($this->view, $this, $file);
- $shareKey = Keymanager::getShareKey($this->view, $this->recoveryKeyId, $this, $file);
- $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);
-
- Keymanager::setFileKey($this->view, $this, $file, $multiEncKey['data']);
- Keymanager::setShareKeys($this->view, $this, $file, $multiEncKey['keys']);
-
- }
-
- /**
- * 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->keysPath . '/' . $path);
- foreach ($dirContent as $item) {
- // get relative path from files_encryption/keyfiles
- $filePath = substr($item['path'], strlen('files_encryption/keys'));
- if ($this->view->is_dir($this->userFilesDir . '/' . $filePath)) {
- $this->recoverAllFiles($filePath . '/', $privateKey);
- } else {
- $this->recoverFile($filePath, $privateKey);
- }
- }
- }
-
- /**
- * recover users files in case of password lost
- * @param string $recoveryPassword
- */
- public function recoverUsersFiles($recoveryPassword) {
-
- $encryptedKey = Keymanager::getPrivateSystemKey( $this->recoveryKeyId);
- $privateKey = Crypt::decryptPrivateKey($encryptedKey, $recoveryPassword);
-
- $this->recoverAllFiles('/', $privateKey);
- }
-
- /**
- * create a backup of all keys from the user
- *
- * @param string $purpose define the purpose of the backup, will be part of the backup folder name
- * @param boolean $timestamp (optional) should a timestamp be added, default true
- * @param boolean $includeUserKeys (optional) include users private-/public-key, default true
- */
- public function backupAllKeys($purpose, $timestamp = true, $includeUserKeys = true) {
- $this->userId;
- $backupDir = $this->encryptionDir . '/backup.' . $purpose;
- $backupDir .= ($timestamp) ? '.' . date("Y-m-d_H-i-s") . '/' : '/';
- $this->view->mkdir($backupDir);
- $this->view->copy($this->keysPath, $backupDir . 'keys/');
- if ($includeUserKeys) {
- $this->view->copy($this->privateKeyPath, $backupDir . $this->userId . '.privateKey');
- $this->view->copy($this->publicKeyPath, $backupDir . $this->userId . '.publicKey');
- }
- }
-
- /**
- * restore backup
- *
- * @param string $backup complete name of the backup
- * @return boolean
- */
- public function restoreBackup($backup) {
- $backupDir = $this->encryptionDir . '/backup.' . $backup . '/';
-
- $fileKeysRestored = $this->view->rename($backupDir . 'keys', $this->encryptionDir . '/keys');
-
- $pubKeyRestored = $privKeyRestored = true;
- if (
- $this->view->file_exists($backupDir . $this->userId . '.privateKey') &&
- $this->view->file_exists($backupDir . $this->userId . '.privateKey')
- ) {
-
- $pubKeyRestored = $this->view->rename($backupDir . $this->userId . '.publicKey', $this->publicKeyPath);
- $privKeyRestored = $this->view->rename($backupDir . $this->userId . '.privateKey', $this->privateKeyPath);
- }
-
- if ($fileKeysRestored && $pubKeyRestored && $privKeyRestored) {
- $this->view->deleteAll($backupDir);
-
- return true;
- }
-
- return false;
- }
-
- /**
- * delete backup
- *
- * @param string $backup complete name of the backup
- * @return boolean
- */
- public function deleteBackup($backup) {
- $backupDir = $this->encryptionDir . '/backup.' . $backup . '/';
- return $this->view->deleteAll($backupDir);
- }
-
- /**
- * check if the file is stored on a system wide mount point
- * @param string $path relative to /data/user with leading '/'
- * @return boolean
- */
- public function isSystemWideMountPoint($path) {
- $normalizedPath = ltrim($path, '/');
- if (\OCP\App::isEnabled("files_external")) {
- $mounts = \OC_Mount_Config::getSystemMountPoints();
- foreach ($mounts as $mount) {
- if ($mount['mountpoint'] == substr($normalizedPath, 0, strlen($mount['mountpoint']))) {
- if ($this->isMountPointApplicableToUser($mount)) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- /**
- * check if mount point is applicable to user
- *
- * @param array $mount contains $mount['applicable']['users'], $mount['applicable']['groups']
- * @return boolean
- */
- protected function isMountPointApplicableToUser($mount) {
- $uid = \OCP\User::getUser();
- $acceptedUids = array('all', $uid);
- // check if mount point is applicable for the user
- $intersection = array_intersect($acceptedUids, $mount['applicable']['users']);
- if (!empty($intersection)) {
- return true;
- }
- // check if mount point is applicable for group where the user is a member
- foreach ($mount['applicable']['groups'] as $gid) {
- if (\OC_Group::inGroup($uid, $gid)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * decrypt private key and add it to the current session
- * @param array $params with 'uid' and 'password'
- * @return mixed session or false
- */
- public function initEncryption($params) {
-
- $session = new Session($this->view);
-
- // we tried to initialize the encryption app for this session
- $session->setInitialized(Session::INIT_EXECUTED);
-
- $encryptedKey = Keymanager::getPrivateKey($this->view, $params['uid']);
-
- $privateKey = false;
- if ($encryptedKey) {
- $privateKey = Crypt::decryptPrivateKey($encryptedKey, $params['password']);
- }
-
- if ($privateKey === false) {
- \OCP\Util::writeLog('Encryption library', 'Private key for user "' . $params['uid']
- . '" is not valid! Maybe the user password was changed from outside if so please change it back to gain access', \OCP\Util::ERROR);
- return false;
- }
-
- $session->setPrivateKey($privateKey);
- $session->setInitialized(Session::INIT_SUCCESSFUL);
-
- return $session;
- }
-
- /*
- * remove encryption related keys from the session
- */
- public function closeEncryptionSession() {
- $session = new Session($this->view);
- $session->closeSession();
- }
-
-}