/** * 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; }
/** * @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; 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); $this->readHeader(); } if ($this->isLocalTmpFile) { $this->handle = fopen($this->localTmpFile, $mode); } else { $this->handle = $this->rootView->fopen($this->rawPath, $mode); } \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); }
/** * @dataProvider dataStripUserFilesPath */ function testStripUserFilesPath($path, $expected) { $result = Helper::stripUserFilesPath($path); $this->assertSame($expected, $result); }
/** * @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; if (!isset($this->rootView)) { $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)); if ($originalFile = Helper::getPathFromTmpFile($normalizedPath)) { $this->rawPath = $originalFile; $this->isLocalTmpFile = true; $this->localTmpFile = $normalizedPath; } else { $this->rawPath = $normalizedPath; } $this->userId = Helper::getUser($this->rawPath); $util = new Util($this->rootView, $this->userId); // get the key ID which we want to use, can be the users key or the // public share key $this->keyId = $util->getKeyId(); // Strip identifier text from path, this gives us the path relative to data/<user>/files $this->relPath = Helper::stripUserFilesPath($this->rawPath); // if raw path doesn't point to a real file, check if it is a version or a file in the trash bin if ($this->relPath === false) { $this->relPath = Helper::getPathToRealFile($this->rawPath); } if ($this->relPath === false) { \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; 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 { if ($this->privateKey === false) { // if private key is not valid redirect user to a error page Helper::redirectToErrorPage($this->session); } $this->size = $this->rootView->filesize($this->rawPath); $this->readHeader(); } if ($this->isLocalTmpFile) { $this->handle = fopen($this->localTmpFile, $mode); } else { $this->handle = $this->rootView->fopen($this->rawPath, $mode); } \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); }