1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594 |
- <?php
- /**
- * ownCloud
- *
- * @copyright (C) 2014 ownCloud, Inc.
- *
- * @author Sam Tuke <samtuke@owncloud.com>,
- * @author Frank Karlitschek <frank@owncloud.org>,
- * @author Bjoern Schiessle <schiessle@owncloud.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
- namespace OCA\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
-
- private $view; // OC\Files\View object for filesystem operations
- private $userId; // ID of the user we use to encrypt/decrypt files
- private $keyId; // ID of the key we want to manipulate
- private $client; // Client side encryption mode flag
- private $publicKeyDir; // Dir containing all public user keys
- private $encryptionDir; // Dir containing user's files_encryption
- private $keysPath; // Dir containing all file related encryption keys
- private $publicKeyPath; // Path to user's public key
- private $privateKeyPath; // Path to user's private key
- private $userFilesDir;
- private $publicShareKeyId;
- private $recoveryKeyId;
- 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 (\OCA\Encryption\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 !== "..") {
-
- $filePath = $directory . '/' . $this->view->getRelativePath('/' . $file);
- $relPath = \OCA\Encryption\Helper::stripUserFilesPath($filePath);
-
- // If the path is a directory, search
- // its contents
- if ($this->view->is_dir($filePath)) {
-
- $this->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 = \OCA\Encryption\Helper::stripUserFilesPath($path);
- $shareKey = Keymanager::getShareKey($this->view, $this->keyId, $this, $relPath);
- if($shareKey===false) {
- \OC_FileProxy::$enabled = $proxyStatus;
- return $result;
- }
- $session = new \OCA\Encryption\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');
- $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 = \OCA\Encryption\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']) {
- $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) {
- $filename = $path;
- $fileOwnerUid = $this->userId;
-
- return array(
- $fileOwnerUid,
- $filename
- );
- } else {
-
- // Check that UID is valid
- if (!\OCP\User::userExists($fileOwnerUid)) {
- throw new \Exception(
- 'Could not find owner (UID = "' . var_export($fileOwnerUid, 1) . '") of file "' . $path . '"');
- }
-
- // NOTE: Bah, this dependency should be elsewhere
- \OC\Files\Filesystem::initMountPoints($fileOwnerUid);
-
- // If the file owner is the currently logged in user
- if ($fileOwnerUid === $this->userId) {
-
- // Assume the path supplied is correct
- $filename = $path;
-
- } else {
- $info = $view->getFileInfo($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 \OCA\Encryption\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 (optional) define the purpose of the backup, will be part of the backup folder
- */
- public function backupAllKeys($purpose = '') {
- $this->userId;
- $backupDir = $this->encryptionDir . '/backup.';
- $backupDir .= ($purpose === '') ? date("Y-m-d_H-i-s") . '/' : $purpose . '.' . date("Y-m-d_H-i-s") . '/';
- $this->view->mkdir($backupDir);
- $this->view->copy($this->keysPath, $backupDir . 'keys/');
- $this->view->copy($this->privateKeyPath, $backupDir . $this->userId . '.privateKey');
- $this->view->copy($this->publicKeyPath, $backupDir . $this->userId . '.publicKey');
- }
-
- /**
- * 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 \OCA\Encryption\Session($this->view);
-
- // we tried to initialize the encryption app for this session
- $session->setInitialized(\OCA\Encryption\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(\OCA\Encryption\Session::INIT_SUCCESSFUL);
-
- return $session;
- }
-
- /*
- * remove encryption related keys from the session
- */
- public function closeEncryptionSession() {
- $session = new \OCA\Encryption\Session($this->view);
- $session->closeSession();
- }
-
- }
|