* @return true / false\r
* @note see also OCA\Encryption\Util->isEncryptedPath()\r
*/\r
- public static function isCatfile( $content ) {\r
+ public static function isCatfileContent( $content ) {\r
\r
if ( !$content ) {\r
\r
if ( \r
isset( $metadata['encrypted'] ) \r
and $metadata['encrypted'] === true \r
- and ! self::isCatfile( $data ) \r
+ and ! self::isCatfileContent( $data ) \r
) {\r
\r
return true;\r
}
- if ( Crypt::isCatfile( $path ) ) {
+ if ( Crypt::isCatfileContent( $path ) ) {
return true;
// If data is a catfile
if (
Crypt::mode() == 'server'
- && Crypt::isCatfile( $data )
+ && Crypt::isCatfileContent( $data )
) {
// TODO use get owner to find correct location of key files for shared files
public function postGetMimeType( $path, $mime ) {
- if ( Crypt::isCatfile( $path ) ) {
+ if ( Crypt::isCatfileContent( $path ) ) {
$mime = \OCP\Files::getMimeType( 'crypt://' . $path, 'w' );
public function postStat( $path, $data ) {
- if ( Crypt::isCatfile( $path ) ) {
+ if ( Crypt::isCatfileContent( $path ) ) {
$cached = \OC\Files\Filesystem::getFileInfo( $path, '' );
public function postFileSize( $path, $size ) {
- if ( Crypt::isCatfile( $path ) ) {
+ if ( Crypt::isCatfileContent( $path ) ) {
$cached = \OC\Files\Filesystem::getFileInfo( $path, '' );
private $rootView; // a fsview object set to '/'
public function stream_open( $path, $mode, $options, &$opened_path ) {
-
- $this->userId = \OCP\User::getUser();
- // Get access to filesystem via filesystemview object
- if ( !self::$view ) {
-
- self::$view = new \OC_FilesystemView( $this->userId . '/' );
-
- }
+ $this->userId = \OCP\User::getUser();
- // Set rootview object if necessary
- if ( ! $this->rootView ) {
+ if ( ! isset( $this->rootView ) ) {
- $this->rootView = new \OC_FilesystemView( $this->userId . '/' );
+ $this->rootView = new \OC_FilesystemView( '/' );
}
- // Get the bare file path
- $path = str_replace( 'crypt://', '', $path );
+ // Strip identifier text from path
+ $this->rawPath = str_replace( 'crypt://', '', $path );
- $this->rawPath = $path;
-
- $this->path_f = $this->userId . '/files/' . $path;
+ // Set file path relative to user files dir
+ $this->relPath = $this->userId . '/files/' . $this->rawPath;
if (
- dirname( $path ) == 'streams'
- and isset( self::$sourceStreams[basename( $path )] )
+ dirname( $this->rawPath ) == 'streams'
+ and isset( self::$sourceStreams[basename( $this->rawPath )] )
) {
// Is this just for unit testing purposes?
- $this->handle = self::$sourceStreams[basename( $path )]['stream'];
+ $this->handle = self::$sourceStreams[basename( $this->rawPath )]['stream'];
- $this->path = self::$sourceStreams[basename( $path )]['path'];
+ $this->path = self::$sourceStreams[basename( $this->rawPath )]['path'];
- $this->size = self::$sourceStreams[basename( $path )]['size'];
+ $this->size = self::$sourceStreams[basename( $this->rawPath )]['size'];
} else {
or $mode == 'wb+'
) {
+ // We're writing a new file so start write counter with 0 bytes
$this->size = 0;
} else {
+ $this->size = $this->rootView->filesize( $this->relPath, $mode );
-
- $this->size = self::$view->filesize( $this->path_f, $mode );
-
- //$this->size = filesize( $path );
+ //$this->size = filesize( $this->rawPath );
}
// Disable fileproxies so we can open the source file without recursive encryption
\OC_FileProxy::$enabled = false;
- //$this->handle = fopen( $path, $mode );
+ //$this->handle = fopen( $this->rawPath, $mode );
- $this->handle = self::$view->fopen( $this->path_f, $mode );
+ $this->handle = $this->rootView->fopen( $this->relPath, $mode );
\OC_FileProxy::$enabled = true;
- if ( !is_resource( $this->handle ) ) {
+ if ( ! is_resource( $this->handle ) ) {
- \OCP\Util::writeLog( 'files_encryption', 'failed to open '.$path, \OCP\Util::ERROR );
+ \OCP\Util::writeLog( 'files_encryption', 'failed to open file "'.$this->rootView . '"', \OCP\Util::ERROR );
+ } else {
+
+ $this->meta = stream_get_meta_data( $this->handle );
+
}
}
- if ( is_resource( $this->handle ) ) {
-
- $this->meta = stream_get_meta_data( $this->handle );
-
- }
-
return is_resource( $this->handle );
}
// If a keyfile already exists for a file named identically to
// file to be written
- if ( self::$view->file_exists( $this->userId . '/'. 'files_encryption' . '/' . 'keyfiles' . '/' . $this->rawPath . '.key' ) ) {
+ if ( $this->rootView->file_exists( $this->userId . '/'. 'files_encryption' . '/' . 'keyfiles' . '/' . $this->rawPath . '.key' ) ) {
// TODO: add error handling for when file exists but no
// keyfile
# Bugs
# ----
# Sharing a file to a user without encryption set up will not provide them with access but won't notify the sharer
-# When encryption app is disabled files become unreadable
# Timeouts on first login due to encryption of very large files
# Missing features
# ----------------
-# Re-use existing keyfiles so they don't need version control
+# Re-use existing keyfiles so they don't need version control (part implemented, stream{} and util{} remain)
# Make sure user knows if large files weren't encrypted
# Trashbin support
// will eat server resources :(
if (
Keymanager::getFileKey( $this->view, $this->userId, $file )
- && Crypt::isCatfile( $data )
+ && Crypt::isCatfileContent( $data )
) {
$found['encrypted'][] = array( 'name' => $file, 'path' => $filePath );
// If the file uses old
// encryption system
- } elseif ( Crypt::isLegacyEncryptedContent( $this->view->file_get_contents( $filePath ), $relPath ) ) {
+ } elseif ( Crypt::isLegacyEncryptedContent( $this->tail( $filePath, 3 ), $relPath ) ) {
$found['legacy'][] = array( 'name' => $file, 'path' => $filePath );
}
+ /**
+ * @brief Fetch the last lines of a file efficiently
+ * @note Safe to use on large files; does not read entire file to memory
+ * @note Derivative of http://tekkie.flashbit.net/php/tail-functionality-in-php
+ */
+ public function tail( $filename, $numLines ) {
+
+ \OC_FileProxy::$enabled = false;
+
+ $text = '';
+ $pos = -1;
+ $handle = $this->view->fopen( $filename, 'r' );
+
+ while ( $numLines > 0 ) {
+
+ --$pos;
+
+ if( fseek( $handle, $pos, SEEK_END ) !== 0 ) {
+
+ rewind( $handle );
+ $numLines = 0;
+
+ } elseif ( fgetc( $handle ) === "\n" ) {
+
+ --$numLines;
+
+ }
+
+ $block_size = ( -$pos ) % 8192;
+ if ( $block_size === 0 || $numLines === 0 ) {
+
+ $text = fread( $handle, ( $block_size === 0 ? 8192 : $block_size ) ) . $text;
+
+ }
+ }
+
+ fclose( $handle );
+
+ \OC_FileProxy::$enabled = true;
+
+ return $text;
+ }
+
/**
* @brief Check if a given path identifies an encrypted file
* @return true / false
\OC_FileProxy::$enabled = true;
- return Crypt::isCatfile( $data );
+ return Crypt::isCatfileContent( $data );
}
// Encrypt unencrypted files
foreach ( $found['plain'] as $plainFile ) {
+
+ // Open plain file handle
+
+
+ // Open enc file handle
+
- // Fetch data from file
- $plainData = $this->view->file_get_contents( $plainFile['path'] );
+ // Read plain file in chunks
- // Encrypt data, generate catfile
- $encrypted = Crypt::keyEncryptKeyfile( $plainData, $publicKey );
$relPath = $this->stripUserFilesPath( $plainFile['path'] );
- // Save keyfile
- Keymanager::setFileKey( $this->view, $relPath, $this->userId, $encrypted['key'] );
+ // Open handle with for binary reading
+ $plainHandle = $this->view->fopen( $plainFile['path'], 'rb' );
+ // Open handle with for binary writing
+ $encHandle = fopen( 'crypt://' . 'var/www/oc6/data/' . $plainFile['path'] . '.tmp', 'ab' );
// Overwrite the existing file with the encrypted one
- $this->view->file_put_contents( $plainFile['path'], $encrypted['data'] );
+ //$this->view->file_put_contents( $plainFile['path'], $encrypted['data'] );
+ $size = stream_copy_to_stream( $plainHandle, $encHandle );
+
+ // Fetch the key that has just been set/updated by the stream
+ $encKey = Keymanager::getFileKey( $relPath );
- $size = strlen( $encrypted['data'] );
+ // Save keyfile
+ Keymanager::setFileKey( $this->view, $relPath, $this->userId, $encKey );
// Add the file to the cache
\OC\Files\Filesystem::putFileInfo( $plainFile['path'], array( 'encrypted'=>true, 'size' => $size ), '' );
function testIsEncryptedContent() {
- $this->assertFalse( Encryption\Crypt::isCatfile( $this->dataUrl ) );
+ $this->assertFalse( Encryption\Crypt::isCatfileContent( $this->dataUrl ) );
- $this->assertFalse( Encryption\Crypt::isCatfile( $this->legacyEncryptedData ) );
+ $this->assertFalse( Encryption\Crypt::isCatfileContent( $this->legacyEncryptedData ) );
$keyfileContent = Encryption\Crypt::symmetricEncryptFileContent( $this->dataUrl, 'hat' );
- $this->assertTrue( Encryption\Crypt::isCatfile( $keyfileContent ) );
+ $this->assertTrue( Encryption\Crypt::isCatfileContent( $keyfileContent ) );
}