diff options
author | Bart Visscher <bartv@thisnet.nl> | 2012-10-17 16:38:11 +0200 |
---|---|---|
committer | Bart Visscher <bartv@thisnet.nl> | 2012-10-17 16:38:11 +0200 |
commit | 6081bfa2bcbe121e373486273ecce58a49e6fa97 (patch) | |
tree | f2504800c66919a53eff9323724b493079569495 /lib | |
parent | c2b4e534534e083147bbad9b564179832cfa2912 (diff) | |
parent | 44287d680bd0e8799724a7595db43c0fafcaff40 (diff) | |
download | nextcloud-server-6081bfa2bcbe121e373486273ecce58a49e6fa97.tar.gz nextcloud-server-6081bfa2bcbe121e373486273ecce58a49e6fa97.zip |
Merge branch 'master' into routing
Conflicts:
lib/search/provider/file.php
settings/ajax/changepassword.php
settings/settings.php
Diffstat (limited to 'lib')
38 files changed, 632 insertions, 171 deletions
diff --git a/lib/app.php b/lib/app.php index 71add883802..21ba14f1db1 100755 --- a/lib/app.php +++ b/lib/app.php @@ -63,7 +63,7 @@ class OC_App{ if (!defined('DEBUG') || !DEBUG) { if (is_null($types) - && empty(OC_Util::$core_scripts) + && empty(OC_Util::$core_scripts) && empty(OC_Util::$core_styles)) { OC_Util::$core_scripts = OC_Util::$scripts; OC_Util::$scripts = array(); @@ -390,9 +390,8 @@ class OC_App{ */ public static function getAppVersion($appid) { $file= self::getAppPath($appid).'/appinfo/version'; - $version=@file_get_contents($file); - if($version) { - return trim($version); + if(is_file($file) && $version = trim(file_get_contents($file))) { + return $version; }else{ $appData=self::getAppInfo($appid); return isset($appData['version'])? $appData['version'] : ''; @@ -458,7 +457,7 @@ class OC_App{ } } self::$appInfo[$appid]=$data; - + return $data; } @@ -551,83 +550,78 @@ class OC_App{ * @todo: change the name of this method to getInstalledApps, which is more accurate */ public static function getAllApps() { - + $apps=array(); - + foreach ( OC::$APPSROOTS as $apps_dir ) { if(! is_readable($apps_dir['path'])) { OC_Log::write('core', 'unable to read app folder : ' .$apps_dir['path'] , OC_Log::WARN); continue; } $dh = opendir( $apps_dir['path'] ); - + while( $file = readdir( $dh ) ) { - - if ( - $file[0] != '.' - and is_file($apps_dir['path'].'/'.$file.'/appinfo/app.php' ) + + if ( + $file[0] != '.' + and is_file($apps_dir['path'].'/'.$file.'/appinfo/app.php' ) ) { - + $apps[] = $file; - + } - + } - + } - + return $apps; } - + /** * @brief: get a list of all apps on apps.owncloud.com * @return array, multi-dimensional array of apps. Keys: id, name, type, typename, personid, license, detailpage, preview, changed, description */ public static function getAppstoreApps( $filter = 'approved' ) { - $catagoryNames = OC_OCSClient::getCategories(); - if ( is_array( $catagoryNames ) ) { - // Check that categories of apps were retrieved correctly if ( ! $categories = array_keys( $catagoryNames ) ) { - return false; - } - + $page = 0; - $remoteApps = OC_OCSClient::getApplications( $categories, $page, $filter ); - $app1 = array(); - $i = 0; - foreach ( $remoteApps as $app ) { - $app1[$i] = $app; - $app1[$i]['author'] = $app['personid']; - $app1[$i]['ocs_id'] = $app['id']; - $app1[$i]['internal'] = $app1[$i]['active'] = 0; - + + // rating img + if($app['score']>=0 and $app['score']<5) $img=OC_Helper::imagePath( "core", "rating/s1.png" ); + elseif($app['score']>=5 and $app['score']<15) $img=OC_Helper::imagePath( "core", "rating/s2.png" ); + elseif($app['score']>=15 and $app['score']<25) $img=OC_Helper::imagePath( "core", "rating/s3.png" ); + elseif($app['score']>=25 and $app['score']<35) $img=OC_Helper::imagePath( "core", "rating/s4.png" ); + elseif($app['score']>=35 and $app['score']<45) $img=OC_Helper::imagePath( "core", "rating/s5.png" ); + elseif($app['score']>=45 and $app['score']<55) $img=OC_Helper::imagePath( "core", "rating/s6.png" ); + elseif($app['score']>=55 and $app['score']<65) $img=OC_Helper::imagePath( "core", "rating/s7.png" ); + elseif($app['score']>=65 and $app['score']<75) $img=OC_Helper::imagePath( "core", "rating/s8.png" ); + elseif($app['score']>=75 and $app['score']<85) $img=OC_Helper::imagePath( "core", "rating/s9.png" ); + elseif($app['score']>=85 and $app['score']<95) $img=OC_Helper::imagePath( "core", "rating/s10.png" ); + elseif($app['score']>=95 and $app['score']<100) $img=OC_Helper::imagePath( "core", "rating/s11.png" ); + + $app1[$i]['score'] = '<img src="'.$img.'"> Score: '.$app['score'].'%'; $i++; - } - } - + if ( empty( $app1 ) ) { - return false; - } else { - return $app1; - } } @@ -671,7 +665,7 @@ class OC_App{ foreach($apps as $app) { // check if the app is compatible with this version of ownCloud $info = OC_App::getAppInfo($app); - if(!isset($info['require']) or ($version[0]>$info['require'])) { + if(!isset($info['require']) or (($version[0].'.'.$version[1])>$info['require'])) { OC_Log::write('core', 'App "'.$info['name'].'" ('.$app.') can\'t be used because it is not compatible with this version of ownCloud', OC_Log::ERROR); OC_App::disable( $app ); } diff --git a/lib/archive.php b/lib/archive.php index b4459c2b6ce..a9c245eaf43 100644 --- a/lib/archive.php +++ b/lib/archive.php @@ -13,14 +13,14 @@ abstract class OC_Archive{ * @return OC_Archive */ public static function open($path) { - $ext=substr($path,strrpos($path,'.')); + $ext=substr($path, strrpos($path, '.')); switch($ext) { case '.zip': return new OC_Archive_ZIP($path); case '.gz': case '.bz': case '.bz2': - if(strpos($path,'.tar.')) { + if(strpos($path, '.tar.')) { return new OC_Archive_TAR($path); } break; @@ -126,9 +126,9 @@ abstract class OC_Archive{ continue; } if(is_dir($source.'/'.$file)) { - $this->addRecursive($path.'/'.$file,$source.'/'.$file); + $this->addRecursive($path.'/'.$file, $source.'/'.$file); }else{ - $this->addFile($path.'/'.$file,$source.'/'.$file); + $this->addFile($path.'/'.$file, $source.'/'.$file); } } } diff --git a/lib/archive/tar.php b/lib/archive/tar.php index 639d2392b63..86d39b88968 100644 --- a/lib/archive/tar.php +++ b/lib/archive/tar.php @@ -6,7 +6,7 @@ * See the COPYING-README file. */ -require_once 'Archive/Tar.php'; +require_once '3rdparty/Archive/Tar.php'; class OC_Archive_TAR extends OC_Archive{ const PLAIN=0; @@ -14,6 +14,7 @@ class OC_Archive_TAR extends OC_Archive{ const BZIP=2; private $fileList; + private $cachedHeaders; /** * @var Archive_Tar tar @@ -74,6 +75,7 @@ class OC_Archive_TAR extends OC_Archive{ $result=$this->tar->addModify(array($tmpBase.$path), '', $tmpBase); rmdir($tmpBase.$path); $this->fileList=false; + $this->cachedHeaders=false; return $result; } /** @@ -95,6 +97,7 @@ class OC_Archive_TAR extends OC_Archive{ $result=$this->tar->addString($path, $source); } $this->fileList=false; + $this->cachedHeaders=false; return $result; } @@ -115,13 +118,20 @@ class OC_Archive_TAR extends OC_Archive{ $this->tar=new Archive_Tar($this->path, $types[self::getTarType($this->path)]); $this->tar->createModify(array($tmp), '', $tmp.'/'); $this->fileList=false; + $this->cachedHeaders=false; return true; } private function getHeader($file) { - $headers=$this->tar->listContent(); - foreach($headers as $header) { - if($file==$header['filename'] or $file.'/'==$header['filename'] or '/'.$file.'/'==$header['filename'] or '/'.$file==$header['filename']) { + if ( ! $this->cachedHeaders ) { + $this->cachedHeaders = $this->tar->listContent(); + } + foreach($this->cachedHeaders as $header) { + if( $file == $header['filename'] + or $file.'/' == $header['filename'] + or '/'.$file.'/' == $header['filename'] + or '/'.$file == $header['filename']) + { return $header; } } @@ -180,9 +190,11 @@ class OC_Archive_TAR extends OC_Archive{ if($this->fileList) { return $this->fileList; } - $headers=$this->tar->listContent(); + if ( ! $this->cachedHeaders ) { + $this->cachedHeaders = $this->tar->listContent(); + } $files=array(); - foreach($headers as $header) { + foreach($this->cachedHeaders as $header) { $files[]=$header['filename']; } $this->fileList=$files; @@ -265,6 +277,7 @@ class OC_Archive_TAR extends OC_Archive{ return false; } $this->fileList=false; + $this->cachedHeaders=false; //no proper way to delete, extract entire archive, delete file and remake archive $tmp=OCP\Files::tmpFolder(); $this->tar->extract($tmp); diff --git a/lib/archive/zip.php b/lib/archive/zip.php index a2b07f1a35d..d016c692e35 100644 --- a/lib/archive/zip.php +++ b/lib/archive/zip.php @@ -86,7 +86,7 @@ class OC_Archive_ZIP extends OC_Archive{ $pathLength=strlen($path); foreach($files as $file) { if(substr($file, 0, $pathLength)==$path and $file!=$path) { - if(strrpos(substr($file, 0, -1),'/')<=$pathLength) { + if(strrpos(substr($file, 0, -1), '/')<=$pathLength) { $folderContent[]=substr($file, $pathLength); } } @@ -161,7 +161,10 @@ class OC_Archive_ZIP extends OC_Archive{ function getStream($path,$mode) { if($mode=='r' or $mode=='rb') { return $this->zip->getStream($path); - }else{//since we cant directly get a writable stream, make a temp copy of the file and put it back in the archive when the stream is closed + } else { + //since we cant directly get a writable stream, + //make a temp copy of the file and put it back + //in the archive when the stream is closed if(strrpos($path, '.')!==false) { $ext=substr($path, strrpos($path, '.')); }else{ diff --git a/lib/base.php b/lib/base.php index f7967329c29..c8a54d1c659 100644 --- a/lib/base.php +++ b/lib/base.php @@ -76,11 +76,14 @@ class OC{ */ public static function autoload($className) { if(array_key_exists($className, OC::$CLASSPATH)) { + $path = OC::$CLASSPATH[$className]; /** @TODO: Remove this when necessary Remove "apps/" from inclusion path for smooth migration to mutli app dir */ - $path = str_replace('apps/', '', OC::$CLASSPATH[$className]); - require_once $path; + if (strpos($path, 'apps/')===0) { + OC_Log::write('core', 'include path for class "'.$className.'" starts with "apps/"', OC_Log::DEBUG); + $path = str_replace('apps/', '', $path); + } } elseif(strpos($className, 'OC_')===0) { $path = strtolower(str_replace('_', '/', substr($className, 3)) . '.php'); @@ -104,14 +107,14 @@ class OC{ } if($fullPath = stream_resolve_include_path($path)) { - require_once $path; + require_once $fullPath; } return false; } public static function initPaths() { // calculate the root directories - OC::$SERVERROOT=str_replace("\\", '/', substr(__FILE__, 0, -13)); + OC::$SERVERROOT=str_replace("\\", '/', substr(__DIR__, 0, -4)); OC::$SUBURI= str_replace("\\", "/", substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen(OC::$SERVERROOT))); $scriptName=$_SERVER["SCRIPT_NAME"]; if(substr($scriptName, -1)=='/') { @@ -200,6 +203,7 @@ class OC{ public static function checkSSL() { // redirect to https site if configured if( OC_Config::getValue( "forcessl", false )) { + header('Strict-Transport-Security: max-age=31536000'); ini_set("session.cookie_secure", "on"); if(OC_Request::serverProtocol()<>'https' and !OC::$CLI) { $url = "https://". OC_Request::serverHost() . $_SERVER['REQUEST_URI']; @@ -268,8 +272,30 @@ class OC{ } public static function initSession() { + // prevents javascript from accessing php session cookies ini_set('session.cookie_httponly', '1;'); + + // (re)-initialize session session_start(); + + // regenerate session id periodically to avoid session fixation + if (!isset($_SESSION['SID_CREATED'])) { + $_SESSION['SID_CREATED'] = time(); + } else if (time() - $_SESSION['SID_CREATED'] > 900) { + session_regenerate_id(true); + $_SESSION['SID_CREATED'] = time(); + } + + // session timeout + if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 3600)) { + if (isset($_COOKIE[session_name()])) { + setcookie(session_name(), '', time() - 42000, '/'); + } + session_unset(); + session_destroy(); + session_start(); + } + $_SESSION['LAST_ACTIVITY'] = time(); } public static function getRouter() { @@ -298,7 +324,7 @@ class OC{ ini_set('arg_separator.output', '&'); // try to switch magic quotes off. - if(function_exists('set_magic_quotes_runtime')) { + if(get_magic_quotes_gpc()) { @set_magic_quotes_runtime(false); } @@ -336,6 +362,10 @@ class OC{ self::initPaths(); + register_shutdown_function(array('OC_Log', 'onShutdown')); + set_error_handler(array('OC_Log', 'onError')); + set_exception_handler(array('OC_Log', 'onException')); + // set debug mode if an xdebug session is active if (!defined('DEBUG') || !DEBUG) { if(isset($_COOKIE['XDEBUG_SESSION'])) { @@ -369,6 +399,10 @@ class OC{ OC_User::useBackend(new OC_User_Database()); OC_Group::useBackend(new OC_Group_Database()); + if(isset($_SERVER['PHP_AUTH_USER']) && isset($_SESSION['user_id']) && $_SERVER['PHP_AUTH_USER'] != $_SESSION['user_id']) { + OC_User::logout(); + } + // Load Apps // This includes plugins for users and filesystems as well global $RUNTIME_NOAPPS; @@ -470,6 +504,7 @@ class OC{ OC_App::loadApps(); OC_User::setupBackends(); if(isset($_GET["logout"]) and ($_GET["logout"])) { + OC_Preferences::deleteKey(OC_User::getUser(), 'login_token', $_COOKIE['oc_token']); OC_User::logout(); header("Location: ".OC::$WEBROOT.'/'); }else{ @@ -517,20 +552,31 @@ class OC{ protected static function handleLogin() { OC_App::loadApps(array('prelogin')); - $error = false; + $error = array(); // remember was checked after last login if (OC::tryRememberLogin()) { - // nothing more to do + $error[] = 'invalidcookie'; // Someone wants to log in : } elseif (OC::tryFormLogin()) { - $error = true; + $error[] = 'invalidpassword'; // The user is already authenticated using Apaches AuthType Basic... very usable in combination with LDAP } elseif (OC::tryBasicAuthLogin()) { - $error = true; + $error[] = 'invalidpassword'; + } + OC_Util::displayLoginPage(array_unique($error)); + } + + protected static function cleanupLoginTokens($user) { + $cutoff = time() - OC_Config::getValue('remember_login_cookie_lifetime', 60*60*24*15); + $tokens = OC_Preferences::getKeys($user, 'login_token'); + foreach($tokens as $token) { + $time = OC_Preferences::getValue($user, 'login_token', $token); + if ($time < $cutoff) { + OC_Preferences::deleteKey($user, 'login_token', $token); + } } - OC_Util::displayLoginPage($error); } protected static function tryRememberLogin() { @@ -546,24 +592,35 @@ class OC{ OC_Log::write('core', 'Trying to login from cookie', OC_Log::DEBUG); } // confirm credentials in cookie - if(isset($_COOKIE['oc_token']) && OC_User::userExists($_COOKIE['oc_username']) && - OC_Preferences::getValue($_COOKIE['oc_username'], "login", "token") === $_COOKIE['oc_token']) - { - OC_User::setUserId($_COOKIE['oc_username']); - OC_Util::redirectToDefaultPage(); - } - else { - OC_User::unsetMagicInCookie(); + if(isset($_COOKIE['oc_token']) && OC_User::userExists($_COOKIE['oc_username'])) { + // delete outdated cookies + self::cleanupLoginTokens($_COOKIE['oc_username']); + // get stored tokens + $tokens = OC_Preferences::getKeys($_COOKIE['oc_username'], 'login_token'); + // test cookies token against stored tokens + if (in_array($_COOKIE['oc_token'], $tokens, true)) { + // replace successfully used token with a new one + OC_Preferences::deleteKey($_COOKIE['oc_username'], 'login_token', $_COOKIE['oc_token']); + $token = OC_Util::generate_random_bytes(32); + OC_Preferences::setValue($_COOKIE['oc_username'], 'login_token', $token, time()); + OC_User::setMagicInCookie($_COOKIE['oc_username'], $token); + // login + OC_User::setUserId($_COOKIE['oc_username']); + OC_Util::redirectToDefaultPage(); + // doesn't return + } + // if you reach this point you have changed your password + // or you are an attacker + // we can not delete tokens here because users may reach + // this point multiple times after a password change + OC_Log::write('core', 'Authentication cookie rejected for user '.$_COOKIE['oc_username'], OC_Log::WARN); } + OC_User::unsetMagicInCookie(); return true; } protected static function tryFormLogin() { - if(!isset($_POST["user"]) - || !isset($_POST['password']) - || !isset($_SESSION['sectoken']) - || !isset($_POST['sectoken']) - || ($_SESSION['sectoken']!=$_POST['sectoken']) ) { + if(!isset($_POST["user"]) || !isset($_POST['password'])) { return false; } @@ -573,18 +630,20 @@ class OC{ OC_User::setupBackends(); if(OC_User::login($_POST["user"], $_POST["password"])) { + self::cleanupLoginTokens($_POST['user']); if(!empty($_POST["remember_login"])) { if(defined("DEBUG") && DEBUG) { OC_Log::write('core', 'Setting remember login to cookie', OC_Log::DEBUG); } - $token = md5($_POST["user"].time().$_POST['password']); - OC_Preferences::setValue($_POST['user'], 'login', 'token', $token); + $token = OC_Util::generate_random_bytes(32); + OC_Preferences::setValue($_POST['user'], 'login_token', $token, time()); OC_User::setMagicInCookie($_POST["user"], $token); } else { OC_User::unsetMagicInCookie(); } - OC_Util::redirectToDefaultPage(); + header( 'Location: '.$_SERVER['REQUEST_URI'] ); + exit(); } return true; } diff --git a/lib/connector/sabre/directory.php b/lib/connector/sabre/directory.php index 413efef73b7..b6e02569d2a 100644 --- a/lib/connector/sabre/directory.php +++ b/lib/connector/sabre/directory.php @@ -200,7 +200,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa public function getProperties($properties) { $props = parent::getProperties($properties); if (in_array(self::GETETAG_PROPERTYNAME, $properties) && !isset($props[self::GETETAG_PROPERTYNAME])) { - $props[self::GETETAG_PROPERTYNAME] + $props[self::GETETAG_PROPERTYNAME] = OC_Connector_Sabre_Node::getETagPropertyForPath($this->path); } return $props; diff --git a/lib/connector/sabre/node.php b/lib/connector/sabre/node.php index bdedc030c88..72de9723774 100644 --- a/lib/connector/sabre/node.php +++ b/lib/connector/sabre/node.php @@ -24,7 +24,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IProperties { const GETETAG_PROPERTYNAME = '{DAV:}getetag'; const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified'; - + /** * The path to the current node * @@ -235,7 +235,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr static public function removeETagPropertyForPath($path) { // remove tags from this and parent paths $paths = array(); - while ($path != '/' && $path != '.' && $path != '') { + while ($path != '/' && $path != '.' && $path != '' && $path != '\\') { $paths[] = $path; $path = dirname($path); } diff --git a/lib/connector/sabre/principal.php b/lib/connector/sabre/principal.php index ee95ae63306..763503721f8 100644 --- a/lib/connector/sabre/principal.php +++ b/lib/connector/sabre/principal.php @@ -115,11 +115,11 @@ class OC_Connector_Sabre_Principal implements Sabre_DAVACL_IPrincipalBackend { public function setGroupMemberSet($principal, array $members) { throw new Sabre_DAV_Exception('Setting members of the group is not supported yet'); } - + function updatePrincipal($path, $mutations) { return 0; } - + function searchPrincipals($prefixPath, array $searchProperties) { return 0; } diff --git a/lib/db.php b/lib/db.php index 256ae5b6bf3..a43f2ad20b2 100644 --- a/lib/db.php +++ b/lib/db.php @@ -391,7 +391,7 @@ class OC_DB { * * TODO: write more documentation */ - public static function getDbStructure( $file ,$mode=MDB2_SCHEMA_DUMP_STRUCTURE) { + public static function getDbStructure( $file, $mode=MDB2_SCHEMA_DUMP_STRUCTURE) { self::connectScheme(); // write the scheme @@ -427,14 +427,14 @@ class OC_DB { $file2 = 'static://db_scheme'; $content = str_replace( '*dbname*', $CONFIG_DBNAME, $content ); $content = str_replace( '*dbprefix*', $CONFIG_DBTABLEPREFIX, $content ); - /* FIXME: REMOVE this commented code - * actually mysql, postgresql, sqlite and oracle support CURRENT_TIMESTAMP + /* FIXME: use CURRENT_TIMESTAMP for all databases. mysql supports it as a default for DATETIME since 5.6.5 [1] + * as a fallback we could use <default>0000-01-01 00:00:00</default> everywhere + * [1] http://bugs.mysql.com/bug.php?id=27645 * http://dev.mysql.com/doc/refman/5.0/en/timestamp-initialization.html * http://www.postgresql.org/docs/8.1/static/functions-datetime.html * http://www.sqlite.org/lang_createtable.html * http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions037.htm */ - if( $CONFIG_DBTYPE == 'pgsql' ) { //mysql support it too but sqlite doesn't $content = str_replace( '<default>0000-00-00 00:00:00</default>', '<default>CURRENT_TIMESTAMP</default>', $content ); } @@ -475,6 +475,7 @@ class OC_DB { */ public static function updateDbFromStructure($file) { $CONFIG_DBTABLEPREFIX = OC_Config::getValue( "dbtableprefix", "oc_" ); + $CONFIG_DBTYPE = OC_Config::getValue( "dbtype", "sqlite" ); self::connectScheme(); @@ -493,16 +494,17 @@ class OC_DB { $file2 = 'static://db_scheme'; $content = str_replace( '*dbname*', $previousSchema['name'], $content ); $content = str_replace( '*dbprefix*', $CONFIG_DBTABLEPREFIX, $content ); - /* FIXME: REMOVE this commented code - * actually mysql, postgresql, sqlite and oracle support CUURENT_TIMESTAMP + /* FIXME: use CURRENT_TIMESTAMP for all databases. mysql supports it as a default for DATETIME since 5.6.5 [1] + * as a fallback we could use <default>0000-01-01 00:00:00</default> everywhere + * [1] http://bugs.mysql.com/bug.php?id=27645 * http://dev.mysql.com/doc/refman/5.0/en/timestamp-initialization.html * http://www.postgresql.org/docs/8.1/static/functions-datetime.html * http://www.sqlite.org/lang_createtable.html * http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions037.htm + */ if( $CONFIG_DBTYPE == 'pgsql' ) { //mysql support it too but sqlite doesn't $content = str_replace( '<default>0000-00-00 00:00:00</default>', '<default>CURRENT_TIMESTAMP</default>', $content ); } - */ file_put_contents( $file2, $content ); $op = self::$schema->updateDatabase($file2, $previousSchema, array(), false); @@ -681,7 +683,7 @@ class OC_DB { return false; } } - + /** * returns the error code and message as a string for logging * works with MDB2 and PDOException diff --git a/lib/filecache.php b/lib/filecache.php index 07099bcccd5..a36cfef6759 100644 --- a/lib/filecache.php +++ b/lib/filecache.php @@ -79,7 +79,7 @@ class OC_FileCache{ // add parent directory to the file cache if it does not exist yet. if ($parent == -1 && $fullpath != $root) { - $parentDir = substr(dirname($path), 0, strrpos(dirname($path), DIRECTORY_SEPARATOR)); + $parentDir = dirname($path); self::scanFile($parentDir); $parent = self::getParentId($fullpath); } @@ -203,7 +203,7 @@ class OC_FileCache{ OC_Cache::remove('fileid/'.$root.$path); } - + /** * return array of filenames matching the querty * @param string $query @@ -420,6 +420,7 @@ class OC_FileCache{ $mimetype=$view->getMimeType($path); $stat=$view->stat($path); if($mimetype=='httpd/unix-directory') { + $stat['size'] = 0; $writable=$view->is_writable($path.'/'); }else{ $writable=$view->is_writable($path); @@ -488,9 +489,24 @@ class OC_FileCache{ $query->execute(); } } + + /** + * trigger an update for the cache by setting the mtimes to 0 + * @param string $user (optional) + */ + public static function triggerUpdate($user=''){ + if($user) { + $query=OC_DB::prepare('UPDATE `*PREFIX*fscache` SET `mtime`=0 WHERE `user`=? AND `mimetype`="httpd/unix-directory"'); + $query->execute(array($user)); + }else{ + $query=OC_DB::prepare('UPDATE `*PREFIX*fscache` SET `mtime`=0 AND `mimetype`="httpd/unix-directory"'); + $query->execute(); + } + } } //watch for changes and try to keep the cache up to date OC_Hook::connect('OC_Filesystem','post_write','OC_FileCache_Update','fileSystemWatcherWrite'); OC_Hook::connect('OC_Filesystem','post_delete','OC_FileCache_Update','fileSystemWatcherDelete'); OC_Hook::connect('OC_Filesystem','post_rename','OC_FileCache_Update','fileSystemWatcherRename'); +OC_Hook::connect('OC_User','post_deleteUser','OC_FileCache_Update','deleteFromUser'); diff --git a/lib/filecache/update.php b/lib/filecache/update.php index 2b64a2a90ff..f9d64d0ae99 100644 --- a/lib/filecache/update.php +++ b/lib/filecache/update.php @@ -81,10 +81,13 @@ class OC_FileCache_Update{ $dh=$view->opendir($path.'/'); if($dh) {//check for changed/new files while (($filename = readdir($dh)) !== false) { - if($filename != '.' and $filename != '..') { + if($filename != '.' and $filename != '..' and $filename != '') { $file=$path.'/'.$filename; - if(self::hasUpdated($file, $root)) { - if($root===false) {//filesystem hooks are only valid for the default root + $isDir=$view->is_dir($file); + if(self::hasUpdated($file, $root, $isDir)) { + if($isDir){ + self::updateFolder($file, $root); + }elseif($root===false) {//filesystem hooks are only valid for the default root OC_Hook::emit('OC_Filesystem', 'post_write', array('path'=>$file)); }else{ self::update($file, $root); @@ -136,7 +139,7 @@ class OC_FileCache_Update{ } /** - * update the filecache according to changes to the fileysystem + * update the filecache according to changes to the filesystem * @param string path * @param string root (optional) */ @@ -171,7 +174,9 @@ class OC_FileCache_Update{ }else{ $size=OC_FileCache::scanFile($path, $root); } - OC_FileCache::increaseSize(dirname($path), $size-$cachedSize, $root); + if($path !== '' and $path !== '/'){ + OC_FileCache::increaseSize(dirname($path), $size-$cachedSize, $root); + } } /** @@ -211,4 +216,12 @@ class OC_FileCache_Update{ OC_FileCache::increaseSize(dirname($newPath), $oldSize, $root); OC_FileCache::move($oldPath, $newPath); } -}
\ No newline at end of file + + /** + * delete files owned by user from the cache + * @param string $parameters$parameters["uid"]) + */ + public static function deleteFromUser($parameters) { + OC_FileCache::clear($parameters["uid"]); + } +} diff --git a/lib/fileproxy/fileoperations.php b/lib/fileproxy/fileoperations.php new file mode 100644 index 00000000000..23fb63fcfb1 --- /dev/null +++ b/lib/fileproxy/fileoperations.php @@ -0,0 +1,37 @@ +<?php +/** + * ownCloud + * + * @author Bjoern Schiessle + * @copyright 2012 Bjoern Schiessle <schiessle@owncloud.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +/** + * check if standard file operations + */ + +class OC_FileProxy_FileOperations extends OC_FileProxy{ + static $rootView; + + public function premkdir($path) { + if(!self::$rootView){ + self::$rootView = new OC_FilesystemView(''); + } + return !self::$rootView->file_exists($path); + } + +}
\ No newline at end of file diff --git a/lib/files.php b/lib/files.php index ac999a9bd15..2b2b8b42dc4 100644 --- a/lib/files.php +++ b/lib/files.php @@ -44,15 +44,16 @@ class OC_Files { public static function getFileInfo($path) { if (($path == '/Shared' || substr($path, 0, 8) == '/Shared/') && OC_App::isEnabled('files_sharing')) { if ($path == '/Shared') { - $info = OCP\Share::getItemsSharedWith('file', OC_Share_Backend_File::FORMAT_FILE_APP_ROOT); - } - else { - $path = substr($path, 7); - $info = OCP\Share::getItemSharedWith('file', $path, OC_Share_Backend_File::FORMAT_FILE_APP); + list($info) = OCP\Share::getItemsSharedWith('file', OC_Share_Backend_File::FORMAT_FILE_APP_ROOT); + }else{ + $info['size'] = OC_Filesystem::filesize($path); + $info['mtime'] = OC_Filesystem::filemtime($path); + $info['ctime'] = OC_Filesystem::filectime($path); + $info['mimetype'] = OC_Filesystem::getMimeType($path); + $info['encrypted'] = false; + $info['versioned'] = false; } - $info = $info[0]; - } - else { + } else { $info = OC_FileCache::get($path); } return $info; diff --git a/lib/filesystem.php b/lib/filesystem.php index c6da826a339..da524d7f181 100644 --- a/lib/filesystem.php +++ b/lib/filesystem.php @@ -240,7 +240,7 @@ class OC_Filesystem{ $mtime=filemtime(OC::$SERVERROOT.'/config/mount.php'); $previousMTime=OC_Appconfig::getValue('files','mountconfigmtime',0); if($mtime>$previousMTime) {//mount config has changed, filecache needs to be updated - OC_FileCache::clear(); + OC_FileCache::triggerUpdate(); OC_Appconfig::setValue('files','mountconfigmtime',$mtime); } } diff --git a/lib/helper.php b/lib/helper.php index f5eb2cc86bb..290d281c04c 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -47,6 +47,7 @@ class OC_Helper { * @param string $app app * @param string $file file * @param array $args array with param=>value, will be appended to the returned url + * The value of $args will be urlencoded * @return string the url * * Returns a url to the given app and file. @@ -79,7 +80,7 @@ class OC_Helper { if (!empty($args)) { $urlLinkTo .= '?'; foreach($args as $k => $v) { - $urlLinkTo .= '&'.$k.'='.$v; + $urlLinkTo .= '&'.$k.'='.urlencode($v); } } @@ -91,6 +92,7 @@ class OC_Helper { * @param string $app app * @param string $file file * @param array $args array with param=>value, will be appended to the returned url + * The value of $args will be urlencoded * @return string the url * * Returns a absolute url to the given app and file. @@ -113,6 +115,17 @@ class OC_Helper { } /** + * @brief Creates an url for remote use + * @param string $service id + * @return string the url + * + * Returns a url to the given service. + */ + public static function linkToRemoteBase( $service ) { + return self::linkTo( '', 'remote.php') . '/' . $service; + } + + /** * @brief Creates an absolute url for remote use * @param string $service id * @return string the url @@ -120,7 +133,7 @@ class OC_Helper { * Returns a absolute url to the given service. */ public static function linkToRemote( $service, $add_slash = true ) { - return self::linkToAbsolute( '', 'remote.php') . '/' . $service . (($add_slash && $service[strlen($service)-1]!='/')?'/':''); + return self::makeURLAbsolute(self::linkToRemoteBase($service)) . (($add_slash && $service[strlen($service)-1]!='/')?'/':''); } /** @@ -382,6 +395,7 @@ class OC_Helper { //trim the character set from the end of the response $mimeType=substr($reply,0,strrpos($reply,' ')); + $mimeType=substr($mimeType,0,strrpos($mimeType,"\n")); //trim ; if (strpos($mimeType, ';') !== false) { @@ -672,7 +686,7 @@ class OC_Helper { $length = mb_strlen($search, $encoding); while(($i = mb_strrpos($subject, $search, $offset, $encoding)) !== false ) { $subject = OC_Helper::mb_substr_replace($subject, $replace, $i, $length); - $offset = $i - mb_strlen($subject, $encoding) - 1; + $offset = $i - mb_strlen($subject, $encoding); $count++; } return $subject; diff --git a/lib/image.php b/lib/image.php index 861353e039d..016d20599b2 100644 --- a/lib/image.php +++ b/lib/image.php @@ -669,7 +669,7 @@ class OC_Image { $newWidth = min($maxWidth, $ratio*$maxHeight); $newHeight = min($maxHeight, $maxWidth/$ratio); - + $this->preciseResize(round($newWidth), round($newHeight)); return true; } diff --git a/lib/json.php b/lib/json.php index 518c3c87c49..cc504907261 100644 --- a/lib/json.php +++ b/lib/json.php @@ -58,6 +58,7 @@ class OC_JSON{ */ public static function checkAdminUser() { self::checkLoggedIn(); + self::verifyUser(); if( !OC_Group::inGroup( OC_User::getUser(), 'admin' )) { $l = OC_L10N::get('lib'); self::error(array( 'data' => array( 'message' => $l->t('Authentication error') ))); @@ -70,6 +71,7 @@ class OC_JSON{ */ public static function checkSubAdminUser() { self::checkLoggedIn(); + self::verifyUser(); if(!OC_Group::inGroup(OC_User::getUser(),'admin') && !OC_SubAdmin::isSubAdmin(OC_User::getUser())) { $l = OC_L10N::get('lib'); self::error(array( 'data' => array( 'message' => $l->t('Authentication error') ))); @@ -78,6 +80,19 @@ class OC_JSON{ } /** + * Check if the user verified the login with his password + */ + public static function verifyUser() { + if(OC_Config::getValue('enhancedauth', true) === true) { + if(!isset($_SESSION['verifiedLogin']) OR $_SESSION['verifiedLogin'] < time()) { + $l = OC_L10N::get('lib'); + self::error(array( 'data' => array( 'message' => $l->t('Authentication error') ))); + exit(); + } + } + } + + /** * Send json error msg */ public static function error($data = array()) { diff --git a/lib/l10n/de_DE.php b/lib/l10n/de_DE.php new file mode 100644 index 00000000000..8c81be16582 --- /dev/null +++ b/lib/l10n/de_DE.php @@ -0,0 +1,28 @@ +<?php $TRANSLATIONS = array( +"Help" => "Hilfe", +"Personal" => "Persönlich", +"Settings" => "Einstellungen", +"Users" => "Benutzer", +"Apps" => "Apps", +"Admin" => "Administrator", +"ZIP download is turned off." => "Der ZIP-Download ist deaktiviert.", +"Files need to be downloaded one by one." => "Die Dateien müssen einzeln heruntergeladen werden.", +"Back to Files" => "Zurück zu \"Dateien\"", +"Selected files too large to generate zip file." => "Die gewählten Dateien sind zu groß, um eine ZIP-Datei zu erstellen.", +"Application is not enabled" => "Die Anwendung ist nicht aktiviert", +"Authentication error" => "Authentifizierungs-Fehler", +"Token expired. Please reload page." => "Token abgelaufen. Bitte lade die Seite neu.", +"seconds ago" => "Vor wenigen Sekunden", +"1 minute ago" => "Vor einer Minute", +"%d minutes ago" => "Vor %d Minuten", +"today" => "Heute", +"yesterday" => "Gestern", +"%d days ago" => "Vor %d Tag(en)", +"last month" => "Letzten Monat", +"months ago" => "Vor Monaten", +"last year" => "Letztes Jahr", +"years ago" => "Vor Jahren", +"%s is available. Get <a href=\"%s\">more information</a>" => "%s ist verfügbar. <a href=\"%s\">Weitere Informationen</a>", +"up to date" => "aktuell", +"updates check is disabled" => "Die Update-Überprüfung ist ausgeschaltet" +); diff --git a/lib/l10n/nb_NO.php b/lib/l10n/nb_NO.php index f751a41d5eb..c43ada258d4 100644 --- a/lib/l10n/nb_NO.php +++ b/lib/l10n/nb_NO.php @@ -21,5 +21,8 @@ "last month" => "forrige måned", "months ago" => "måneder siden", "last year" => "i fjor", -"years ago" => "år siden" +"years ago" => "år siden", +"%s is available. Get <a href=\"%s\">more information</a>" => "%s er tilgjengelig. Få <a href=\"%s\">mer informasjon</a>", +"up to date" => "oppdatert", +"updates check is disabled" => "versjonssjekk er avslått" ); diff --git a/lib/l10n/nl.php b/lib/l10n/nl.php index a90fc6caa6c..583956c66e6 100644 --- a/lib/l10n/nl.php +++ b/lib/l10n/nl.php @@ -4,7 +4,7 @@ "Settings" => "Instellingen", "Users" => "Gebruikers", "Apps" => "Apps", -"Admin" => "Administrator", +"Admin" => "Beheerder", "ZIP download is turned off." => "ZIP download is uitgeschakeld.", "Files need to be downloaded one by one." => "Bestanden moeten één voor één worden gedownload.", "Back to Files" => "Terug naar bestanden", @@ -23,6 +23,6 @@ "last year" => "vorig jaar", "years ago" => "jaar geleden", "%s is available. Get <a href=\"%s\">more information</a>" => "%s is beschikbaar. Verkrijg <a href=\"%s\">meer informatie</a>", -"up to date" => "Bijgewerkt", +"up to date" => "bijgewerkt", "updates check is disabled" => "Meest recente versie controle is uitgeschakeld" ); diff --git a/lib/l10n/oc.php b/lib/l10n/oc.php new file mode 100644 index 00000000000..ffc0588becc --- /dev/null +++ b/lib/l10n/oc.php @@ -0,0 +1,24 @@ +<?php $TRANSLATIONS = array( +"Help" => "Ajuda", +"Personal" => "Personal", +"Settings" => "Configuracion", +"Users" => "Usancièrs", +"Apps" => "Apps", +"Admin" => "Admin", +"ZIP download is turned off." => "Avalcargar los ZIP es inactiu.", +"Files need to be downloaded one by one." => "Los fichièrs devan èsser avalcargats un per un.", +"Back to Files" => "Torna cap als fichièrs", +"Authentication error" => "Error d'autentificacion", +"seconds ago" => "segonda a", +"1 minute ago" => "1 minuta a", +"%d minutes ago" => "%d minutas a", +"today" => "uèi", +"yesterday" => "ièr", +"%d days ago" => "%d jorns a", +"last month" => "mes passat", +"months ago" => "meses a", +"last year" => "an passat", +"years ago" => "ans a", +"up to date" => "a jorn", +"updates check is disabled" => "la verificacion de mesa a jorn es inactiva" +); diff --git a/lib/l10n/pt_PT.php b/lib/l10n/pt_PT.php new file mode 100644 index 00000000000..c3cee207a16 --- /dev/null +++ b/lib/l10n/pt_PT.php @@ -0,0 +1,28 @@ +<?php $TRANSLATIONS = array( +"Help" => "Ajuda", +"Personal" => "Pessoal", +"Settings" => "Configurações", +"Users" => "Utilizadores", +"Apps" => "Aplicações", +"Admin" => "Admin", +"ZIP download is turned off." => "Descarregamento em ZIP está desligado.", +"Files need to be downloaded one by one." => "Os ficheiros precisam de ser descarregados um por um.", +"Back to Files" => "Voltar a Ficheiros", +"Selected files too large to generate zip file." => "Os ficheiros seleccionados são grandes demais para gerar um ficheiro zip.", +"Application is not enabled" => "A aplicação não está activada", +"Authentication error" => "Erro na autenticação", +"Token expired. Please reload page." => "O token expirou. Por favor recarregue a página.", +"seconds ago" => "há alguns segundos", +"1 minute ago" => "há 1 minuto", +"%d minutes ago" => "há %d minutos", +"today" => "hoje", +"yesterday" => "ontem", +"%d days ago" => "há %d dias", +"last month" => "mês passado", +"months ago" => "há meses", +"last year" => "ano passado", +"years ago" => "há anos", +"%s is available. Get <a href=\"%s\">more information</a>" => "%s está disponível. Obtenha <a href=\"%s\">mais informação</a>", +"up to date" => "actualizado", +"updates check is disabled" => "a verificação de actualizações está desligada" +); diff --git a/lib/l10n/ru_RU.php b/lib/l10n/ru_RU.php index 1e691993014..decf63efb97 100644 --- a/lib/l10n/ru_RU.php +++ b/lib/l10n/ru_RU.php @@ -5,6 +5,7 @@ "Users" => "Пользователи", "Apps" => "Приложения", "Admin" => "Админ", +"ZIP download is turned off." => "Загрузка ZIP выключена.", "Files need to be downloaded one by one." => "Файлы должны быть загружены один за другим.", "Back to Files" => "Обратно к файлам", "Selected files too large to generate zip file." => "Выбранные файлы слишком велики для генерации zip-архива.", diff --git a/lib/l10n/sk_SK.php b/lib/l10n/sk_SK.php index 33b329c30bb..8c77e82b7a6 100644 --- a/lib/l10n/sk_SK.php +++ b/lib/l10n/sk_SK.php @@ -11,6 +11,7 @@ "Selected files too large to generate zip file." => "Zvolené súbory sú príliž veľké na vygenerovanie zip súboru.", "Application is not enabled" => "Aplikácia nie je zapnutá", "Authentication error" => "Chyba autentifikácie", +"seconds ago" => "pred sekundami", "1 minute ago" => "pred 1 minútou", "%d minutes ago" => "pred %d minútami", "today" => "dnes", diff --git a/lib/log.php b/lib/log.php index 8bb2839be66..4bba62cf4b2 100644 --- a/lib/log.php +++ b/lib/log.php @@ -20,6 +20,7 @@ class OC_Log { const ERROR=3; const FATAL=4; + static public $enabled = true; static protected $class = null; /** @@ -29,11 +30,35 @@ class OC_Log { * @param int level */ public static function write($app, $message, $level) { - if (!self::$class) { - self::$class = 'OC_Log_'.ucfirst(OC_Config::getValue('log_type', 'owncloud')); - call_user_func(array(self::$class, 'init')); + if (self::$enabled) { + if (!self::$class) { + self::$class = 'OC_Log_'.ucfirst(OC_Config::getValue('log_type', 'owncloud')); + call_user_func(array(self::$class, 'init')); + } + $log_class=self::$class; + $log_class::write($app, $message, $level); } - $log_class=self::$class; - $log_class::write($app, $message, $level); + } + + //Fatal errors handler + public static function onShutdown(){ + $error = error_get_last(); + if($error) { + //ob_end_clean(); + self::write('PHP', $error['message'] . ' at ' . $error['file'] . '#' . $error['line'], self::FATAL); + } else { + return true; + } + } + + // Uncaught exception handler + public static function onException($exception){ + self::write('PHP', $exception->getMessage() . ' at ' . $exception->getFile() . '#' . $exception->getLine(), self::FATAL); + } + + //Recoverable errors handler + public static function onError($number, $message, $file, $line){ + self::write('PHP', $message . ' at ' . $file . '#' . $line, self::WARN); + } } diff --git a/lib/migration/content.php b/lib/migration/content.php index 89b1e782d86..87f8da68c9d 100644 --- a/lib/migration/content.php +++ b/lib/migration/content.php @@ -48,7 +48,7 @@ class OC_Migration_Content{ // @brief prepares the db // @param $query the sql query to prepare public function prepare( $query ) { - + // Only add database to tmpfiles if actually used if( !is_null( $this->db ) ) { // Get db path @@ -57,7 +57,7 @@ class OC_Migration_Content{ $this->tmpfiles[] = $db; } } - + // Optimize the query $query = $this->processQuery( $query ); diff --git a/lib/mimetypes.list.php b/lib/mimetypes.list.php index 8386bcb93f3..77b97917583 100644 --- a/lib/mimetypes.list.php +++ b/lib/mimetypes.list.php @@ -94,4 +94,5 @@ return array( 'sgf' => 'application/sgf', 'cdr' => 'application/coreldraw', 'impress' => 'text/impress', + 'ai' => 'application/illustrator', ); diff --git a/lib/ocsclient.php b/lib/ocsclient.php index 6428a883679..3c80f319662 100644 --- a/lib/ocsclient.php +++ b/lib/ocsclient.php @@ -49,6 +49,24 @@ class OC_OCSClient{ return($url); } + /** + * @brief Get the content of an OCS url call. + * @returns string of the response + * This function calls an OCS server and returns the response. It also sets a sane timeout + */ + private static function getOCSresponse($url) { + // set a sensible timeout of 10 sec to stay responsive even if the server is down. + $ctx = stream_context_create( + array( + 'http' => array( + 'timeout' => 10 + ) + ) + ); + $data=@file_get_contents($url, 0, $ctx); + return($data); + } + /** * @brief Get all the categories from the OCS server @@ -61,8 +79,7 @@ class OC_OCSClient{ return NULL; } $url=OC_OCSClient::getAppStoreURL().'/content/categories'; - - $xml=@file_get_contents($url); + $xml=OC_OCSClient::getOCSresponse($url); if($xml==FALSE) { return NULL; } @@ -103,7 +120,8 @@ class OC_OCSClient{ $filterurl='&filter='.urlencode($filter); $url=OC_OCSClient::getAppStoreURL().'/content/data?categories='.urlencode($categoriesstring).'&sortmode=new&page='.urlencode($page).'&pagesize=100'.$filterurl.$version; $apps=array(); - $xml=@file_get_contents($url); + $xml=OC_OCSClient::getOCSresponse($url); + if($xml==FALSE) { return NULL; } @@ -122,6 +140,7 @@ class OC_OCSClient{ $app['preview']=(string)$tmp[$i]->smallpreviewpic1; $app['changed']=strtotime($tmp[$i]->changed); $app['description']=(string)$tmp[$i]->description; + $app['score']=(string)$tmp[$i]->score; $apps[]=$app; } @@ -140,8 +159,8 @@ class OC_OCSClient{ return NULL; } $url=OC_OCSClient::getAppStoreURL().'/content/data/'.urlencode($id); + $xml=OC_OCSClient::getOCSresponse($url); - $xml=@file_get_contents($url); if($xml==FALSE) { OC_Log::write('core','Unable to parse OCS content',OC_Log::FATAL); return NULL; @@ -162,6 +181,7 @@ class OC_OCSClient{ $app['changed']=strtotime($tmp->changed); $app['description']=$tmp->description; $app['detailpage']=$tmp->detailpage; + $app['score']=$tmp->score; return $app; } @@ -177,8 +197,8 @@ class OC_OCSClient{ return NULL; } $url=OC_OCSClient::getAppStoreURL().'/content/download/'.urlencode($id).'/'.urlencode($item); + $xml=OC_OCSClient::getOCSresponse($url); - $xml=@file_get_contents($url); if($xml==FALSE) { OC_Log::write('core','Unable to parse OCS content',OC_Log::FATAL); return NULL; @@ -215,7 +235,8 @@ class OC_OCSClient{ $url=OC_OCSClient::getKBURL().'/knowledgebase/data?type=150&page='.$p.'&pagesize='.$s.$searchcmd; $kbe=array(); - $xml=@file_get_contents($url); + $xml=OC_OCSClient::getOCSresponse($url); + if($xml==FALSE) { OC_Log::write('core','Unable to parse knowledgebase content',OC_Log::FATAL); return NULL; diff --git a/lib/public/share.php b/lib/public/share.php index 1039d6f0dbf..d27802b52f7 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -173,6 +173,7 @@ class Share { */ public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions) { $uidOwner = \OC_User::getUser(); + $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global'); // Verify share type and sharing conditions are met if ($shareType === self::SHARE_TYPE_USER) { if ($shareWith == $uidOwner) { @@ -185,7 +186,7 @@ class Share { \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); throw new \Exception($message); } - if (\OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global') == 'groups_only') { + if ($sharingPolicy == 'groups_only') { $inGroup = array_intersect(\OC_Group::getUserGroups($uidOwner), \OC_Group::getUserGroups($shareWith)); if (empty($inGroup)) { $message = 'Sharing '.$itemSource.' failed, because the user '.$shareWith.' is not a member of any groups that '.$uidOwner.' is a member of'; @@ -208,7 +209,7 @@ class Share { \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); throw new \Exception($message); } - if (!\OC_Group::inGroup($uidOwner, $shareWith)) { + if ($sharingPolicy == 'groups_only' && !\OC_Group::inGroup($uidOwner, $shareWith)) { $message = 'Sharing '.$itemSource.' failed, because '.$uidOwner.' is not a member of the group '.$shareWith; \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); throw new \Exception($message); @@ -326,6 +327,22 @@ class Share { } /** + * @brief Unshare an item from all users, groups, and remove all links + * @param string Item type + * @param string Item source + * @return Returns true on success or false on failure + */ + public static function unshareAll($itemType, $itemSource) { + if ($shares = self::getItemShared($itemType, $itemSource)) { + foreach ($shares as $share) { + self::delete($share['id']); + } + return true; + } + return false; + } + + /** * @brief Unshare an item shared with the current user * @param string Item type * @param string Item target @@ -645,7 +662,7 @@ class Share { } else { if ($fileDependent) { if (($itemType == 'file' || $itemType == 'folder') && $format == \OC_Share_Backend_File::FORMAT_FILE_APP || $format == \OC_Share_Backend_File::FORMAT_FILE_APP_ROOT) { - $select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `share_type`, `share_with`, `file_source`, `path`, `file_target`, `permissions`, `expiration`, `name`, `ctime`, `mtime`, `mimetype`, `size`, `encrypted`, `versioned`, `writable`'; + $select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `uid_owner`, `share_type`, `share_with`, `file_source`, `path`, `file_target`, `permissions`, `expiration`, `name`, `ctime`, `mtime`, `mimetype`, `size`, `encrypted`, `versioned`, `writable`'; } else { $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`, `*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`, `file_source`, `path`, `file_target`, `permissions`, `stime`, `expiration`'; } @@ -975,8 +992,10 @@ class Share { } else { if ($itemType == 'file' || $itemType == 'folder') { $column = 'file_target'; + $columnSource = 'file_source'; } else { $column = 'item_target'; + $columnSource = 'item_source'; } if ($shareType == self::SHARE_TYPE_USER) { // Share with is a user, so set share type to user and groups @@ -1013,9 +1032,14 @@ class Share { continue; } } - // If matching target is from the same owner, use the same target. The share type will be different so this isn't the same share. if ($item['uid_owner'] == $uidOwner) { - return $target; + if ($itemType == 'file' || $itemType == 'folder') { + if ($item['file_source'] == \OC_FileCache::getId($itemSource)) { + return $target; + } + } else if ($item['item_source'] == $itemSource) { + return $target; + } } } if (!isset($exclude)) { @@ -1023,11 +1047,21 @@ class Share { } // Find similar targets to improve backend's chances to generate a unqiue target if ($userAndGroups) { - $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` = ? AND `share_type` IN (?,?,?) AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\') AND `'.$column.'` LIKE ?'); - $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique, '%'.$target.'%')); + if ($column == 'file_target') { + $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` IN (\'file\', \'folder\') AND `share_type` IN (?,?,?) AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')'); + $result = $checkTargets->execute(array(self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique)); + } else { + $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` = ? AND `share_type` IN (?,?,?) AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')'); + $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique)); + } } else { - $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` = ? AND `share_type` = ? AND `share_with` = ? AND `'.$column.'` LIKE ?'); - $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_GROUP, $shareWith, '%'.$target.'%')); + if ($column == 'file_target') { + $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` IN (\'file\', \'folder\') AND `share_type` = ? AND `share_with` = ?'); + $result = $checkTargets->execute(array(self::SHARE_TYPE_GROUP, $shareWith)); + } else { + $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` = ? AND `share_type` = ? AND `share_with` = ?'); + $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_GROUP, $shareWith)); + } } while ($row = $result->fetchRow()) { $exclude[] = $row[$column]; @@ -1055,7 +1089,7 @@ class Share { $parents = "'".implode("','", $parents)."'"; // Check the owner on the first search of reshares, useful for finding and deleting the reshares by a single user of a group share if (count($ids) == 1 && isset($uidOwner)) { - $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.') AND `uid_owner` = ?'); + $query = \OC_DB::prepare('SELECT `id`, `uid_owner`, `item_type`, `item_target`, `parent` FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.') AND `uid_owner` = ?'); $result = $query->execute(array($uidOwner)); } else { $query = \OC_DB::prepare('SELECT `id`, `item_type`, `item_target`, `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.')'); diff --git a/lib/public/util.php b/lib/public/util.php index 747448e62eb..38da7e82171 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -116,6 +116,7 @@ class Util { * @param $app app * @param $file file * @param $args array with param=>value, will be appended to the returned url + * The value of $args will be urlencoded * @returns the url * * Returns a absolute url to the given app and file. @@ -151,6 +152,7 @@ class Util { * @param $app app * @param $file file * @param $args array with param=>value, will be appended to the returned url + * The value of $args will be urlencoded * @returns the url * * Returns a url to the given app and file. diff --git a/lib/search/provider/file.php b/lib/search/provider/file.php index e4e976ed7fd..6cd6ef78f2f 100644 --- a/lib/search/provider/file.php +++ b/lib/search/provider/file.php @@ -10,6 +10,7 @@ class OC_Search_Provider_File extends OC_Search_Provider{ $name = basename($path); $text = ''; + $skip = false; if($mime=='httpd/unix-directory') { $link = OC_Helper::linkTo( 'files', 'index.php', array('dir' => $path)); $type = 'Files'; @@ -18,6 +19,7 @@ class OC_Search_Provider_File extends OC_Search_Provider{ $mimeBase = $fileData['mimepart']; switch($mimeBase) { case 'audio': + $skip = true; break; case 'text': $type = 'Text'; @@ -33,7 +35,9 @@ class OC_Search_Provider_File extends OC_Search_Provider{ } } } - $results[] = new OC_Search_Result($name, $text, $link, $type); + if(!$skip) { + $results[] = new OC_Search_Result($name, $text, $link, $type); + } } return $results; } diff --git a/lib/setup.php b/lib/setup.php index c21c8be3957..3c92e9c5599 100644 --- a/lib/setup.php +++ b/lib/setup.php @@ -5,12 +5,19 @@ $hasMySQL = is_callable('mysql_connect'); $hasPostgreSQL = is_callable('pg_connect'); $hasOracle = is_callable('oci_connect'); $datadir = OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data'); + +// Test if .htaccess is working +$content = "deny from all"; +file_put_contents(OC::$SERVERROOT.'/data/.htaccess', $content); + $opts = array( 'hasSQLite' => $hasSQLite, 'hasMySQL' => $hasMySQL, 'hasPostgreSQL' => $hasPostgreSQL, 'hasOracle' => $hasOracle, 'directory' => $datadir, + 'secureRNG' => OC_Util::secureRNG_available(), + 'htaccessWorking' => OC_Util::ishtaccessworking(), 'errors' => array(), ); @@ -79,7 +86,7 @@ class OC_Setup { } //generate a random salt that is used to salt the local user passwords - $salt=mt_rand(1000,9000).mt_rand(1000,9000).mt_rand(1000,9000).mt_rand(1000,9000).mt_rand(1000,9000).mt_rand(1000,9000).mt_rand(1000,9000).mt_rand(1000,9000); + $salt = OC_Util::generate_random_bytes(30); OC_Config::setValue('passwordsalt', $salt); //write the config file @@ -383,7 +390,7 @@ class OC_Setup { if (isset($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache')) { self::createHtaccess(); } - + //and we are done OC_Config::setValue('installed', true); } diff --git a/lib/subadmin.php b/lib/subadmin.php index 363e4a97cad..9e83e6da430 100644 --- a/lib/subadmin.php +++ b/lib/subadmin.php @@ -172,7 +172,7 @@ class OC_SubAdmin{ } /** - * @brief delete all SubAdmins8 by gid + * @brief delete all SubAdmins by gid * @param $parameters * @return boolean */ diff --git a/lib/template.php b/lib/template.php index 681b3f0b140..1c529932a30 100644 --- a/lib/template.php +++ b/lib/template.php @@ -155,15 +155,15 @@ class OC_Template{ $this->renderas = $renderas; $this->application = $app; $this->vars = array(); - if($renderas == 'user') { - $this->vars['requesttoken'] = OC_Util::callRegister(); - $this->vars['requestlifespan'] = OC_Util::$callLifespan; - } + $this->vars['requesttoken'] = OC_Util::callRegister(); + $this->vars['requestlifespan'] = OC_Util::$callLifespan; $parts = explode('/', $app); // fix translation when app is something like core/lostpassword $this->l10n = OC_L10N::get($parts[0]); - header('X-Frame-Options: Sameorigin'); - header('X-XSS-Protection: 1; mode=block'); - header('X-Content-Type-Options: nosniff'); + + // Some headers to enhance security + header('X-Frame-Options: Sameorigin'); + header('X-XSS-Protection: 1; mode=block'); + header('X-Content-Type-Options: nosniff'); $this->findTemplate($name); } diff --git a/lib/templatelayout.php b/lib/templatelayout.php index c898628bcdf..78893457f47 100644 --- a/lib/templatelayout.php +++ b/lib/templatelayout.php @@ -12,8 +12,7 @@ class OC_TemplateLayout extends OC_Template { if( $renderas == 'user' ) { parent::__construct( 'core', 'layout.user' ); - $this->assign('searchurl',OC_Helper::linkTo( 'search', 'index.php' ), false); - if(array_search(OC_APP::getCurrentApp(),array('settings','admin','help'))!==false) { + if(in_array(OC_APP::getCurrentApp(),array('settings','admin','help'))!==false) { $this->assign('bodyid','body-settings', false); }else{ $this->assign('bodyid','body-user', false); @@ -50,7 +49,7 @@ class OC_TemplateLayout extends OC_Template { $jsfiles = self::findJavascriptFiles(OC_Util::$scripts); $this->assign('jsfiles', array(), false); if (!empty(OC_Util::$core_scripts)) { - $this->append( 'jsfiles', OC_Helper::linkToRemote('core.js', false)); + $this->append( 'jsfiles', OC_Helper::linkToRemoteBase('core.js', false)); } foreach($jsfiles as $info) { $root = $info[0]; @@ -63,7 +62,7 @@ class OC_TemplateLayout extends OC_Template { $cssfiles = self::findStylesheetFiles(OC_Util::$styles); $this->assign('cssfiles', array()); if (!empty(OC_Util::$core_styles)) { - $this->append( 'cssfiles', OC_Helper::linkToRemote('core.css', false)); + $this->append( 'cssfiles', OC_Helper::linkToRemoteBase('core.css', false)); } foreach($cssfiles as $info) { $root = $info[0]; diff --git a/lib/updater.php b/lib/updater.php index ad42f2bf605..cb22da4f906 100644 --- a/lib/updater.php +++ b/lib/updater.php @@ -42,7 +42,16 @@ class OC_Updater{ //fetch xml data from updater $url=$updaterurl.'?version='.$versionstring; - $xml=@file_get_contents($url); + + // set a sensible timeout of 10 sec to stay responsive even if the update server is down. + $ctx = stream_context_create( + array( + 'http' => array( + 'timeout' => 10 + ) + ) + ); + $xml=@file_get_contents($url, 0, $ctx); if($xml==FALSE) { return array(); } diff --git a/lib/user.php b/lib/user.php index 7de2a4b7fe6..77bfe0de92a 100644 --- a/lib/user.php +++ b/lib/user.php @@ -210,6 +210,10 @@ class OC_User { } // Delete the user's keys in preferences OC_Preferences::deleteUser($uid); + + // Delete user files in /data/ + OC_Helper::rmdirr(OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ) . '/'.$uid.'/'); + // Emit and exit OC_Hook::emit( "OC_User", "post_deleteUser", array( "uid" => $uid )); return true; @@ -329,6 +333,8 @@ class OC_User { } } } + // invalidate all login cookies + OC_Preferences::deleteApp($uid, 'login_token'); OC_Hook::emit( "OC_User", "post_setPassword", array( "uid" => $uid, "password" => $password )); return $success; } @@ -472,9 +478,10 @@ class OC_User { */ public static function setMagicInCookie($username, $token) { $secure_cookie = OC_Config::getValue("forcessl", false); - setcookie("oc_username", $username, time()+60*60*24*15, '', '', $secure_cookie); - setcookie("oc_token", $token, time()+60*60*24*15, '', '', $secure_cookie); - setcookie("oc_remember_login", true, time()+60*60*24*15, '', '', $secure_cookie); + $expires = time() + OC_Config::getValue('remember_login_cookie_lifetime', 60*60*24*15); + setcookie("oc_username", $username, $expires, '', '', $secure_cookie); + setcookie("oc_token", $token, $expires, '', '', $secure_cookie, true); + setcookie("oc_remember_login", true, $expires, '', '', $secure_cookie); } /** diff --git a/lib/util.php b/lib/util.php index 777cb7a28fc..5771b89f265 100755 --- a/lib/util.php +++ b/lib/util.php @@ -1,9 +1,9 @@ <?php - /** * Class for utility functions * */ + class OC_Util { public static $scripts=array(); public static $styles=array(); @@ -49,7 +49,9 @@ class OC_Util { OC_Filesystem::mount('OC_Filestorage_Local', array('datadir' => $user_root), $user); OC_Filesystem::init($user_dir); $quotaProxy=new OC_FileProxy_Quota(); + $fileOperationProxy = new OC_FileProxy_FileOperations(); OC_FileProxy::register($quotaProxy); + OC_FileProxy::register($fileOperationProxy); // Load personal mount config if (is_file($user_root.'/mount.php')) { $mountConfig = include($user_root.'/mount.php'); @@ -62,7 +64,7 @@ class OC_Util { $mtime=filemtime($user_root.'/mount.php'); $previousMTime=OC_Preferences::getValue($user,'files','mountconfigmtime',0); if($mtime>$previousMTime) {//mount config has changed, filecache needs to be updated - OC_FileCache::clear($user); + OC_FileCache::triggerUpdate($user); OC_Preferences::setValue($user,'files','mountconfigmtime',$mtime); } } @@ -80,8 +82,8 @@ class OC_Util { * @return array */ public static function getVersion() { - // hint: We only can count up. So the internal version number of ownCloud 4.5 will be 4,9,0. This is not visible to the user - return array(4,85,11); + // hint: We only can count up. So the internal version number of ownCloud 4.5 will be 4.90.0. This is not visible to the user + return array(4,91,00); } /** @@ -89,7 +91,7 @@ class OC_Util { * @return string */ public static function getVersionString() { - return '4.5 RC 1'; + return '5.0 pre alpha'; } /** @@ -287,6 +289,11 @@ class OC_Util { $errors[]=array('error'=>'PHP module zlib is not installed.<br/>','hint'=>'Please ask your server administrator to install the module.'); $web_server_restart= false; } + + if(!function_exists('simplexml_load_string')) { + $errors[]=array('error'=>'PHP module SimpleXML is not installed.<br/>','hint'=>'Please ask your server administrator to install the module.'); + $web_server_restart= false; + } if(floatval(phpversion())<5.3) { $errors[]=array('error'=>'PHP 5.3 is required.<br/>','hint'=>'Please ask your server administrator to update PHP to version 5.3 or higher. PHP 5.2 is no longer supported by ownCloud and the PHP community.'); $web_server_restart= false; @@ -303,9 +310,11 @@ class OC_Util { return $errors; } - public static function displayLoginPage($display_lostpassword) { + public static function displayLoginPage($errors = array()) { $parameters = array(); - $parameters['display_lostpassword'] = $display_lostpassword; + foreach( $errors as $key => $value ) { + $parameters[$value] = true; + } if (!empty($_POST['user'])) { $parameters["username"] = OC_Util::sanitizeHTML($_POST['user']).'"'; @@ -314,9 +323,6 @@ class OC_Util { $parameters["username"] = ''; $parameters['user_autofocus'] = true; } - $sectoken=rand(1000000,9999999); - $_SESSION['sectoken']=$sectoken; - $parameters["sectoken"] = $sectoken; if (isset($_REQUEST['redirect_url'])) { $redirect_url = OC_Util::sanitizeHTML($_REQUEST['redirect_url']); } else { @@ -344,7 +350,7 @@ class OC_Util { public static function checkLoggedIn() { // Check if we are a user if( !OC_User::isLoggedIn()) { - header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php', array('redirect_url' => urlencode($_SERVER["REQUEST_URI"])))); + header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php', array('redirect_url' => $_SERVER["REQUEST_URI"]))); exit(); } } @@ -355,6 +361,7 @@ class OC_Util { public static function checkAdminUser() { // Check if we are a user self::checkLoggedIn(); + self::verifyUser(); if( !OC_Group::inGroup( OC_User::getUser(), 'admin' )) { header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php' )); exit(); @@ -368,6 +375,7 @@ class OC_Util { public static function checkSubAdminUser() { // Check if we are a user self::checkLoggedIn(); + self::verifyUser(); if(OC_Group::inGroup(OC_User::getUser(),'admin')) { return true; } @@ -379,6 +387,40 @@ class OC_Util { } /** + * Check if the user verified the login with his password in the last 15 minutes + * If not, the user will be shown a password verification page + */ + public static function verifyUser() { + if(OC_Config::getValue('enhancedauth', true) === true) { + // Check password to set session + if(isset($_POST['password'])) { + if (OC_User::login(OC_User::getUser(), $_POST["password"] ) === true) { + $_SESSION['verifiedLogin']=time() + OC_Config::getValue('enhancedauthtime', 15 * 60); + } + } + + // Check if the user verified his password + if(!isset($_SESSION['verifiedLogin']) OR $_SESSION['verifiedLogin'] < time()) { + OC_Template::printGuestPage("", "verify", array('username' => OC_User::getUser())); + exit(); + } + } + } + + /** + * Check if the user verified the login with his password + * @return bool + */ + public static function isUserVerified() { + if(OC_Config::getValue('enhancedauth', true) === true) { + if(!isset($_SESSION['verifiedLogin']) OR $_SESSION['verifiedLogin'] < time()) { + return false; + } + return true; + } + } + + /** * Redirect to the user default page */ public static function redirectToDefaultPage() { @@ -422,7 +464,7 @@ class OC_Util { * @description * Also required for the client side to compute the piont in time when to * request a fresh token. The client will do so when nearly 97% of the - * timespan coded here has expired. + * timespan coded here has expired. */ public static $callLifespan = 3600; // 3600 secs = 1 hour @@ -440,7 +482,7 @@ class OC_Util { */ public static function callRegister() { // generate a random token. - $token=mt_rand(1000,9000).mt_rand(1000,9000).mt_rand(1000,9000); + $token = self::generate_random_bytes(20); // store the token together with a timestamp in the session. $_SESSION['requesttoken-'.$token]=time(); @@ -551,4 +593,62 @@ class OC_Util { } } + /** + * @brief Generates a cryptographical secure pseudorandom string + * @param Int with the length of the random string + * @return String + * Please also update secureRNG_available if you change something here + */ + public static function generate_random_bytes($length = 30) { + + // Try to use openssl_random_pseudo_bytes + if(function_exists('openssl_random_pseudo_bytes')) { + $pseudo_byte = bin2hex(openssl_random_pseudo_bytes($length, $strong)); + if($strong == TRUE) { + return substr($pseudo_byte, 0, $length); // Truncate it to match the length + } + } + + // Try to use /dev/urandom + $fp = @file_get_contents('/dev/urandom', false, null, 0, $length); + if ($fp !== FALSE) { + $string = substr(bin2hex($fp), 0, $length); + return $string; + } + + // Fallback to mt_rand() + $characters = '0123456789'; + $characters .= 'abcdefghijklmnopqrstuvwxyz'; + $charactersLength = strlen($characters)-1; + $pseudo_byte = ""; + + // Select some random characters + for ($i = 0; $i < $length; $i++) { + $pseudo_byte .= $characters[mt_rand(0, $charactersLength)]; + } + return $pseudo_byte; + } + + /** + * @brief Checks if a secure random number generator is available + * @return bool + */ + public static function secureRNG_available() { + + // Check openssl_random_pseudo_bytes + if(function_exists('openssl_random_pseudo_bytes')) { + openssl_random_pseudo_bytes(1, $strong); + if($strong == TRUE) { + return true; + } + } + + // Check /dev/urandom + $fp = @file_get_contents('/dev/urandom', false, null, 0, 1); + if ($fp !== FALSE) { + return true; + } + + return false; + } } |