From b6ed61eab2fce2de3653b376bef0eeddd431562a Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 21 Oct 2011 15:17:39 +0200 Subject: [PATCH 001/167] pass paramters to file proxies by reference so they can be modified --- lib/fileproxy.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/fileproxy.php b/lib/fileproxy.php index 235fc8bf28..7e0722b960 100644 --- a/lib/fileproxy.php +++ b/lib/fileproxy.php @@ -88,11 +88,11 @@ class OC_FileProxy{ $operation='pre'.$operation; foreach($proxies as $proxy){ if($filepath2){ - if(!$proxy->$operation($filepath,$filepath2)){ + if(!$proxy->$operation(&$filepath,&$filepath2)){ return false; } }else{ - if(!$proxy->$operation($filepath)){ + if(!$proxy->$operation(&$filepath)){ return false; } } From abc749feeb14c49d483135f879195b70ee89654f Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 21 Oct 2011 17:01:41 +0200 Subject: [PATCH 002/167] make documentation reflect reality a bit better --- lib/fileproxy.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fileproxy.php b/lib/fileproxy.php index 7e0722b960..1fb22bd113 100644 --- a/lib/fileproxy.php +++ b/lib/fileproxy.php @@ -34,7 +34,7 @@ * A post-proxy recieves 2 arguments, the filepath and the result of the operation. * The return calue of the post-proxy will be used as the new result of the operation * The operations that have a post-proxy are - * file_get_contents, is_file, is_dir, file_exists, stat, is_readable, is_writable, filemtime, filectime, file_get_contents, getMimeType, hash, free_space and search + * file_get_contents, is_file, is_dir, file_exists, stat, is_readable, is_writable, fileatime, filemtime, filectime, file_get_contents, getMimeType, hash, fopen, free_space and search */ class OC_FileProxy{ From 3d67cd51c2f42029435343004b3ebe608bcba375 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 21 Oct 2011 17:02:11 +0200 Subject: [PATCH 003/167] encryption proxy wip --- apps/files_encryption/appinfo/app.php | 11 ++ apps/files_encryption/lib/cryptstream.php | 121 ++++++++++++++++++++++ apps/files_encryption/lib/proxy.php | 70 +++++++++++++ lib/crypt.php | 39 +++++-- lib/fileproxy.php | 8 +- lib/filestorage/local.php | 2 +- lib/filesystemview.php | 2 +- 7 files changed, 239 insertions(+), 14 deletions(-) create mode 100644 apps/files_encryption/appinfo/app.php create mode 100644 apps/files_encryption/lib/cryptstream.php create mode 100644 apps/files_encryption/lib/proxy.php diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php new file mode 100644 index 0000000000..82d2544dd1 --- /dev/null +++ b/apps/files_encryption/appinfo/app.php @@ -0,0 +1,11 @@ +. + * + */ + +/** + * transparently encrypted filestream + */ + +class OC_CryptStream{ + private $source; + + public function stream_open($path, $mode, $options, &$opened_path){ + $path=str_replace('crypt://','',$path); + $this->source=OC_FileSystem::fopen($path.'.enc',$mode); + if(!is_resource($this->source)){ + OC_Log::write('files_encryption','failed to open '.$path.'.enc',OC_Log::ERROR); + } + return is_resource($this->source); + } + + public function stream_seek($offset, $whence=SEEK_SET){ + fseek($this->source,$offset,$whence); + } + + public function stream_tell(){ + return ftell($this->source); + } + + public function stream_read($count){ + $pos=0; + $currentPos=ftell($this->source); + $offset=$currentPos%8192; + fseek($this->source,-$offset,SEEK_CUR); + $result=''; + while($count>$pos){ + $data=fread($this->source,8192); + $pos+=8192; + $result.=OC_Crypt::decrypt($data); + } + return substr($result,$offset,$count); + } + + public function stream_write($data){ + $length=strlen($data); + $written=0; + $currentPos=ftell($this->source); + if($currentPos%8192!=0){ + //make sure we always start on a block start + fseek($this->source,-($currentPos%8192),SEEK_CUR); + $encryptedBlock=fread($this->source,8192); + fseek($this->source,-($currentPos%8192),SEEK_CUR); + $block=OC_Crypt::decrypt($encryptedBlock); + $data=substr($block,0,$currentPos%8192).$data; + } + while(strlen($data)>0){ + if(strlen($data)<8192){ + //fetch the current data in that block and append it to the input so we always write entire blocks + $oldPos=ftell($this->source); + $encryptedBlock=fread($this->source,8192); + fseek($this->source,$oldPos); + $block=OC_Crypt::decrypt($encryptedBlock); + $data.=substr($block,strlen($data)); + } + $encrypted=OC_Crypt::encrypt(substr($data,0,8192)); + fwrite($this->source,$encrypted); + $data=substr($data,8192); + } + return $length; + } + + public function stream_set_option($option,$arg1,$arg2){ + switch($option){ + case STREAM_OPTION_BLOCKING: + stream_set_blocking($this->source,$arg1); + break; + case STREAM_OPTION_READ_TIMEOUT: + stream_set_timeout($this->source,$arg1,$arg2); + break; + case STREAM_OPTION_WRITE_BUFFER: + stream_set_write_buffer($this->source,$arg1,$arg2); + } + } + + public function stream_stat(){ + return fstat($this->source); + } + + public function stream_lock($mode){ + flock($this->source,$mode); + } + + public function stream_flush(){ + return fflush($this->source); + } + + public function stream_eof(){ + return feof($this->source); + } + + public function stream_close(){ + return fclose($this->source); + } +} \ No newline at end of file diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php new file mode 100644 index 0000000000..f7a991a344 --- /dev/null +++ b/apps/files_encryption/lib/proxy.php @@ -0,0 +1,70 @@ +. +* +*/ + +/** + * transparent encryption + */ + +class OC_FileProxy_Encryption extends OC_FileProxy{ + public function preFile_put_contents($path,&$data){ + if(substr($path,-4)=='.enc'){ + OC_Log::write('files_encryption','file put contents',OC_Log::DEBUG); + if (is_resource($data)) { + $newData=''; + while(!feof($data)){ + $block=fread($data,8192); + $newData.=OC_Crypt::encrypt($block); + } + $data=$newData; + }else{ + $data=OC_Crypt::blockEncrypt($data); + } + } + } + + public function postFile_get_contents($path,$data){ + if(substr($path,-4)=='.enc'){ + OC_Log::write('files_encryption','file get contents',OC_Log::DEBUG); + return OC_Crypt::blockDecrypt($data); + } + } + + public function postFopen($path,&$result){ + if(substr($path,-4)=='.enc'){ + OC_Log::write('files_encryption','fopen',OC_Log::DEBUG); + fclose($result); + $result=fopen('crypt://'.substr($path,0,-4));//remove the .enc extention so we don't catch the fopen request made by cryptstream + } + } + + public function preReadFile($path){ + if(substr($path,-4)=='.enc'){ + OC_Log::write('files_encryption','readline',OC_Log::DEBUG); + $stream=fopen('crypt://'.substr($path,0,-4)); + while(!feof($stream)){ + print(fread($stream,8192)); + } + return false;//cancel the original request + } + } +} diff --git a/lib/crypt.php b/lib/crypt.php index 6002067948..3e6fa05b85 100644 --- a/lib/crypt.php +++ b/lib/crypt.php @@ -113,14 +113,13 @@ class OC_Crypt { return($bf->encrypt($contents)); } - - /** - * @brief encryption of a file - * @param $filename - * @param $key the encryption key - * - * This function encrypts a file - */ + /** + * @brief encryption of a file + * @param $filename + * @param $key the encryption key + * + * This function encrypts a file + */ public static function encryptfile( $filename, $key) { $handleread = fopen($filename, "rb"); if($handleread<>FALSE) { @@ -158,6 +157,30 @@ class OC_Crypt { } fclose($handleread); } + + /** + * encrypt data in 8192b sized blocks + */ + public static function blockEncrypt($data){ + $result=''; + while(strlen($data)){ + $result=self::encrypt(substr($data,0,8192)); + $data=substr($data,8192); + } + return $result; + } + + /** + * decrypt data in 8192b sized blocks + */ + public static function blockDecrypt($data){ + $result=''; + while(strlen($data)){ + $result=self::decrypt(substr($data,0,8192)); + $data=substr($data,8192); + } + return $result; + } diff --git a/lib/fileproxy.php b/lib/fileproxy.php index 1fb22bd113..796fd95cb3 100644 --- a/lib/fileproxy.php +++ b/lib/fileproxy.php @@ -83,16 +83,16 @@ class OC_FileProxy{ return $proxies; } - public static function runPreProxies($operation,$filepath,$filepath2=null){ + public static function runPreProxies($operation,&$filepath,&$filepath2=null){ $proxies=self::getProxies($operation,false); $operation='pre'.$operation; foreach($proxies as $proxy){ - if($filepath2){ - if(!$proxy->$operation(&$filepath,&$filepath2)){ + if(!is_null($filepath2)){ + if($proxy->$operation($filepath,$filepath2)===false){ return false; } }else{ - if(!$proxy->$operation(&$filepath)){ + if($proxy->$operation($filepath)===false){ return false; } } diff --git a/lib/filestorage/local.php b/lib/filestorage/local.php index dcb516a3af..ee4b267bcd 100644 --- a/lib/filestorage/local.php +++ b/lib/filestorage/local.php @@ -74,7 +74,7 @@ class OC_Filestorage_Local extends OC_Filestorage{ public function file_get_contents($path){ return file_get_contents($this->datadir.$path); } - public function file_put_contents($path,$data){ + public function file_put_contents($path,$data=null){ if($return=file_put_contents($this->datadir.$path,$data)){ } } diff --git a/lib/filesystemview.php b/lib/filesystemview.php index 91c6cd1772..a78f3f652a 100644 --- a/lib/filesystemview.php +++ b/lib/filesystemview.php @@ -302,7 +302,7 @@ class OC_FilesystemView { } } if($run){ - if($extraParam){ + if(!is_null($extraParam)){ $result=$storage->$operation($interalPath,$extraParam); }else{ $result=$storage->$operation($interalPath); From 82394f9527817673f3ecbf7e5fd1d4857f0f3fe1 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 22 Oct 2011 14:10:51 +0200 Subject: [PATCH 004/167] add option to dissable fileproxies --- lib/fileproxy.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/fileproxy.php b/lib/fileproxy.php index 796fd95cb3..46fc2f49c5 100644 --- a/lib/fileproxy.php +++ b/lib/fileproxy.php @@ -39,6 +39,7 @@ class OC_FileProxy{ private static $proxies=array(); + public static $enabled=true; /** * check if this proxy implments a specific proxy operation @@ -84,6 +85,9 @@ class OC_FileProxy{ } public static function runPreProxies($operation,&$filepath,&$filepath2=null){ + if(!self::$enabled){ + return true; + } $proxies=self::getProxies($operation,false); $operation='pre'.$operation; foreach($proxies as $proxy){ @@ -101,6 +105,9 @@ class OC_FileProxy{ } public static function runPostProxies($operation,$path,$result){ + if(!self::$enabled){ + return $result; + } $proxies=self::getProxies($operation,true); $operation='post'.$operation; foreach($proxies as $proxy){ From e2b49541760dabbdfce11bcc8063d31139b6caa3 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 22 Oct 2011 14:11:15 +0200 Subject: [PATCH 005/167] simple file encryption wip --- apps/files_encryption/lib/cryptstream.php | 7 +++++-- apps/files_encryption/lib/proxy.php | 17 +++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/apps/files_encryption/lib/cryptstream.php b/apps/files_encryption/lib/cryptstream.php index e4544313f6..7fbfeaa7a8 100644 --- a/apps/files_encryption/lib/cryptstream.php +++ b/apps/files_encryption/lib/cryptstream.php @@ -29,9 +29,12 @@ class OC_CryptStream{ public function stream_open($path, $mode, $options, &$opened_path){ $path=str_replace('crypt://','',$path); - $this->source=OC_FileSystem::fopen($path.'.enc',$mode); + OC_Log::write('files_encryption','open encrypted '.$path. ' in '.$mode,OC_Log::DEBUG); + OC_FileProxy::$enabled=false;//disable fileproxies so we can open the source file + $this->source=OC_FileSystem::fopen($path,$mode); + OC_FileProxy::$enabled=true; if(!is_resource($this->source)){ - OC_Log::write('files_encryption','failed to open '.$path.'.enc',OC_Log::ERROR); + OC_Log::write('files_encryption','failed to open '.$path,OC_Log::ERROR); } return is_resource($this->source); } diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index f7a991a344..053ac786c3 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -28,7 +28,6 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ public function preFile_put_contents($path,&$data){ if(substr($path,-4)=='.enc'){ - OC_Log::write('files_encryption','file put contents',OC_Log::DEBUG); if (is_resource($data)) { $newData=''; while(!feof($data)){ @@ -44,27 +43,33 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ public function postFile_get_contents($path,$data){ if(substr($path,-4)=='.enc'){ - OC_Log::write('files_encryption','file get contents',OC_Log::DEBUG); return OC_Crypt::blockDecrypt($data); } } public function postFopen($path,&$result){ if(substr($path,-4)=='.enc'){ - OC_Log::write('files_encryption','fopen',OC_Log::DEBUG); + $meta=stream_get_meta_data($result); fclose($result); - $result=fopen('crypt://'.substr($path,0,-4));//remove the .enc extention so we don't catch the fopen request made by cryptstream + OC_log::write('file_encryption','mode: '.$meta['mode']); + $result=fopen('crypt://'.$path,$meta['mode']); } } public function preReadFile($path){ if(substr($path,-4)=='.enc'){ - OC_Log::write('files_encryption','readline',OC_Log::DEBUG); - $stream=fopen('crypt://'.substr($path,0,-4)); + $stream=fopen('crypt://'.$path,'r'); while(!feof($stream)){ print(fread($stream,8192)); } return false;//cancel the original request } } + + public function postGetMimeType($path,$result){ + if(substr($path,-4)=='.enc'){ + return 'text/plain'; + } + return $result; + } } From e9af2185625f5012067cd5fe2ee04cee9828f11b Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sun, 5 Feb 2012 20:49:32 +0100 Subject: [PATCH 006/167] use streams instead of temporary files for cross-storage copy and rename --- lib/filesystemview.php | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/filesystemview.php b/lib/filesystemview.php index a78f3f652a..27552d25f2 100644 --- a/lib/filesystemview.php +++ b/lib/filesystemview.php @@ -179,9 +179,13 @@ class OC_FilesystemView { if($storage=$this->getStorage($path1)){ $result=$storage->rename($this->getInternalPath($path1),$this->getInternalPath($path2)); } - }elseif($storage1=$this->getStorage($path1) and $storage2=$this->getStorage($path2)){ - $tmpFile=$storage1->toTmpFile($this->getInternalPath($path1)); - $result=$storage2->fromTmpFile($tmpFile,$this->getInternalPath($path2)); + }else{ + $source=$this->fopen($path1,'r'); + $target=$this->fopen($path2,'w'); + while (!feof($source)){ + fwrite($target,fread($source,8192)); + } + $storage1=$this->getStorage($path1); $storage1->unlink($this->getInternalPath($path1)); } OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_rename, array( OC_Filesystem::signal_param_oldpath => $path1, OC_Filesystem::signal_param_newpath=>$path2)); @@ -207,9 +211,14 @@ class OC_FilesystemView { if($storage=$this->getStorage($path1)){ $result=$storage->copy($this->getInternalPath($path1),$this->getInternalPath($path2)); } - }elseif($storage1=$this->getStorage($path1) and $storage2=$this->getStorage($path2)){ - $tmpFile=$storage1->toTmpFile($this->getInternalPath($path1)); - $result=$storage2->fromTmpFile($tmpFile,$this->getInternalPath($path2)); + }else{ + $source=$this->fopen($path1,'r'); + $target=$this->fopen($path2,'w'); + if($target and $source){ + while (!feof($source)){ + fwrite($target,fread($source,8192)); + } + } } OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_copy, array( OC_Filesystem::signal_param_oldpath => $path1 , OC_Filesystem::signal_param_newpath=>$path2)); if(!$exists){ From fd4b30ac6f81193cac1e558cc115802717aa88c1 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sun, 5 Feb 2012 20:50:35 +0100 Subject: [PATCH 007/167] no post hooks for fopen --- lib/filesystemview.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/filesystemview.php b/lib/filesystemview.php index 27552d25f2..a7003e84f1 100644 --- a/lib/filesystemview.php +++ b/lib/filesystemview.php @@ -317,9 +317,11 @@ class OC_FilesystemView { $result=$storage->$operation($interalPath); } $result=OC_FileProxy::runPostProxies($operation,$path,$result); - foreach($hooks as $hook){ - if($hook!='read'){ - OC_Hook::emit( OC_Filesystem::CLASSNAME, 'post_'.$hook, array( OC_Filesystem::signal_param_path => $path)); + if($operation!='fopen'){//no post hooks for fopen, the file stream is still open + foreach($hooks as $hook){ + if($hook!='read'){ + OC_Hook::emit( OC_Filesystem::CLASSNAME, 'post_'.$hook, array( OC_Filesystem::signal_param_path => $path)); + } } } return $result; From e53e7990c404e3ff2a1b7abad1e4c8ad4f89ee2a Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 22 Nov 2011 01:48:08 +0100 Subject: [PATCH 008/167] improve get_temp_dir() implementation --- lib/base.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/base.php b/lib/base.php index 880645ff79..5b6ed9bcb1 100644 --- a/lib/base.php +++ b/lib/base.php @@ -271,6 +271,8 @@ if(!function_exists('get_temp_dir')) { unlink($temp); return dirname($temp); } + if( $temp=sys_get_temp_dir()) return $temp; + return null; } } From f1cbb9effc7e0672dd9dd6fa810aba36c5749898 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 24 Nov 2011 01:44:54 +0100 Subject: [PATCH 009/167] initial integration of encryption --- apps/files_encryption/appinfo/info.xml | 11 +++ {lib => apps/files_encryption/lib}/crypt.php | 89 +++++++++++-------- apps/files_encryption/lib/cryptstream.php | 49 +++++++++-- apps/files_encryption/lib/proxy.php | 91 ++++++++++++++++---- lib/user.php | 3 +- 5 files changed, 178 insertions(+), 65 deletions(-) create mode 100644 apps/files_encryption/appinfo/info.xml rename {lib => apps/files_encryption/lib}/crypt.php (68%) diff --git a/apps/files_encryption/appinfo/info.xml b/apps/files_encryption/appinfo/info.xml new file mode 100644 index 0000000000..a8db06aa3d --- /dev/null +++ b/apps/files_encryption/appinfo/info.xml @@ -0,0 +1,11 @@ + + + files_encryption + Encryption + Server side encryption of files + 0.1 + AGPL + Robin Appelman + 3 + + diff --git a/lib/crypt.php b/apps/files_encryption/lib/crypt.php similarity index 68% rename from lib/crypt.php rename to apps/files_encryption/lib/crypt.php index 3e6fa05b85..4e7739b1d0 100644 --- a/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -37,20 +37,42 @@ require_once('Crypt_Blowfish/Blowfish.php'); * This class is for crypting and decrypting */ class OC_Crypt { + static private $bf = null; - static $encription_extension='.encrypted'; + public static function loginListener($params){ + self::init($params['uid'],$params['password']); + } public static function init($login,$password) { - $_SESSION['user_password'] = $password; // save the password as passcode for the encryption if(OC_User::isLoggedIn()){ - // does key exist? - if(!file_exists(OC_Config::getValue( "datadirectory").'/'.$login.'/encryption.key')){ - OC_Crypt::createkey($_SESSION['user_password']); + $view=new OC_FilesystemView('/'.$login); + if(!$view->file_exists('/encryption.key')){// does key exist? + OC_Crypt::createkey($password); } + $key=$view->file_get_contents('/encryption.key'); + $_SESSION['enckey']=OC_Crypt::decrypt($key, $password); } } - + /** + * get the blowfish encryption handeler for a key + * @param string $key (optional) + * + * if the key is left out, the default handeler will be used + */ + public static function getBlowfish($key=''){ + if($key){ + return new Crypt_Blowfish($key); + }else{ + if(!isset($_SESSION['enckey'])){ + return false; + } + if(!self::$bf){ + self::$bf=new Crypt_Blowfish($_SESSION['enckey']); + } + return self::$bf; + } + } public static function createkey($passcode) { if(OC_User::isLoggedIn()){ @@ -61,57 +83,58 @@ class OC_Crypt { $enckey=OC_Crypt::encrypt($key,$passcode); // Write the file - $username=OC_USER::getUser(); - @file_put_contents(OC_Config::getValue( "datadirectory").'/'.$username.'/encryption.key', $enckey ); + $username=OC_USER::getUser(); + OC_FileProxy::$enabled=false; + $view=new OC_FilesystemView('/'.$username); + $view->file_put_contents('/encryption.key',$enckey); + OC_FileProxy::$enabled=true; } } - public static function changekeypasscode( $newpasscode) { + public static function changekeypasscode($oldPassword, $newPassword) { if(OC_User::isLoggedIn()){ - $username=OC_USER::getUser(); + $username=OC_USER::getUser(); + $view=new OC_FilesystemView('/'.$username); // read old key - $key=file_get_contents(OC_Config::getValue( "datadirectory").'/'.$username.'/encryption.key'); + $key=$view->file_get_contents('/encryption.key'); // decrypt key with old passcode - $key=OC_Crypt::decrypt($key, $_SESSION['user_password']); + $key=OC_Crypt::decrypt($key, $oldPassword); // encrypt again with new passcode - $key=OC_Crypt::encrypt($key,$newpassword); + $key=OC_Crypt::encrypt($key, $newPassword); // store the new key - file_put_contents(OC_Config::getValue( "datadirectory").'/'.$username.'/encryption.key', $key ); - - $_SESSION['user_password']=$newpasscode; + $view->file_put_contents('/encryption.key', $key ); } } /** * @brief encrypts an content * @param $content the cleartext message you want to encrypt - * @param $key the encryption key + * @param $key the encryption key (optional) * @returns encrypted content * * This function encrypts an content */ - public static function encrypt( $content, $key) { - $bf = new Crypt_Blowfish($key); + public static function encrypt( $content, $key='') { + $bf = self::getBlowfish($key); return($bf->encrypt($content)); } - - /** - * @brief decryption of an content - * @param $content the cleartext message you want to decrypt - * @param $key the encryption key - * @returns cleartext content - * - * This function decrypts an content - */ - public static function decrypt( $content, $key) { - $bf = new Crypt_Blowfish($key); + /** + * @brief decryption of an content + * @param $content the cleartext message you want to decrypt + * @param $key the encryption key (optional) + * @returns cleartext content + * + * This function decrypts an content + */ + public static function decrypt( $content, $key='') { + $bf = self::getBlowfish($key); return($bf->encrypt($contents)); - } + } /** * @brief encryption of a file @@ -181,8 +204,4 @@ class OC_Crypt { } return $result; } - - - - } diff --git a/apps/files_encryption/lib/cryptstream.php b/apps/files_encryption/lib/cryptstream.php index 7fbfeaa7a8..00dda7352b 100644 --- a/apps/files_encryption/lib/cryptstream.php +++ b/apps/files_encryption/lib/cryptstream.php @@ -22,19 +22,35 @@ /** * transparently encrypted filestream + * + * you can use it as wrapper around an existing stream by setting OC_CryptStream::$sourceStreams['foo']=array('path'=>$path,'stream'=>$stream) + * and then fopen('crypt://streams/foo'); */ class OC_CryptStream{ + public static $sourceStreams=array(); private $source; + private $path; + private $readBuffer;//for streams that dont support seeking + private $meta=array();//header/meta for source stream public function stream_open($path, $mode, $options, &$opened_path){ $path=str_replace('crypt://','',$path); - OC_Log::write('files_encryption','open encrypted '.$path. ' in '.$mode,OC_Log::DEBUG); - OC_FileProxy::$enabled=false;//disable fileproxies so we can open the source file - $this->source=OC_FileSystem::fopen($path,$mode); - OC_FileProxy::$enabled=true; - if(!is_resource($this->source)){ - OC_Log::write('files_encryption','failed to open '.$path,OC_Log::ERROR); + if(dirname($path)=='streams' and isset(self::$sourceStreams[basename($path)])){ + $this->source=self::$sourceStreams[basename($path)]['stream']; + $this->path=self::$sourceStreams[basename($path)]['path']; + }else{ + $this->path=$path; + OC_Log::write('files_encryption','open encrypted '.$path. ' in '.$mode,OC_Log::DEBUG); + OC_FileProxy::$enabled=false;//disable fileproxies so we can open the source file + $this->source=OC_FileSystem::fopen($path,$mode); + OC_FileProxy::$enabled=true; + if(!is_resource($this->source)){ + OC_Log::write('files_encryption','failed to open '.$path,OC_Log::ERROR); + } + } + if(is_resource($this->source)){ + $this->meta=stream_get_meta_data($this->source); } return is_resource($this->source); } @@ -51,14 +67,26 @@ class OC_CryptStream{ $pos=0; $currentPos=ftell($this->source); $offset=$currentPos%8192; - fseek($this->source,-$offset,SEEK_CUR); $result=''; + if($offset>0){ + if($this->meta['seekable']){ + fseek($this->source,-$offset,SEEK_CUR);//if seeking isnt supported the internal read buffer will be used + }else{ + $pos=strlen($this->readBuffer); + $result=$this->readBuffer; + } + } while($count>$pos){ $data=fread($this->source,8192); $pos+=8192; - $result.=OC_Crypt::decrypt($data); + if(strlen($data)){ + $result.=OC_Crypt::decrypt($data); + } } - return substr($result,$offset,$count); + if(!$this->meta['seekable']){ + $this->readBuffer=substr($result,$count); + } + return substr($result,0,$count); } public function stream_write($data){ @@ -119,6 +147,9 @@ class OC_CryptStream{ } public function stream_close(){ + if(OC_FileCache::inCache($this->path)){ + OC_FileCache::put($this->path,array('encrypted'=>true)); + } return fclose($this->source); } } \ No newline at end of file diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 053ac786c3..173aea785e 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -26,38 +26,98 @@ */ class OC_FileProxy_Encryption extends OC_FileProxy{ + private static $blackList=null; //mimetypes blacklisted from encryption + private static $metaData=array(); //metadata cache + + /** + * check if a file should be encrypted during write + * @param string $path + * @return bool + */ + private static function shouldEncrypt($path){ + if(is_null(self::$blackList)){ + self::$blackList=explode(',',OC_Appconfig::getValue('files_encryption','type_blacklist','jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg')); + } + if(isset(self::$metaData[$path])){ + $metadata=self::$metaData[$path]; + }else{ + $metadata=OC_FileCache::get($path); + self::$metaData[$path]=$metadata; + } + if($metadata['encrypted']){ + return true; + } + $extention=substr($path,strrpos($path,'.')+1); + if(array_search($extention,self::$blackList)===false){ + return true; + } + } + + /** + * check if a file is encrypted + * @param string $path + * @return bool + */ + private static function isEncrypted($path){ + if(isset(self::$metaData[$path])){ + $metadata=self::$metaData[$path]; + }else{ + $metadata=OC_FileCache::get($path); + self::$metaData[$path]=$metadata; + } + return (bool)$metadata['encrypted']; + } + public function preFile_put_contents($path,&$data){ - if(substr($path,-4)=='.enc'){ + if(self::shouldEncrypt($path)){ + $exists=OC_Filesystem::file_exists($path); + $target=fopen('crypt://'.$path,'w'); if (is_resource($data)) { - $newData=''; while(!feof($data)){ - $block=fread($data,8192); - $newData.=OC_Crypt::encrypt($block); + fwrite($target,fread($data,8192)); } - $data=$newData; }else{ - $data=OC_Crypt::blockEncrypt($data); + fwrite($target,$data); } + //fake the normal hooks + OC_Hook::emit( 'OC_Filesystem', 'post_create', array( 'path' => $path)); + OC_Hook::emit( 'OC_Filesystem', 'post_write', array( 'path' => $path)); + return false; } } public function postFile_get_contents($path,$data){ - if(substr($path,-4)=='.enc'){ - return OC_Crypt::blockDecrypt($data); + if(self::isEncrypted($path)){ + $data=OC_Crypt::blockDecrypt($data); } + return $data; } public function postFopen($path,&$result){ - if(substr($path,-4)=='.enc'){ - $meta=stream_get_meta_data($result); + if(!$result){ + return $result; + } + $meta=stream_get_meta_data($result); + if(self::isEncrypted($path)){ fclose($result); - OC_log::write('file_encryption','mode: '.$meta['mode']); + $result=fopen('crypt://'.$path,$meta['mode']); + }elseif(self::shouldEncrypt($path) and $meta['mode']!='r'){ + if(OC_Filesystem::file_exists($path)){ + //first encrypt the target file so we don't end up with a half encrypted file + OC_Log::write('files_encryption','Decrypting '.$path.' before writing',OC_Log::DEBUG); + if($result){ + fclose($result); + } + $tmpFile=OC_Filesystem::toTmpFile($path); + OC_Filesystem::fromTmpFile($tmpFile,$path); + } $result=fopen('crypt://'.$path,$meta['mode']); } + return $result; } public function preReadFile($path){ - if(substr($path,-4)=='.enc'){ + if(self::isEncrypted($path)){ $stream=fopen('crypt://'.$path,'r'); while(!feof($stream)){ print(fread($stream,8192)); @@ -65,11 +125,4 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ return false;//cancel the original request } } - - public function postGetMimeType($path,$result){ - if(substr($path,-4)=='.enc'){ - return 'text/plain'; - } - return $result; - } } diff --git a/lib/user.php b/lib/user.php index 34f44f572e..aa828de52f 100644 --- a/lib/user.php +++ b/lib/user.php @@ -195,8 +195,8 @@ class OC_User { if( $run ){ $uid=self::checkPassword( $uid, $password ); if($uid){ - OC_Crypt::init($uid,$password); return self::setUserId($uid); + OC_Hook::emit( "OC_User", "post_login", array( "uid" => $uid, 'password'=>$password )); } } return false; @@ -209,7 +209,6 @@ class OC_User { */ public static function setUserId($uid) { $_SESSION['user_id'] = $uid; - OC_Hook::emit( "OC_User", "post_login", array( "uid" => $uid )); return true; } From 501678f981cf8e320d11cf1a780aefeae1537050 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sun, 5 Feb 2012 21:45:41 +0100 Subject: [PATCH 010/167] always mount the root filesystem, sometimes we need the filesystem when not logged in --- lib/util.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/util.php b/lib/util.php index 1b1e29b674..3329789de9 100644 --- a/lib/util.php +++ b/lib/util.php @@ -35,9 +35,9 @@ class OC_Util { $user = OC_User::getUser(); } + //first set up the local "root" storage + OC_Filesystem::mount('OC_Filestorage_Local',array('datadir'=>$CONFIG_DATADIRECTORY_ROOT),'/'); if( $user != "" ){ //if we aren't logged in, there is no use to set up the filesystem - //first set up the local "root" storage - OC_Filesystem::mount('OC_Filestorage_Local',array('datadir'=>$CONFIG_DATADIRECTORY_ROOT),'/'); OC::$CONFIG_DATADIRECTORY = $CONFIG_DATADIRECTORY_ROOT."/$user/$root"; if( !is_dir( OC::$CONFIG_DATADIRECTORY )){ From b3a974d8bbcd88602a54cf32cd472802583ab4aa Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sun, 5 Feb 2012 21:49:22 +0100 Subject: [PATCH 011/167] only trigger hooks for the default filesystem view --- apps/files_encryption/lib/crypt.php | 41 ++++++++++++++--------------- lib/filesystemview.php | 22 +++++++++------- lib/user.php | 3 ++- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 4e7739b1d0..0a593b98c4 100644 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -44,19 +44,20 @@ class OC_Crypt { } public static function init($login,$password) { - if(OC_User::isLoggedIn()){ - $view=new OC_FilesystemView('/'.$login); - if(!$view->file_exists('/encryption.key')){// does key exist? - OC_Crypt::createkey($password); - } - $key=$view->file_get_contents('/encryption.key'); - $_SESSION['enckey']=OC_Crypt::decrypt($key, $password); + $view=new OC_FilesystemView('/'.$login); + OC_FileProxy::$enabled=false; + if(!$view->file_exists('/encryption.key')){// does key exist? + OC_Crypt::createkey($login,$password); } + $key=$view->file_get_contents('/encryption.key'); + OC_FileProxy::$enabled=true; + $_SESSION['enckey']=OC_Crypt::decrypt($key, $password); } /** * get the blowfish encryption handeler for a key * @param string $key (optional) + * @return Crypt_Blowfish * * if the key is left out, the default handeler will be used */ @@ -74,21 +75,19 @@ class OC_Crypt { } } - public static function createkey($passcode) { - if(OC_User::isLoggedIn()){ - // generate a random key - $key=mt_rand(10000,99999).mt_rand(10000,99999).mt_rand(10000,99999).mt_rand(10000,99999); + public static function createkey($username,$passcode) { + // generate a random key + $key=mt_rand(10000,99999).mt_rand(10000,99999).mt_rand(10000,99999).mt_rand(10000,99999); - // encrypt the key with the passcode of the user - $enckey=OC_Crypt::encrypt($key,$passcode); + // encrypt the key with the passcode of the user + $enckey=OC_Crypt::encrypt($key,$passcode); - // Write the file - $username=OC_USER::getUser(); - OC_FileProxy::$enabled=false; - $view=new OC_FilesystemView('/'.$username); - $view->file_put_contents('/encryption.key',$enckey); - OC_FileProxy::$enabled=true; - } + // Write the file + $proxyEnabled=OC_FileProxy::$enabled; + OC_FileProxy::$enabled=false; + $view=new OC_FilesystemView('/'.$username); + $view->file_put_contents('/encryption.key',$enckey); + OC_FileProxy::$enabled=$proxyEnabled; } public static function changekeypasscode($oldPassword, $newPassword) { @@ -133,7 +132,7 @@ class OC_Crypt { */ public static function decrypt( $content, $key='') { $bf = self::getBlowfish($key); - return($bf->encrypt($contents)); + return($bf->decrypt($content)); } /** diff --git a/lib/filesystemview.php b/lib/filesystemview.php index a7003e84f1..0ce803be2b 100644 --- a/lib/filesystemview.php +++ b/lib/filesystemview.php @@ -303,11 +303,13 @@ class OC_FilesystemView { if(OC_FileProxy::runPreProxies($operation,$path, $extraParam) and OC_Filesystem::isValidPath($path) and $storage=$this->getStorage($path)){ $interalPath=$this->getInternalPath($path); $run=true; - foreach($hooks as $hook){ - if($hook!='read'){ - OC_Hook::emit( OC_Filesystem::CLASSNAME, $hook, array( OC_Filesystem::signal_param_path => $path, OC_Filesystem::signal_param_run => &$run)); - }else{ - OC_Hook::emit( OC_Filesystem::CLASSNAME, $hook, array( OC_Filesystem::signal_param_path => $path)); + if(OC_Filesystem::$loaded and $this->fakeRoot==OC_Filesystem::getRoot()){ + foreach($hooks as $hook){ + if($hook!='read'){ + OC_Hook::emit( OC_Filesystem::CLASSNAME, $hook, array( OC_Filesystem::signal_param_path => $path, OC_Filesystem::signal_param_run => &$run)); + }else{ + OC_Hook::emit( OC_Filesystem::CLASSNAME, $hook, array( OC_Filesystem::signal_param_path => $path)); + } } } if($run){ @@ -317,10 +319,12 @@ class OC_FilesystemView { $result=$storage->$operation($interalPath); } $result=OC_FileProxy::runPostProxies($operation,$path,$result); - if($operation!='fopen'){//no post hooks for fopen, the file stream is still open - foreach($hooks as $hook){ - if($hook!='read'){ - OC_Hook::emit( OC_Filesystem::CLASSNAME, 'post_'.$hook, array( OC_Filesystem::signal_param_path => $path)); + if(OC_Filesystem::$loaded and $this->fakeRoot==OC_Filesystem::getRoot()){ + if($operation!='fopen'){//no post hooks for fopen, the file stream is still open + foreach($hooks as $hook){ + if($hook!='read'){ + OC_Hook::emit( OC_Filesystem::CLASSNAME, 'post_'.$hook, array( OC_Filesystem::signal_param_path => $path)); + } } } } diff --git a/lib/user.php b/lib/user.php index aa828de52f..826215b228 100644 --- a/lib/user.php +++ b/lib/user.php @@ -195,8 +195,9 @@ class OC_User { if( $run ){ $uid=self::checkPassword( $uid, $password ); if($uid){ - return self::setUserId($uid); + self::setUserId($uid); OC_Hook::emit( "OC_User", "post_login", array( "uid" => $uid, 'password'=>$password )); + return true; } } return false; From 6658f510986aff0e41fee37319a1b0eefa98a4d0 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sun, 5 Feb 2012 23:49:22 +0100 Subject: [PATCH 012/167] provide early file system when using webdav --- lib/connector/sabre/auth.php | 1 + lib/util.php | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/connector/sabre/auth.php b/lib/connector/sabre/auth.php index 1e87c7cee0..8964ef7d0d 100644 --- a/lib/connector/sabre/auth.php +++ b/lib/connector/sabre/auth.php @@ -23,6 +23,7 @@ class OC_Connector_Sabre_Auth extends Sabre_DAV_Auth_Backend_AbstractBasic { * @return bool */ protected function validateUserPass($username, $password){ + OC_Util::setUpFS();//login hooks may need early access to the filesystem if(OC_User::login($username,$password)){ OC_Util::setUpFS(); return true; diff --git a/lib/util.php b/lib/util.php index 3329789de9..18a5db3e4e 100644 --- a/lib/util.php +++ b/lib/util.php @@ -8,6 +8,7 @@ class OC_Util { public static $scripts=array(); public static $styles=array(); public static $headers=array(); + private static $rootMounted=false; private static $fsSetup=false; // Can be set up @@ -36,7 +37,10 @@ class OC_Util { } //first set up the local "root" storage - OC_Filesystem::mount('OC_Filestorage_Local',array('datadir'=>$CONFIG_DATADIRECTORY_ROOT),'/'); + if(!self::$rootMounted){ + OC_Filesystem::mount('OC_Filestorage_Local',array('datadir'=>$CONFIG_DATADIRECTORY_ROOT),'/'); + self::$rootMounted=true; + } if( $user != "" ){ //if we aren't logged in, there is no use to set up the filesystem OC::$CONFIG_DATADIRECTORY = $CONFIG_DATADIRECTORY_ROOT."/$user/$root"; From 1cffeefa069075054f9c2f676b84ddc02b56232c Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 11 Feb 2012 15:48:31 +0100 Subject: [PATCH 013/167] move implementation of from/toTmpFile from the file storage to the filesystem --- lib/filestorage.php | 2 -- lib/filestorage/local.php | 22 ---------------------- lib/filesystemview.php | 34 +++++++++++++++------------------- 3 files changed, 15 insertions(+), 43 deletions(-) diff --git a/lib/filestorage.php b/lib/filestorage.php index 4523144f6f..d420427225 100644 --- a/lib/filestorage.php +++ b/lib/filestorage.php @@ -45,8 +45,6 @@ class OC_Filestorage{ public function rename($path1,$path2){} public function copy($path1,$path2){} public function fopen($path,$mode){} - public function toTmpFile($path){}//copy the file to a temporary file, used for cross-storage file actions - public function fromTmpFile($tmpPath,$path){}//copy a file from a temporary file, used for cross-storage file actions public function getMimeType($path){} public function hash($type,$path,$raw){} public function free_space($path){} diff --git a/lib/filestorage/local.php b/lib/filestorage/local.php index ee4b267bcd..de1f83e3e1 100644 --- a/lib/filestorage/local.php +++ b/lib/filestorage/local.php @@ -171,28 +171,6 @@ class OC_Filestorage_Local extends OC_Filestorage{ } } - public function toTmpFile($path){ - $tmpFolder=get_temp_dir(); - $filename=tempnam($tmpFolder,'OC_TEMP_FILE_'.substr($path,strrpos($path,'.'))); - $fileStats = stat($this->datadir.$path); - if(copy($this->datadir.$path,$filename)){ - touch($filename, $fileStats['mtime'], $fileStats['atime']); - return $filename; - }else{ - return false; - } - } - - public function fromTmpFile($tmpFile,$path){ - $fileStats = stat($tmpFile); - if(rename($tmpFile,$this->datadir.$path)){ - touch($this->datadir.$path, $fileStats['mtime'], $fileStats['atime']); - return true; - }else{ - return false; - } - } - private function delTree($dir) { $dirRelative=$dir; $dir=$this->datadir.$dir; diff --git a/lib/filesystemview.php b/lib/filesystemview.php index 0ce803be2b..592fd972a7 100644 --- a/lib/filesystemview.php +++ b/lib/filesystemview.php @@ -254,29 +254,25 @@ class OC_FilesystemView { return $this->basicOperation('fopen',$path,$hooks,$mode); } public function toTmpFile($path){ - if(OC_FileProxy::runPreProxies('toTmpFile',$path) and OC_Filesystem::isValidPath($path) and $storage=$this->getStorage($path)){ - OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_read, array( OC_Filesystem::signal_param_path => $path)); - return $storage->toTmpFile($this->getInternalPath($path)); + if(OC_Filesystem::isValidPath($path)){ + $source=$this->fopen($path,'r'); + $tmpFile=tempnam(get_temp_dir(),'OC_TMP_').substr($path,strrpos($path,'.')); + if($source){ + return file_put_contents($tmpFile,$source); + } } } public function fromTmpFile($tmpFile,$path){ - if(OC_FileProxy::runPreProxies('copy',$tmpFile,$path) and OC_Filesystem::isValidPath($path) and $storage=$this->getStorage($path)){ - $run=true; - $exists=$this->file_exists($path); - if(!$exists){ - OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_create, array( OC_Filesystem::signal_param_path => $path, OC_Filesystem::signal_param_run => &$run)); - } - if($run){ - OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_write, array( OC_Filesystem::signal_param_path => $path, OC_Filesystem::signal_param_run => &$run)); - } - if($run){ - $result=$storage->fromTmpFile($tmpFile,$this->getInternalPath($path)); - if(!$exists){ - OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_create, array( OC_Filesystem::signal_param_path => $path)); - } - OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, array( OC_Filesystem::signal_param_path => $path)); - return $result; + if(OC_Filesystem::isValidPath($path)){ + $source=fopen($tmpFile,'r'); + if($source){ + $this->file_put_contents($path,$source); + unlink($tmpFile); + return true; + }else{ } + }else{ + error_log('invalid path'); } } From 95459d068e47b83ed13348da3e1d03d062209e41 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 11 Feb 2012 16:06:34 +0100 Subject: [PATCH 014/167] non existing files can never be updated --- lib/filecache.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/filecache.php b/lib/filecache.php index 6ae2f8253d..5d299ff24e 100644 --- a/lib/filecache.php +++ b/lib/filecache.php @@ -515,6 +515,9 @@ class OC_FileCache{ } $view=new OC_FilesystemView($root); } + if(!$view->file_exists($path)){ + return false; + } $mtime=$view->filemtime($path); $isDir=$view->is_dir($path); $path=$root.$path; From 6a8364c3ffeb9d6227f141ae77ba317a1afbfdf6 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sun, 12 Feb 2012 15:56:32 +0100 Subject: [PATCH 015/167] rework the way file_put_contents is handeled --- apps/files_encryption/lib/cryptstream.php | 1 + apps/files_encryption/lib/proxy.php | 14 ++++---------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/apps/files_encryption/lib/cryptstream.php b/apps/files_encryption/lib/cryptstream.php index 00dda7352b..97e0846187 100644 --- a/apps/files_encryption/lib/cryptstream.php +++ b/apps/files_encryption/lib/cryptstream.php @@ -90,6 +90,7 @@ class OC_CryptStream{ } public function stream_write($data){ + error_log('write to '. $this->path); $length=strlen($data); $written=0; $currentPos=ftell($this->source); diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 173aea785e..be6ffa4f44 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -70,19 +70,13 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ public function preFile_put_contents($path,&$data){ if(self::shouldEncrypt($path)){ - $exists=OC_Filesystem::file_exists($path); - $target=fopen('crypt://'.$path,'w'); if (is_resource($data)) { - while(!feof($data)){ - fwrite($target,fread($data,8192)); - } + $id=md5($path); + OC_CryptStream::$sourceStreams[$id]=array('path'=>$path,'stream'=>$data); + $data=fopen('crypt://streams/'.$id,'r'); }else{ - fwrite($target,$data); + $data=OC_Crypt::blockEncrypt($data); } - //fake the normal hooks - OC_Hook::emit( 'OC_Filesystem', 'post_create', array( 'path' => $path)); - OC_Hook::emit( 'OC_Filesystem', 'post_write', array( 'path' => $path)); - return false; } } From c121a1a1e7d9ae554005b8438d8ad999cdacc601 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 15 Feb 2012 16:23:00 +0100 Subject: [PATCH 016/167] implement file_put_contents with stream data using fopen --- apps/files_encryption/lib/proxy.php | 6 +----- lib/filesystemview.php | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index be6ffa4f44..7974d68d48 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -70,11 +70,7 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ public function preFile_put_contents($path,&$data){ if(self::shouldEncrypt($path)){ - if (is_resource($data)) { - $id=md5($path); - OC_CryptStream::$sourceStreams[$id]=array('path'=>$path,'stream'=>$data); - $data=fopen('crypt://streams/'.$id,'r'); - }else{ + if (!is_resource($data)) {//stream put contents should have been converter to fopen $data=OC_Crypt::blockEncrypt($data); } } diff --git a/lib/filesystemview.php b/lib/filesystemview.php index 592fd972a7..58d5b3af71 100644 --- a/lib/filesystemview.php +++ b/lib/filesystemview.php @@ -163,7 +163,21 @@ class OC_FilesystemView { return $this->basicOperation('file_get_contents',$path,array('read')); } public function file_put_contents($path,$data){ - return $this->basicOperation('file_put_contents',$path,array('create','write'),$data); + if(is_resource($data)){//not having to deal with streams in file_put_contents makes life easier + $target=$this->fopen($path,'w'); + if($target){ + while(!feof($data)){ + fwrite($target,fread($data,8192)); + } + fclose($target); + fclose($data); + return true; + }else{ + return false; + } + }else{ + return $this->basicOperation('file_put_contents',$path,array('create','write'),$data); + } } public function unlink($path){ return $this->basicOperation('unlink',$path,array('delete')); From 325858e9e239b726a207ac150404863df509935c Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 15 Feb 2012 20:19:48 +0100 Subject: [PATCH 017/167] add stream wrapper for in-memory files and dont use global variables for the fakedir stream wrapper --- apps/files_sharing/sharedstorage.php | 3 +- lib/base.php | 2 +- lib/fakedirstream.php | 45 ------ lib/streamwrappers.php | 223 +++++++++++++++++++++++++++ 4 files changed, 225 insertions(+), 48 deletions(-) delete mode 100644 lib/fakedirstream.php create mode 100644 lib/streamwrappers.php diff --git a/apps/files_sharing/sharedstorage.php b/apps/files_sharing/sharedstorage.php index cb641e68a8..07653fc11b 100644 --- a/apps/files_sharing/sharedstorage.php +++ b/apps/files_sharing/sharedstorage.php @@ -79,7 +79,6 @@ class OC_Filestorage_Shared extends OC_Filestorage { if ($path == "" || $path == "/") { $path = $this->datadir.$path; $sharedItems = OC_Share::getItemsInFolder($path); - global $FAKEDIRS; $files = array(); foreach ($sharedItems as $item) { // If item is in the root of the shared storage provider and the item exists add it to the fakedirs @@ -87,7 +86,7 @@ class OC_Filestorage_Shared extends OC_Filestorage { $files[] = basename($item['target']); } } - $FAKEDIRS['shared'] = $files; + OC_FakeDirStream::$dirs['shared']=$files; return opendir('fakedir://shared'); } else { $source = $this->getSource($path); diff --git a/lib/base.php b/lib/base.php index 5b6ed9bcb1..94e4907fed 100644 --- a/lib/base.php +++ b/lib/base.php @@ -279,7 +279,7 @@ if(!function_exists('get_temp_dir')) { OC::init(); -require_once('fakedirstream.php'); +require_once('streamwrappers.php'); diff --git a/lib/fakedirstream.php b/lib/fakedirstream.php deleted file mode 100644 index fa3e64da62..0000000000 --- a/lib/fakedirstream.php +++ /dev/null @@ -1,45 +0,0 @@ -name=substr($path,strlen('fakedir://')); - $this->index=0; - if(isset($FAKEDIRS[$this->name])){ - $this->data=$FAKEDIRS[$this->name]; - }else{ - $this->data=array(); - } - return true; - } - - public function dir_readdir(){ - if($this->index>=count($this->data)){ - return false; - } - $filename=$this->data[$this->index]; - $this->index++; - return $filename; - } - - public function dir_closedir() { - $this->data=false; - $this->name=''; - return true; - } - - public function dir_rewinddir() { - $this->index=0; - return true; - } -} - -stream_wrapper_register("fakedir", "fakeDirStream"); - diff --git a/lib/streamwrappers.php b/lib/streamwrappers.php new file mode 100644 index 0000000000..1454a99e8d --- /dev/null +++ b/lib/streamwrappers.php @@ -0,0 +1,223 @@ +name=substr($path,strlen('fakedir://')); + $this->index=0; + if(!isset(self::$dirs[$this->name])){ + self::$dirs[$this->name]=array(); + } + return true; + } + + public function dir_readdir(){ + if($this->index>=count(self::$dirs[$this->name])){ + return false; + } + $filename=self::$dirs[$this->name][$this->index]; + $this->index++; + return $filename; + } + + public function dir_closedir() { + $this->name=''; + return true; + } + + public function dir_rewinddir() { + $this->index=0; + return true; + } +} + +class OC_StaticStreamWrapper { + public $context; + protected static $data = array(); + + protected $path = ''; + protected $pointer = 0; + protected $writable = false; + + public function stream_close() {} + + public function stream_eof() { + return $this->pointer >= strlen(self::$data[$this->path]); + } + + public function stream_flush() {} + + public function stream_open($path, $mode, $options, &$opened_path) { + switch ($mode[0]) { + case 'r': + if (!isset(self::$data[$path])) return false; + $this->path = $path; + $this->writable = isset($mode[1]) && $mode[1] == '+'; + break; + case 'w': + self::$data[$path] = ''; + $this->path = $path; + $this->writable = true; + break; + case 'a': + if (!isset(self::$data[$path])) self::$data[$path] = ''; + $this->path = $path; + $this->writable = true; + $this->pointer = strlen(self::$data[$path]); + break; + case 'x': + if (isset(self::$data[$path])) return false; + $this->path = $path; + $this->writable = true; + break; + case 'c': + if (!isset(self::$data[$path])) self::$data[$path] = ''; + $this->path = $path; + $this->writable = true; + break; + default: + return false; + } + $opened_path = $this->path; + return true; + } + + public function stream_read($count) { + $bytes = min(strlen(self::$data[$this->path]) - $this->pointer, $count); + $data = substr(self::$data[$this->path], $this->pointer, $bytes); + $this->pointer += $bytes; + return $data; + } + + public function stream_seek($offset, $whence = SEEK_SET) { + $len = strlen(self::$data[$this->path]); + switch ($whence) { + case SEEK_SET: + if ($offset <= $len) { + $this->pointer = $offset; + return true; + } + break; + case SEEK_CUR: + if ($this->pointer + $offset <= $len) { + $this->pointer += $offset; + return true; + } + break; + case SEEK_END: + if ($len + $offset <= $len) { + $this->pointer = $len + $offset; + return true; + } + break; + } + return false; + } + + public function stream_stat() { + $size = strlen(self::$data[$this->path]); + $time = time(); + return array( + 0 => 0, + 'dev' => 0, + 1 => 0, + 'ino' => 0, + 2 => 0777, + 'mode' => 0777, + 3 => 1, + 'nlink' => 1, + 4 => 0, + 'uid' => 0, + 5 => 0, + 'gid' => 0, + 6 => '', + 'rdev' => '', + 7 => $size, + 'size' => $size, + 8 => $time, + 'atime' => $time, + 9 => $time, + 'mtime' => $time, + 10 => $time, + 'ctime' => $time, + 11 => -1, + 'blksize' => -1, + 12 => -1, + 'blocks' => -1, + ); + } + + public function stream_tell() { + return $this->pointer; + } + + public function stream_write($data) { + if (!$this->writable) return 0; + $size = strlen($data); + $len = strlen(self::$data[$this->path]); + if ($this->stream_eof()) { + self::$data[$this->path] .= $data; + } else { + self::$data[$this->path] = substr_replace( + self::$data[$this->path], + $data, + $this->pointer + ); + } + $this->pointer += $size; + return $size; + } + + public function unlink($path) { + if (isset(self::$data[$path])) { + unset(self::$data[$path]); + } + return true; + } + + public function url_stat($path) { + if (isset(self::$data[$path])) { + $size = strlen(self::$data[$path]); + $time = time(); + return array( + 0 => 0, + 'dev' => 0, + 1 => 0, + 'ino' => 0, + 2 => 0777, + 'mode' => 0777, + 3 => 1, + 'nlink' => 1, + 4 => 0, + 'uid' => 0, + 5 => 0, + 'gid' => 0, + 6 => '', + 'rdev' => '', + 7 => $size, + 'size' => $size, + 8 => $time, + 'atime' => $time, + 9 => $time, + 'mtime' => $time, + 10 => $time, + 'ctime' => $time, + 11 => -1, + 'blksize' => -1, + 12 => -1, + 'blocks' => -1, + ); + } + return false; + } +} + +stream_wrapper_register("fakedir", "OC_FakeDirStream"); +stream_wrapper_register('static', 'OC_StaticStreamWrapper'); From d9c7e4c333f858efaaee35d26ea12733d29bd694 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 15 Feb 2012 21:44:58 +0100 Subject: [PATCH 018/167] proper mimetypes for encrypted files --- apps/files_encryption/lib/proxy.php | 4 ++ lib/filestorage/local.php | 47 ++--------------------- lib/helper.php | 58 +++++++++++++++++++++++++++++ tests/lib/streamwrappers.php | 47 +++++++++++++++++++++++ 4 files changed, 112 insertions(+), 44 deletions(-) create mode 100644 tests/lib/streamwrappers.php diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 7974d68d48..c53d567ad1 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -115,4 +115,8 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ return false;//cancel the original request } } + + public function postGetMimeType($path,$mime){ + return OC_Helper::getMimeType('crypt://'.$path,'w'); + } } diff --git a/lib/filestorage/local.php b/lib/filestorage/local.php index de1f83e3e1..6f4f68c503 100644 --- a/lib/filestorage/local.php +++ b/lib/filestorage/local.php @@ -122,50 +122,9 @@ class OC_Filestorage_Local extends OC_Filestorage{ return $return; } - public function getMimeType($fspath){ - if($this->is_readable($fspath)){ - $mimeType='application/octet-stream'; - if ($mimeType=='application/octet-stream') { - self::$mimetypes = include('mimetypes.fixlist.php'); - $extention=strtolower(strrchr(basename($fspath), ".")); - $extention=substr($extention,1);//remove leading . - $mimeType=(isset(self::$mimetypes[$extention]))?self::$mimetypes[$extention]:'application/octet-stream'; - - } - if (@is_dir($this->datadir.$fspath)) { - // directories are easy - return "httpd/unix-directory"; - } - if($mimeType=='application/octet-stream' and function_exists('finfo_open') and function_exists('finfo_file') and $finfo=finfo_open(FILEINFO_MIME)){ - $mimeType =strtolower(finfo_file($finfo,$this->datadir.$fspath)); - $mimeType=substr($mimeType,0,strpos($mimeType,';')); - finfo_close($finfo); - } - if ($mimeType=='application/octet-stream' && function_exists("mime_content_type")) { - // use mime magic extension if available - $mimeType = mime_content_type($this->datadir.$fspath); - } - if ($mimeType=='application/octet-stream' && OC_Helper::canExecute("file")) { - // it looks like we have a 'file' command, - // lets see it it does have mime support - $fspath=str_replace("'","\'",$fspath); - $fp = popen("file -i -b '{$this->datadir}$fspath' 2>/dev/null", "r"); - $reply = fgets($fp); - pclose($fp); - - //trim the character set from the end of the response - $mimeType=substr($reply,0,strrpos($reply,' ')); - } - if ($mimeType=='application/octet-stream') { - // Fallback solution: (try to guess the type by the file extension - if(!self::$mimetypes || self::$mimetypes != include('mimetypes.list.php')){ - self::$mimetypes=include('mimetypes.list.php'); - } - $extention=strtolower(strrchr(basename($fspath), ".")); - $extention=substr($extention,1);//remove leading . - $mimeType=(isset(self::$mimetypes[$extention]))?self::$mimetypes[$extention]:'application/octet-stream'; - } - return $mimeType; + public function getMimeType($path){ + if($this->is_readable($path)){ + return OC_Helper::getMimeType($this->datadir.$path); }else{ return false; } diff --git a/lib/helper.php b/lib/helper.php index 2f71bdad2d..6dea4a6a8c 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -25,6 +25,8 @@ * Collection of useful functions */ class OC_Helper { + private static $mimetypes=array(); + /** * @brief Creates an url * @param $app app @@ -267,6 +269,62 @@ class OC_Helper { unlink($dir); } } + + /** + * get the mimetype form a local file + * @param string path + * @return string + * does NOT work for ownClouds filesystem, use OC_FileSystem::getMimeType instead + */ + static function getMimeType($path){ + $isWrapped=(strpos($path,'://')!==false) and (substr($path,0,7)=='file://'); + $mimeType='application/octet-stream'; + if ($mimeType=='application/octet-stream') { + if(count(self::$mimetypes)>0){ + self::$mimetypes = include('mimetypes.fixlist.php'); + } + $extention=strtolower(strrchr(basename($path), ".")); + $extention=substr($extention,1);//remove leading . + $mimeType=(isset(self::$mimetypes[$extention]))?self::$mimetypes[$extention]:'application/octet-stream'; + + } + if (@is_dir($path)) { + // directories are easy + return "httpd/unix-directory"; + } + if($mimeType=='application/octet-stream' and function_exists('finfo_open') and function_exists('finfo_file') and $finfo=finfo_open(FILEINFO_MIME)){ + $info = @strtolower(finfo_file($finfo,$path)); + if($info){ + $mimeType=substr($info,0,strpos($info,';')); + } + finfo_close($finfo); + } + if (!$isWrapped and $mimeType=='application/octet-stream' && function_exists("mime_content_type")) { + // use mime magic extension if available + $mimeType = mime_content_type($path); + } + if (!$isWrapped and $mimeType=='application/octet-stream' && OC_Helper::canExecute("file")) { + // it looks like we have a 'file' command, + // lets see it it does have mime support + $path=str_replace("'","\'",$path); + $fp = popen("file -i -b '$path' 2>/dev/null", "r"); + $reply = fgets($fp); + pclose($fp); + + //trim the character set from the end of the response + $mimeType=substr($reply,0,strrpos($reply,' ')); + } + if ($mimeType=='application/octet-stream') { + // Fallback solution: (try to guess the type by the file extension + if(!self::$mimetypes || self::$mimetypes != include('mimetypes.list.php')){ + self::$mimetypes=include('mimetypes.list.php'); + } + $extention=strtolower(strrchr(basename($path), ".")); + $extention=substr($extention,1);//remove leading . + $mimeType=(isset(self::$mimetypes[$extention]))?self::$mimetypes[$extention]:'application/octet-stream'; + } + return $mimeType; + } /** * @brief Checks $_REQUEST contains a var for the $s key. If so, returns the html-escaped value of this var; otherwise returns the default value provided by $d. diff --git a/tests/lib/streamwrappers.php b/tests/lib/streamwrappers.php new file mode 100644 index 0000000000..c4784a6297 --- /dev/null +++ b/tests/lib/streamwrappers.php @@ -0,0 +1,47 @@ +. +* +*/ + +class Test_StreamWrappers extends UnitTestCase { + public function testFakeDir(){ + $items=array('foo','bar'); + OC_FakeDirStream::$dirs['test']=$items; + $dh=opendir('fakedir://test'); + $result=array(); + while($file=readdir($dh)){ + $result[]=$file; + $this->assertNotIdentical(false,array_search($file,$items)); + } + $this->assertEqual(count($items),count($result)); + } + + public function testStaticStream(){ + $sourceFile=OC::$SERVERROOT.'/tests/data/lorem.txt'; + $staticFile='static://test'; + $this->assertFalse(file_exists($staticFile)); + file_put_contents($staticFile,file_get_contents($sourceFile)); + $this->assertTrue(file_exists($staticFile)); + $this->assertEqual(file_get_contents($sourceFile),file_get_contents($staticFile)); + unlink($staticFile); + clearstatcache(); + $this->assertFalse(file_exists($staticFile)); + } +} \ No newline at end of file From c20319d37701efb9d32c38dd71880739ca75b33f Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 21 Feb 2012 20:48:14 +0100 Subject: [PATCH 019/167] fix incorrect information in the filecache when using encryption --- apps/files_encryption/lib/cryptstream.php | 5 +-- apps/files_encryption/lib/proxy.php | 31 ++++++++++-------- apps/media/lib_media.php | 1 + files/ajax/upload.php | 3 +- lib/filecache.php | 40 ++++++++++++++++++++--- lib/filesystemview.php | 6 +++- 6 files changed, 62 insertions(+), 24 deletions(-) diff --git a/apps/files_encryption/lib/cryptstream.php b/apps/files_encryption/lib/cryptstream.php index 97e0846187..86583096f1 100644 --- a/apps/files_encryption/lib/cryptstream.php +++ b/apps/files_encryption/lib/cryptstream.php @@ -90,7 +90,6 @@ class OC_CryptStream{ } public function stream_write($data){ - error_log('write to '. $this->path); $length=strlen($data); $written=0; $currentPos=ftell($this->source); @@ -148,9 +147,7 @@ class OC_CryptStream{ } public function stream_close(){ - if(OC_FileCache::inCache($this->path)){ - OC_FileCache::put($this->path,array('encrypted'=>true)); - } + OC_FileCache::put($this->path,array('encrypted'=>true)); return fclose($this->source); } } \ No newline at end of file diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index c53d567ad1..ed3907cccf 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -38,13 +38,7 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ if(is_null(self::$blackList)){ self::$blackList=explode(',',OC_Appconfig::getValue('files_encryption','type_blacklist','jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg')); } - if(isset(self::$metaData[$path])){ - $metadata=self::$metaData[$path]; - }else{ - $metadata=OC_FileCache::get($path); - self::$metaData[$path]=$metadata; - } - if($metadata['encrypted']){ + if(self::isEncrypted($path)){ return true; } $extention=substr($path,strrpos($path,'.')+1); @@ -62,7 +56,7 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ if(isset(self::$metaData[$path])){ $metadata=self::$metaData[$path]; }else{ - $metadata=OC_FileCache::get($path); + $metadata=OC_FileCache::getCached($path); self::$metaData[$path]=$metadata; } return (bool)$metadata['encrypted']; @@ -92,14 +86,19 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ fclose($result); $result=fopen('crypt://'.$path,$meta['mode']); }elseif(self::shouldEncrypt($path) and $meta['mode']!='r'){ - if(OC_Filesystem::file_exists($path)){ + if(OC_Filesystem::file_exists($path) and OC_Filesystem::filesize($path)>0){ //first encrypt the target file so we don't end up with a half encrypted file OC_Log::write('files_encryption','Decrypting '.$path.' before writing',OC_Log::DEBUG); - if($result){ - fclose($result); + $tmp=fopen('php://temp'); + while(!feof($result)){ + $chunk=fread($result,8192); + if($chunk){ + fwrite($tmp,$chunk); + } } - $tmpFile=OC_Filesystem::toTmpFile($path); - OC_Filesystem::fromTmpFile($tmpFile,$path); + fclose($result); + OC_Filesystem::file_put_contents($path,$tmp); + fclose($tmp); } $result=fopen('crypt://'.$path,$meta['mode']); } @@ -117,6 +116,10 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ } public function postGetMimeType($path,$mime){ - return OC_Helper::getMimeType('crypt://'.$path,'w'); + if((!OC_FileCache::inCache($path) and self::shouldEncrypt($path)) or self::isEncrypted($path)){ + return OC_Helper::getMimeType('crypt://'.$path,'w'); + }else{ + return $mime; + } } } diff --git a/apps/media/lib_media.php b/apps/media/lib_media.php index 1bcd0f08c8..a2109c151a 100644 --- a/apps/media/lib_media.php +++ b/apps/media/lib_media.php @@ -56,6 +56,7 @@ class OC_MEDIA{ */ public static function updateFile($params){ $path=$params['path']; + if(!$path) return; require_once 'lib_scanner.php'; require_once 'lib_collection.php'; //fix a bug where there were multiply '/' in front of the path, it should only be one diff --git a/files/ajax/upload.php b/files/ajax/upload.php index 241edc216f..034b891460 100644 --- a/files/ajax/upload.php +++ b/files/ajax/upload.php @@ -48,7 +48,8 @@ if(strpos($dir,'..') === false){ for($i=0;$i<$fileCount;$i++){ $target=stripslashes($dir) . $files['name'][$i]; if(is_uploaded_file($files['tmp_name'][$i]) and OC_Filesystem::fromTmpFile($files['tmp_name'][$i],$target)){ - $result[]=array( "status" => "success", 'mime'=>OC_Filesystem::getMimeType($target),'size'=>OC_Filesystem::filesize($target),'name'=>$files['name'][$i]); + $meta=OC_FileCache::getCached($target); + $result[]=array( "status" => "success", 'mime'=>$meta['mimetype'],'size'=>$meta['size'],'name'=>$files['name'][$i]); } } OC_JSON::encodedPrint($result); diff --git a/lib/filecache.php b/lib/filecache.php index 5d299ff24e..83eaffb171 100644 --- a/lib/filecache.php +++ b/lib/filecache.php @@ -28,6 +28,8 @@ * It will try to keep the data up to date but changes from outside ownCloud can invalidate the cache */ class OC_FileCache{ + private static $savedData=array(); + /** * get the filesystem info from the cache * @param string path @@ -93,6 +95,14 @@ class OC_FileCache{ self::update($id,$data); return; } + if(isset(self::$savedData[$path])){ + $data=array_merge($data,self::$savedData[$path]); + unset(self::$savedData[$path]); + } + if(!isset($data['size']) or !isset($data['mtime'])){//save incomplete data for the next time we write it + self::$savedData[$path]=$data; + return; + } if(!isset($data['encrypted'])){ $data['encrypted']=false; } @@ -101,9 +111,8 @@ class OC_FileCache{ } $mimePart=dirname($data['mimetype']); $user=OC_User::getUser(); - $query=OC_DB::prepare('INSERT INTO *PREFIX*fscache(parent, name, path, size, mtime, ctime, mimetype, mimepart,user,writable) VALUES(?,?,?,?,?,?,?,?,?,?)'); - $query->execute(array($parent,basename($path),$path,$data['size'],$data['mtime'],$data['ctime'],$data['mimetype'],$mimePart,$user,$data['writable'])); - + $query=OC_DB::prepare('INSERT INTO *PREFIX*fscache(parent, name, path, size, mtime, ctime, mimetype, mimepart,user,writable,encrypted,versioned) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)'); + $query->execute(array($parent,basename($path),$path,$data['size'],$data['mtime'],$data['ctime'],$data['mimetype'],$mimePart,$user,$data['writable'],$data['encrypted'],$data['versioned'])); } /** @@ -323,7 +332,29 @@ class OC_FileCache{ } self::increaseSize(dirname($fullPath),$size-$cachedSize); } - + + public static function getCached($path,$root=''){ + if(!$root){ + $root=OC_Filesystem::getRoot(); + }else{ + if($root=='/'){ + $root=''; + } + } + $path=$root.$path; + $query=OC_DB::prepare('SELECT ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path=?'); + $result=$query->execute(array($path))->fetchRow(); + if(is_array($result)){ + if(isset(self::$savedData[$path])){ + $result=array_merge($result,self::$savedData[$path]); + } + return $result; + }else{ + OC_Log::write('get(): file not found in cache ('.$path.')','core',OC_Log::DEBUG); + return false; + } + } + private static function getCachedSize($path,$root){ if(!$root){ $root=OC_Filesystem::getRoot(); @@ -332,6 +363,7 @@ class OC_FileCache{ $root=''; } } + $path=$root.$path; $query=OC_DB::prepare('SELECT size FROM *PREFIX*fscache WHERE path=?'); $result=$query->execute(array($path)); if($row=$result->fetchRow()){ diff --git a/lib/filesystemview.php b/lib/filesystemview.php index 58d5b3af71..c4d5ff3514 100644 --- a/lib/filesystemview.php +++ b/lib/filesystemview.php @@ -171,6 +171,7 @@ class OC_FilesystemView { } fclose($target); fclose($data); + OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, array( OC_Filesystem::signal_param_path => $path)); return true; }else{ return false; @@ -278,6 +279,9 @@ class OC_FilesystemView { } public function fromTmpFile($tmpFile,$path){ if(OC_Filesystem::isValidPath($path)){ + if(!$tmpFile){ + debug_print_backtrace(); + } $source=fopen($tmpFile,'r'); if($source){ $this->file_put_contents($path,$source); @@ -286,7 +290,7 @@ class OC_FilesystemView { }else{ } }else{ - error_log('invalid path'); + return false; } } From ed0c99ef149d63a350c7ffcb87d398b90ed3b0a2 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 22 Feb 2012 15:18:22 +0100 Subject: [PATCH 020/167] make sure we always have the encryption key unlocked --- apps/files_encryption/appinfo/app.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index 82d2544dd1..23f3955aa4 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -9,3 +9,9 @@ OC_FileProxy::register(new OC_FileProxy_Encryption()); OC_Hook::connect('OC_User','post_login','OC_Crypt','loginListener'); stream_wrapper_register('crypt','OC_CryptStream'); + +if(!isset($_SESSION['enckey']) and OC_User::isLoggedIn()){//force the user to re-loggin if the encryption key isn't unlocked (happens when a user is logged in before the encryption app is enabled) + OC_User::logout(); + header("Location: ".OC::$WEBROOT.'/'); + exit(); +} From b3f3b8c23f4f07a4d38e952f4d77827380c34b58 Mon Sep 17 00:00:00 2001 From: Marvin Thomas Rabe Date: Tue, 21 Feb 2012 22:31:35 +0100 Subject: [PATCH 021/167] UI problems solved. Bookmarks app updated. --- apps/bookmarks/css/bookmarks.css | 5 ++++- apps/bookmarks/js/bookmarks.js | 3 +++ apps/bookmarks/templates/list.php | 10 ++++++---- apps/bookmarks/templates/settings.php | 2 +- apps/contacts/css/contacts.css | 4 ++-- apps/contacts/js/contacts.js | 6 +++--- apps/gallery/css/styles.css | 6 +++--- apps/media/js/collection.js | 24 +++++++++++++----------- apps/media/js/loader.js | 4 ++-- apps/media/js/music.js | 12 +++++------- apps/media/js/playlist.js | 8 ++++---- apps/media/js/scanner.js | 8 ++++---- core/css/styles.css | 9 +++++---- core/js/js.js | 22 +++++++++++----------- core/templates/layout.user.php | 4 ++-- settings/css/settings.css | 4 ++-- 16 files changed, 70 insertions(+), 61 deletions(-) diff --git a/apps/bookmarks/css/bookmarks.css b/apps/bookmarks/css/bookmarks.css index 8dfdc8a07b..499a4e9c53 100644 --- a/apps/bookmarks/css/bookmarks.css +++ b/apps/bookmarks/css/bookmarks.css @@ -1,4 +1,7 @@ -#content { overflow: auto; } +#content { overflow: auto; height: 100%; } +#firstrun { width: 80%; margin: 5em auto auto auto; text-align: center; font-weight:bold; font-size:1.5em; color:#777;} +#firstrun small { display: block; font-weight: normal; font-size: 0.5em; } +#firstrun #selections { font-size:0.8em; width: 100%; margin: 2em auto auto auto; clear: both; } .bookmarks_headline { font-size: large; diff --git a/apps/bookmarks/js/bookmarks.js b/apps/bookmarks/js/bookmarks.js index fadbbd5513..328f88a45d 100644 --- a/apps/bookmarks/js/bookmarks.js +++ b/apps/bookmarks/js/bookmarks.js @@ -35,6 +35,7 @@ function getBookmarks() { for(var i in bookmarks.data) { updateBookmarksList(bookmarks.data[i]); + $("#firstrun").hide(); } $('.bookmark_link').click(recordClick); @@ -71,6 +72,8 @@ function addOrEditBookmark(event) { var tags = encodeEntities($('#bookmark_add_tags').val()); var taglist = tags.split(' '); var tagshtml = ''; + $("#firstrun").hide(); + for ( var i=0, len=taglist.length; i' + taglist[i] + ' '; } diff --git a/apps/bookmarks/templates/list.php b/apps/bookmarks/templates/list.php index d44a0ecbcd..bd33fe457f 100644 --- a/apps/bookmarks/templates/list.php +++ b/apps/bookmarks/templates/list.php @@ -21,9 +21,11 @@

+
+
t('You have no bookmarks'); ?> -
- diff --git a/apps/bookmarks/templates/settings.php b/apps/bookmarks/templates/settings.php index a985ee9d61..41433d8476 100644 --- a/apps/bookmarks/templates/settings.php +++ b/apps/bookmarks/templates/settings.php @@ -8,7 +8,7 @@ ?>
- t('Bookmarklet:');?> t('Add page to ownCloud'); ?> + t('Bookmarklet:');?> ?output=popup&url="+c(b.location)+"&title="+c(b.title),"bkmk_popup","left="+((a.screenX||a.screenLeft)+10)+",top="+((a.screenY||a.screenTop)+10)+",height=510px,width=550px,resizable=1,alwaysRaised=1");a.setTimeout(function(){d.focus()},300)})();'>t('Add page to ownCloud'); ?>
t('Drag this to your browser bookmarks and click it, when you want to bookmark a webpage.'); ?>
diff --git a/apps/contacts/css/contacts.css b/apps/contacts/css/contacts.css index 384541f375..b24ec438f2 100644 --- a/apps/contacts/css/contacts.css +++ b/apps/contacts/css/contacts.css @@ -17,8 +17,8 @@ #contacts_propertymenu li a:hover { color: #fff } #actionbar { height: 30px; width: 200px; position: fixed; right: 0px; top: 75px; margin: 0 0 0 0; padding: 0 0 0 0;} #card { /*max-width: 70em; border: thin solid lightgray; display: block;*/ } -#firstrun { /*border: thin solid lightgray;*/ width: 80%; margin: 5em auto auto auto; text-align: center; font-weight:bold; font-size:1.5em; color:#777;} -#firstrun #selections { /*border: thin solid lightgray;*/ font-size:0.8em; width: 100%; margin: 2em auto auto auto; clear: both; } +#firstrun { width: 100%; position: absolute; top: 5em; left: 0; text-align: center; font-weight:bold; font-size:1.5em; color:#777; } +#firstrun #selections { font-size:0.8em; margin: 2em auto auto auto; clear: both; } #card input[type="text"].contacts_property,input[type="email"].contacts_property { width: 16em; } #card input[type="text"],input[type="email"],input[type="tel"],input[type="date"], select { background-color: #f8f8f8; border: 0 !important; -webkit-appearance:none !important; -moz-appearance:none !important; -webkit-box-sizing:none !important; -moz-box-sizing:none !important; box-sizing:none !important; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; float: left; } diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 11661320c5..d033e3f21c 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -8,7 +8,7 @@ String.prototype.strip_tags = function(){ tags = this; stripped = tags.replace(/[\<\>]/gi, ""); return stripped; -} +}; Contacts={ @@ -142,7 +142,7 @@ Contacts={ } }); }); - } + }; }, loadListHandlers:function() { //$('.add,.delete').hide(); @@ -323,7 +323,7 @@ Contacts={ } }); }, - delete:function() { + delete: function() { $('#contacts_deletecard').tipsy('hide'); $.getJSON('ajax/deletecard.php',{'id':this.id},function(jsondata){ if(jsondata.status == 'success'){ diff --git a/apps/gallery/css/styles.css b/apps/gallery/css/styles.css index c039cd5ec0..da94f9ac9e 100644 --- a/apps/gallery/css/styles.css +++ b/apps/gallery/css/styles.css @@ -1,8 +1,8 @@ -div#gallery_list { margin: 70pt 20pt 0 20pt; } +div#gallery_list { margin: 4.5em 2em 0 2em; } div#gallery_list.leftcontent { padding-top: 15pt; margin: 0; position: absolute; bottom:0px; text-align: center; overflow: auto; } -div.gallery_album_box { width: 200px; position:relative; text-align: center; border: 0; display: inline-block; margin: 5pt; vertical-align: top; padding: 20px 5px 5px 5px; position: relative; -webkit-transition: color 0.5s ease-in-out; -o-transition: color 0.5s ease-in-out; -moz-transition: color 0.5s ease-in-out;color: #BBB;} +div.gallery_album_box { width: 200px; position:relative; text-align: center; border: 0; display: inline-block; margin: 5pt; vertical-align: top; padding: 5px 5px 5px 5px; position: relative; -webkit-transition: color 0.5s ease-in-out; -o-transition: color 0.5s ease-in-out; -moz-transition: color 0.5s ease-in-out;color: #BBB;} div.gallery_album_box h1 { font-size: 9pt; font-family: Verdana; } -div.gallery_album_decoration { width: 200px; position: absolute; border: 0; height: 20px; top: 20px; text-align:right; vertical-align:middle; background-color: #eee; opacity: 0; -webkit-transition: opacity 0.5s ease-in-out; -moz-transition: opacity 0.5s ease-in-out; -o-transition: opacity 0.5s ease-in-out; border-bottom-right-radius: 7px; border-bottom-left-radius: 7px; -moz-border-radius-bottomright: 7px; -moz-border-radius-bottomleft:7px;} +div.gallery_album_decoration { width: 200px; position: absolute; border: 0; height: 20px; top: 5px; text-align:right; vertical-align:middle; background-color: #eee; opacity: 0; -webkit-transition: opacity 0.5s ease-in-out; -moz-transition: opacity 0.5s ease-in-out; -o-transition: opacity 0.5s ease-in-out; border-bottom-right-radius: 7px; border-bottom-left-radius: 7px; -moz-border-radius-bottomright: 7px; -moz-border-radius-bottomleft:7px;} div.gallery_album_box:hover { color: black; } div.gallery_album_box:hover div.gallery_album_decoration { opacity: 0.7;} div.gallery_album_decoration a {padding: 0 4pt; cursor: pointer;} diff --git a/apps/media/js/collection.js b/apps/media/js/collection.js index 2249acf3cc..753785f77b 100644 --- a/apps/media/js/collection.js +++ b/apps/media/js/collection.js @@ -1,3 +1,5 @@ +var initScanned = false; + Collection={ artists:[], albums:[], @@ -68,10 +70,10 @@ Collection={ for(var i=0;i0){ var tr=template.clone().removeClass('template'); @@ -108,7 +108,7 @@ Collection={ $('tr[data-artist="'+artist.name+'"]').addClass('active'); }); if(artist.songs.length>1){ - var expander=$('>'); + expander=$('>'); expander.data('expanded',false); expander.click(function(event){ var tr=$(this).parent().parent(); @@ -136,10 +136,11 @@ Collection={ var first=true; $.each(artist.albums,function(j,album){ $.each(album.songs,function(i,song){ + var newRow; if(first){ newRow=tr; }else{ - var newRow=tr.clone(); + newRow=tr.clone(); newRow.find('td.artist').text(''); newRow.find('.expander').remove(); } @@ -221,13 +222,14 @@ Collection={ tr.find('td.album-expander a.expander').addClass('expanded'); tr.find('td.album-expander a.expander').text('v'); $.each(albumData.songs,function(i,song){ + var newRow; if(i>0){ - var newRow=tr.clone(); + newRow=tr.clone(); newRow.find('a.expander').remove(); newRow.find('td.album a').text(''); newRow.find('td.artist a').text(''); }else{ - var newRow=tr; + newRow=tr; } newRow.find('td.title a').text(song.name); newRow.find('td.title a').click(function(event){ @@ -339,11 +341,11 @@ Collection={ path:song.song_path, playCount:song.song_playcount, }; - album.songs.push(songData) + album.songs.push(songData); artist.songs.push(songData); Collection.songs.push(songData); } -} +}; $(document).ready(function(){ Collection.parent=$('#collection'); diff --git a/apps/media/js/loader.js b/apps/media/js/loader.js index 055f858ae1..a832180d1e 100644 --- a/apps/media/js/loader.js +++ b/apps/media/js/loader.js @@ -1,7 +1,7 @@ function musicTypeFromFile(file){ var extention=file.substr(file.indexOf('.')+1); if(extention=='ogg'){ - return 'oga' + return 'oga'; } //TODO check for more specific cases return extention; @@ -39,7 +39,7 @@ function loadPlayer(type,ready){ } $(document).ready(function() { - loadPlayer.done=false + loadPlayer.done=false; // FileActions.register('audio','Add to playlist','',addAudio); // FileActions.register('application/ogg','Add to playlist','',addAudio); diff --git a/apps/media/js/music.js b/apps/media/js/music.js index 3373cbac25..1ffe4e1008 100644 --- a/apps/media/js/music.js +++ b/apps/media/js/music.js @@ -16,7 +16,7 @@ $(document).ready(function(){ PlayList.render(); }); var button=$(''); - button.css('background-image','url('+OC.imagePath('core','actions/play-add')+')') + button.css('background-image','url('+OC.imagePath('core','actions/play-add')+')'); button.click(function(event){ event.stopPropagation(); PlayList.add(media); @@ -24,7 +24,7 @@ $(document).ready(function(){ }); row.find('div.name').append(button); button.tipsy({gravity:'n', fade:true, delayIn: 400, live:true}); - } + }; Collection.display(); Collection.load(function(){ @@ -34,11 +34,9 @@ $(document).ready(function(){ PlayList.add(song); PlayList.play(0); } - }) + }); }); - - function getUrlVars(){ var vars = {}, hash; var hashes = window.location.hash.substr(1).split('&'); @@ -52,8 +50,8 @@ function getUrlVars(){ function musicTypeFromFile(file){ var extention=file.split('.').pop(); if(extention=='ogg'){ - return 'oga' + return 'oga'; } //TODO check for more specific cases return extention; -} \ No newline at end of file +} diff --git a/apps/media/js/playlist.js b/apps/media/js/playlist.js index 089065989a..8e9e2a9153 100644 --- a/apps/media/js/playlist.js +++ b/apps/media/js/playlist.js @@ -26,19 +26,19 @@ PlayList.render=function(){ li.click(function(event){ PlayList.play($(this).data('index')); }); - li.append(img) + li.append(img); li.data('index',i); li.addClass('song'); PlayList.parent.append(li); } $(".jp-playlist-" + PlayList.current).addClass("collection_playing"); -} +}; PlayList.getSelected=function(){ return $('tbody td.name input:checkbox:checked').parent().parent(); -} +}; PlayList.hide=function(){ $('#playlist').hide(); -} +}; $(document).ready(function(){ PlayList.parent=$('#leftcontent'); diff --git a/apps/media/js/scanner.js b/apps/media/js/scanner.js index 0baa9db419..6c991b60d5 100644 --- a/apps/media/js/scanner.js +++ b/apps/media/js/scanner.js @@ -6,7 +6,7 @@ Scanner={ $.getJSON(OC.linkTo('media','ajax/api.php')+'?action=find_music',function(songs){ Scanner.songsFound=songs.length; if(ready){ - ready(songs) + ready(songs); } }); }, @@ -24,13 +24,13 @@ Scanner={ Scanner.songsScanned=data.count; $('#scan span.songCount').text(Scanner.songsScanned); var progress=(Scanner.songsScanned/Scanner.songsFound)*100; - $('#scanprogressbar').progressbar('value',progress) + $('#scanprogressbar').progressbar('value',progress); }); Scanner.eventSource.listen('done',function(count){ $('#scan input.start').show(); $('#scan input.stop').hide(); $('#scanprogressbar').hide(); - Collection.load(Collection.display) + Collection.load(Collection.display); if(ready){ ready(); } @@ -41,4 +41,4 @@ Scanner={ Scanner.close(); }, -} +}; diff --git a/core/css/styles.css b/core/css/styles.css index 53af8b383e..335b008ffd 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -3,6 +3,7 @@ See the COPYING-README file. */ html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, dialog, figure, footer, header, hgroup, nav, section { margin:0; padding:0; border:0; outline:0; font-weight:inherit; font-size:100%; font-family:inherit; vertical-align:baseline; cursor:default; } +html, body { height: 100%; } article, aside, dialog, figure, footer, header, hgroup, nav, section { display:block; } body { line-height:1.5; } table { border-collapse:separate; border-spacing:0; white-space:nowrap; } @@ -55,11 +56,11 @@ input[type="submit"].highlight{ background:#ffc100; border:1px solid #db0; text- /* CONTENT ------------------------------------------------------------------ */ #controls { padding: 0 0.5em; width:100%; top:3.5em; height:2.8em; margin:0; background:#f7f7f7; border-bottom:1px solid #eee; position:fixed; z-index:50; -moz-box-shadow:0 -3px 7px #000; -webkit-box-shadow:0 -3px 7px #000; box-shadow:0 -3px 7px #000; } #controls .button { display:inline-block; } -#content { margin:3.5em 0 0 12.5em; } +#content { top: 3.5em; left: 12.5em; position: absolute; } #leftcontent, .leftcontent { position:fixed; overflow: auto; top:6.4em; width:20em; background:#f8f8f8; border-right:1px solid #ddd; } #leftcontent li, .leftcontent li { background:#f8f8f8; padding:.3em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 500ms; -moz-transition:background-color 500ms; -o-transition:background-color 500ms; transition:background-color 500ms; } #leftcontent li:hover, #leftcontent li:active, #leftcontent li.active, .leftcontent li:hover, .leftcontent li:active, .leftcontent li.active { background:#eee; } -#rightcontent, .rightcontent { position:absolute; top:6.4em; left:33em; } +#rightcontent, .rightcontent { position:fixed; top: 6.4em; left: 32.5em; } /* LOG IN & INSTALLATION ------------------------------------------------------------ */ @@ -113,8 +114,8 @@ table:not(.nostyle) tr { -webkit-transition:background-color 500ms; -moz-transit tbody tr:hover, tr:active { background-color:#f8f8f8; } #body-settings .personalblock, #body-settings .helpblock { padding:.5em 1em; margin:1em; background:#f8f8f8; color:#555; text-shadow:#fff 0 1px 0; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; } -#body-settings .personalblock#quota { position:relative; margin-top:4.5em; padding:0; } -#body-settings #controls+.helpblock { position:relative; margin-top:7.3em; } +#body-settings .personalblock#quota { position:relative; padding:0; } +#body-settings #controls+.helpblock { position:relative; margin-top: 3em; } .personalblock > legend { margin-top:2em; } #quota div, div.jp-play-bar, div.jp-seek-bar { padding:0; background:#e6e6e6; font-weight:normal; white-space:nowrap; -moz-border-radius-bottomleft:.4em; -webkit-border-bottom-left-radius:.4em; border-bottom-left-radius:.4em; -moz-border-radius-topleft:.4em; -webkit-border-top-left-radius:.4em; border-top-left-radius:.4em; } diff --git a/core/js/js.js b/core/js/js.js index c6cde3cea9..6da9c29e69 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -13,7 +13,7 @@ function t(app,text){ success:function(jsondata){ t.cache[app] = jsondata.data; }, - }) + }); // Bad answer ... if( !( app in t.cache )){ @@ -58,7 +58,7 @@ OC={ } link+=app; if(type){ - link+=type+'/' + link+=type+'/'; } link+=file; return link; @@ -73,7 +73,7 @@ OC={ */ imagePath:function(app,file){ if(file.indexOf('.')==-1){//if no extention is given, use png or svg depending on browser support - file+=(SVGSupport())?'.svg':'.png' + file+=(SVGSupport())?'.svg':'.png'; } return OC.filePath(app,'img',file); }, @@ -126,7 +126,7 @@ OC={ }); } } -} +}; OC.search.customResults={}; OC.search.currentResult=-1; OC.search.lastQuery=''; @@ -147,7 +147,7 @@ if(typeof localStorage !='undefined'){ getItem:function(name){ return JSON.parse(localStorage.getItem(OC.localStorage.namespace+name)); } - } + }; }else{ //dummy localstorage OC.localStorage={ @@ -160,7 +160,7 @@ if(typeof localStorage !='undefined'){ getItem:function(name){ return null; } - } + }; } /** @@ -182,7 +182,7 @@ if (!Array.prototype.filter) { } } return res; - } + }; } /** * implement Array.indexOf for browsers without native support @@ -235,11 +235,11 @@ SVGSupport.checkMimeType=function(){ }); if(headers["Content-Type"]!='image/svg+xml'){ replaceSVG(); - SVGSupport.checkMimeType.correct=false + SVGSupport.checkMimeType.correct=false; } } }); -} +}; SVGSupport.checkMimeType.correct=true; //replace all svg images with png for browser compatibility @@ -305,11 +305,12 @@ $(document).ready(function(){ $(window).resize(function () { fillHeight($('#leftcontent')); + fillWindow($('#content')); fillWindow($('#rightcontent')); }); $(window).trigger('resize'); - if(!SVGSupport()){//replace all svg images with png images for browser that dont support svg + if(!SVGSupport()){ //replace all svg images with png images for browser that dont support svg replaceSVG(); }else{ SVGSupport.checkMimeType(); @@ -379,7 +380,6 @@ $(document).ready(function(){ } }); - if($('body').attr("id")=="body-user") { $('#settings #expanddiv').hide(); } $('#settings #expand').click(function(event) { $('#settings #expanddiv').slideToggle(); event.stopPropagation(); diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php index 64353d4d4f..c048653cce 100644 --- a/core/templates/layout.user.php +++ b/core/templates/layout.user.php @@ -44,8 +44,8 @@