Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Schießle <schiessle@owncloud.com>2013-12-19 19:09:07 +0400
committerBjörn Schießle <schiessle@owncloud.com>2013-12-19 19:09:07 +0400
commit079f1a6f4146ee181995084e7c4c43a6bbe0082c (patch)
tree7b25e140394dc6d9ca44da1f1bf36a0f9f8d5acf
parentae3df84e207f9bcac1b12923319c18fd80d5252d (diff)
parentdf0c1fe7f3abb0a7ec584cf64c19091bf86e1906 (diff)
Merge pull request #6495 from owncloud/enc_fseek_fallback
Added fseek fallback to the encryption app
-rwxr-xr-xapps/files_encryption/lib/helper.php24
-rw-r--r--apps/files_encryption/lib/stream.php38
-rw-r--r--apps/files_encryption/lib/util.php33
-rw-r--r--apps/files_encryption/tests/stream.php39
-rwxr-xr-xapps/files_encryption/tests/util.php35
5 files changed, 159 insertions, 10 deletions
diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php
index 17bcac5c585..f893cf16e5a 100755
--- a/apps/files_encryption/lib/helper.php
+++ b/apps/files_encryption/lib/helper.php
@@ -29,6 +29,8 @@ namespace OCA\Encryption;
*/
class Helper {
+ private static $tmpFileMapping; // Map tmp files to files in data/user/files
+
/**
* @brief register share related hooks
*
@@ -423,5 +425,27 @@ class Helper {
public static function escapeGlobPattern($path) {
return preg_replace('/(\*|\?|\[)/', '[$1]', $path);
}
+
+ /**
+ * @brief 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;
+ }
+
+ /**
+ * @brief get the path of the original file
+ * @param string $tmpFile path of the tmp file
+ * @return mixed path of the original file or false
+ */
+ public static function getPathFromTmpFile($tmpFile) {
+ if (isset(self::$tmpFileMapping[$tmpFile])) {
+ return self::$tmpFileMapping[$tmpFile];
+ }
+
+ return false;
+ }
}
diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php
index 7a37d2200a4..b3bf34ddb82 100644
--- a/apps/files_encryption/lib/stream.php
+++ b/apps/files_encryption/lib/stream.php
@@ -64,6 +64,9 @@ class Stream {
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
+
/**
* @var \OC\Files\View
*/
@@ -91,13 +94,18 @@ class Stream {
$this->rootView = new \OC_FilesystemView('/');
}
-
$this->session = new \OCA\Encryption\Session($this->rootView);
$this->privateKey = $this->session->getPrivateKey();
- // rawPath is relative to the data directory
- $this->rawPath = \OC\Files\Filesystem::normalizePath(str_replace('crypt://', '', $path));
+ $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);
@@ -141,10 +149,14 @@ class Stream {
\OCA\Encryption\Helper::redirectToErrorPage($this->session);
}
- $this->size = $this->rootView->filesize($this->rawPath, $mode);
+ $this->size = $this->rootView->filesize($this->rawPath);
}
- $this->handle = $this->rootView->fopen($this->rawPath, $mode);
+ if ($this->isLocalTmpFile) {
+ $this->handle = fopen($this->localTmpFile, $mode);
+ } else {
+ $this->handle = $this->rootView->fopen($this->rawPath, $mode);
+ }
\OC_FileProxy::$enabled = $proxyStatus;
@@ -164,14 +176,25 @@ class Stream {
}
/**
+ * @brief Returns the current position of the file pointer
+ * @return int position of the file pointer
+ */
+ public function stream_tell() {
+ return ftell($this->handle);
+ }
+
+ /**
* @param $offset
* @param int $whence
+ * @return bool true if fseek was successful, otherwise false
*/
public function stream_seek($offset, $whence = SEEK_SET) {
$this->flush();
- fseek($this->handle, $offset, $whence);
+ // this wrapper needs to return "true" for success.
+ // the fseek call itself returns 0 on succeess
+ return !fseek($this->handle, $offset, $whence);
}
@@ -477,7 +500,7 @@ class Stream {
if ($this->privateKey === false) {
// cleanup
- if ($this->meta['mode'] !== 'r' && $this->meta['mode'] !== 'rb') {
+ if ($this->meta['mode'] !== 'r' && $this->meta['mode'] !== 'rb' && !$this->isLocalTmpFile) {
// Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
@@ -498,6 +521,7 @@ class Stream {
if (
$this->meta['mode'] !== 'r' &&
$this->meta['mode'] !== 'rb' &&
+ $this->isLocalTmpFile === false &&
$this->size > 0 &&
$this->unencryptedSize > 0
) {
diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php
index a3852312200..6007d4e0e2e 100644
--- a/apps/files_encryption/lib/util.php
+++ b/apps/files_encryption/lib/util.php
@@ -429,8 +429,22 @@ class Util {
// we only need 24 byte from the last chunk
$data = '';
$handle = $this->view->fopen($path, 'r');
- if (is_resource($handle) && !fseek($handle, -24, SEEK_END)) {
- $data = fgets($handle);
+ 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
@@ -482,7 +496,20 @@ class Util {
$lastChunckPos = ($lastChunkNr * 8192);
// seek to end
- fseek($stream, $lastChunckPos);
+ if (@fseek($stream, $lastChunckPos) === -1) {
+ // storage doesn't support fseek, we need a local copy
+ fclose($stream);
+ $localFile = $this->view->getLocalFile($path);
+ Helper::addTmpFileToMapper($localFile, $path);
+ $stream = fopen('crypt://' . $localFile, "r");
+ if (fseek($stream, $lastChunckPos) === -1) {
+ // if fseek also fails on the local storage, than
+ // there is nothing we can do
+ fclose($stream);
+ \OCP\Util::writeLog('Encryption library', 'couldn\'t determine size of "' . $path, \OCP\Util::ERROR);
+ return $result;
+ }
+ }
// get the content of the last chunk
$lastChunkContent = fread($stream, $lastChunkSize);
diff --git a/apps/files_encryption/tests/stream.php b/apps/files_encryption/tests/stream.php
index 530ee3a7b2d..2767bbe512b 100644
--- a/apps/files_encryption/tests/stream.php
+++ b/apps/files_encryption/tests/stream.php
@@ -180,4 +180,43 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
// tear down
$view->unlink($filename);
}
+
+ /**
+ * @medium
+ * @brief test if stream wrapper can read files outside from the data folder
+ */
+ function testStreamFromLocalFile() {
+
+ $filename = '/' . $this->userId . '/files/' . 'tmp-' . time().'.txt';
+
+ $tmpFilename = "/tmp/" . time() . ".txt";
+
+ // write an encrypted file
+ $cryptedFile = $this->view->file_put_contents($filename, $this->dataShort);
+
+ // Test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile));
+
+ // create a copy outside of the data folder in /tmp
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+ $encryptedContent = $this->view->file_get_contents($filename);
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ file_put_contents($tmpFilename, $encryptedContent);
+
+ \OCA\Encryption\Helper::addTmpFileToMapper($tmpFilename, $filename);
+
+ // try to read the file from /tmp
+ $handle = fopen("crypt://".$tmpFilename, "r");
+ $contentFromTmpFile = stream_get_contents($handle);
+
+ // check if it was successful
+ $this->assertEquals($this->dataShort, $contentFromTmpFile);
+
+ // clean up
+ unlink($tmpFilename);
+ $this->view->unlink($filename);
+
+ }
}
diff --git a/apps/files_encryption/tests/util.php b/apps/files_encryption/tests/util.php
index e8dfb74f3f3..7d425dc122a 100755
--- a/apps/files_encryption/tests/util.php
+++ b/apps/files_encryption/tests/util.php
@@ -134,6 +134,41 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
/**
* @medium
+ * @brief test detection of encrypted files
+ */
+ function testIsEncryptedPath() {
+
+ $util = new Encryption\Util($this->view, $this->userId);
+
+ self::loginHelper($this->userId);
+
+ $unencryptedFile = '/tmpUnencrypted-' . time() . '.txt';
+ $encryptedFile = '/tmpEncrypted-' . time() . '.txt';
+
+ // Disable encryption proxy to write a unencrypted file
+ $proxyStatus = \OC_FileProxy::$enabled;
+ \OC_FileProxy::$enabled = false;
+
+ $this->view->file_put_contents($this->userId . '/files/' . $unencryptedFile, $this->dataShort);
+
+ // Re-enable proxy - our work is done
+ \OC_FileProxy::$enabled = $proxyStatus;
+
+ // write a encrypted file
+ $this->view->file_put_contents($this->userId . '/files/' . $encryptedFile, $this->dataShort);
+
+ // test if both files are detected correctly
+ $this->assertFalse($util->isEncryptedPath($this->userId . '/files/' . $unencryptedFile));
+ $this->assertTrue($util->isEncryptedPath($this->userId . '/files/' . $encryptedFile));
+
+ // cleanup
+ $this->view->unlink($this->userId . '/files/' . $unencryptedFile, $this->dataShort);
+ $this->view->unlink($this->userId . '/files/' . $encryptedFile, $this->dataShort);
+
+ }
+
+ /**
+ * @medium
* @brief test setup of encryption directories
*/
function testSetupServerSide() {