Merge branch 'master' into routing

This commit is contained in:
Bart Visscher 2012-09-28 21:41:21 +02:00
commit c9317b5a68
14 changed files with 160 additions and 34 deletions

View File

@ -17,6 +17,7 @@ ownCloud is written by:
Sam Tuke
Simon Birnbach
Lukas Reschke
Christian Reiner
With help from many libraries and frameworks including:

View File

@ -157,7 +157,7 @@ $(document).ready(function(){
var downloadScope = 'file';
}
FileActions.register(downloadScope,'Download', OC.PERMISSION_READ, function(){return OC.imagePath('core','actions/download');},function(filename){
window.location=OC.filePath('files', 'ajax', 'download.php') + encodeURIComponent('?files='+encodeURIComponent(filename)+'&dir='+encodeURIComponent($('#dir').val()));
window.location=OC.filePath('files', 'ajax', 'download.php') + '&files='+encodeURIComponent(filename)+'&dir='+encodeURIComponent($('#dir').val());
});
});

View File

@ -0,0 +1,41 @@
<?php
/**
* ownCloud
* @author Christian Reiner
* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info>
*
* 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/>.
*
*/
/**
* @file core/ajax/requesttoken.php
* @brief Ajax method to retrieve a fresh request protection token for ajax calls
* @return json: success/error state indicator including a fresh request token
* @author Christian Reiner
*/
require_once '../../lib/base.php';
// don't load apps or filesystem for this task
$RUNTIME_NOAPPS = TRUE;
$RUNTIME_NOSETUPFS = TRUE;
// Sanity checks
// using OCP\JSON::callCheck() below protects the token refreshing itself.
//OCP\JSON::callCheck ( );
OCP\JSON::checkLoggedIn ( );
// hand out a fresh token
OCP\JSON::success ( array ( 'token' => OCP\Util::callRegister() ) );
?>

View File

@ -40,7 +40,7 @@ OC.EventSource=function(src,data){
dataStr+=name+'='+encodeURIComponent(data[name])+'&';
}
}
dataStr+='requesttoken='+OC.EventSource.requesttoken;
dataStr+='requesttoken='+OC.Request.Token;
if(!this.useFallBack && typeof EventSource !='undefined'){
this.source=new EventSource(src+'?'+dataStr);
this.source.onmessage=function(e){

55
core/js/requesttoken.js Normal file
View File

@ -0,0 +1,55 @@
/**
* ownCloud
*
* @file core/js/requesttoken.js
* @brief Routine to refresh the Request protection request token periodically
* @author Christian Reiner (arkascha)
* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info>
*
* 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/>.
*
*/
OC.Request = {
// the request token
Token: {},
// the lifespan span (in secs)
Lifespan: {},
// method to refresh the local request token periodically
Refresh: function(){
// just a client side console log to preserve efficiency
console.log("refreshing request token (lifebeat)");
var dfd=new $.Deferred();
$.ajax({
type: 'POST',
url: OC.filePath('core','ajax','requesttoken.php'),
cache: false,
data: { },
dataType: 'json'
}).done(function(response){
// store refreshed token inside this class
OC.Request.Token=response.token;
dfd.resolve();
}).fail(dfd.reject);
return dfd;
}
}
// accept requesttoken and lifespan into the OC namespace
OC.Request.Token = oc_requesttoken;
OC.Request.Lifespan = oc_requestlifespan;
// refresh the request token periodically shortly before it becomes invalid on the server side
setInterval(OC.Request.Refresh,Math.floor(1000*OC.Request.Lifespan*0.93)), // 93% of lifespan value, close to when the token expires
// early bind token as additional ajax argument for every single request
$(document).bind('ajaxSend', function(elm, xhr, s){xhr.setRequestHeader('requesttoken', OC.Request.Token);});

View File

@ -11,6 +11,8 @@
var oc_webroot = '<?php echo OC::$WEBROOT; ?>';
var oc_appswebroots = <?php echo $_['apps_paths'] ?>;
var oc_current_user = '<?php echo OC_User::getUser() ?>';
var oc_requesttoken = '<?php echo $_['requesttoken']; ?>';
var oc_requestlifespan = '<?php echo $_['requestlifespan']; ?>';
</script>
<?php foreach($_['jsfiles'] as $jsfile): ?>
<script type="text/javascript" src="<?php echo $jsfile; ?>"></script>
@ -24,13 +26,6 @@
echo '/>';
?>
<?php endforeach; ?>
<script type="text/javascript">
requesttoken = '<?php echo $_['requesttoken']; ?>';
OC.EventSource.requesttoken=requesttoken;
$(document).bind('ajaxSend', function(elm, xhr, s) {
xhr.setRequestHeader('requesttoken', requesttoken);
});
</script>
</head>
<body id="<?php echo $_['bodyid'];?>">

View File

@ -247,6 +247,8 @@ class OC{
OC_Util::addScript( "jquery-tipsy" );
OC_Util::addScript( "oc-dialogs" );
OC_Util::addScript( "js" );
// request protection token MUST be defined after the jquery library but before any $('document').ready()
OC_Util::addScript( "requesttoken" );
OC_Util::addScript( "eventsource" );
OC_Util::addScript( "config" );
//OC_Util::addScript( "multiselect" );

View File

@ -23,8 +23,7 @@
abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IProperties {
const GETETAG_PROPERTYNAME = '{DAV:}getetag';
const LASTMODIFIED_PROPERTYNAME_DEPRECIATED = '{DAV:}lastmodified'; // FIXME: keept for the transition period, can be removed for OC 4.5.1 if the sync client update too
const GETLASTMODIFIED_PROPERTYNAME = '{DAV:}getlastmodified';
const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified';
/**
* The path to the current node
@ -151,9 +150,8 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
$query->execute( array( OC_User::getUser(), $this->path, $propertyName ));
}
}
else { //FIXME: first part of if statement can be removed together with the LASTMODIFIED_PROPERTYNAME_DEPRECIATED const for oc4.5.1 if the sync client was updated too
if( strcmp( $propertyName, self::LASTMODIFIED_PROPERTYNAME_DEPRECIATED) === 0 ||
strcmp( $propertyName, self::GETLASTMODIFIED_PROPERTYNAME) === 0 ) {
else {
if( strcmp( $propertyName, self::LASTMODIFIED_PROPERTYNAME) === 0 ) {
$this->touch($propertyValue);
} else {
if(!array_key_exists( $propertyName, $existing )) {

View File

@ -521,12 +521,19 @@ class OC_Filesystem{
return self::$defaultInstance->hasUpdated($path,$time);
}
static public function removeETagHook($params) {
static public function removeETagHook($params, $root = false) {
if (isset($params['path'])) {
$path=$params['path'];
} else {
$path=$params['oldpath'];
}
if ($root) { // reduce path to the required part of it (no 'username/files')
$fakeRootView = new OC_FilesystemView($root);
$count = 1;
$path=str_replace(OC_App::getStorage("files")->getAbsolutePath(), "", $fakeRootView->getAbsolutePath($path), $count);
}
$path = self::normalizePath($path);
OC_Connector_Sabre_Node::removeETagPropertyForPath($path);
}

View File

@ -451,8 +451,9 @@ class OC_FilesystemView {
OC_Filesystem::signal_post_write,
array( OC_Filesystem::signal_param_path => $path2)
);
} else { // no real copy, file comes from somewhere else, e.g. version rollback -> just update the file cache without all the other post_write actions
} else { // no real copy, file comes from somewhere else, e.g. version rollback -> just update the file cache and the webdav properties without all the other post_write actions
OC_FileCache_Update::update($path2, $this->fakeRoot);
OC_Filesystem::removeETagHook(array("path" => $path2), $this->fakeRoot);
}
return $result;
}

View File

@ -5,29 +5,36 @@ class OC_Search_Provider_File extends OC_Search_Provider{
$files=OC_FileCache::search($query,true);
$results=array();
foreach($files as $fileData) {
$file=$fileData['path'];
$mime=$fileData['mimetype'];
$path = $fileData['path'];
$mime = $fileData['mimetype'];
$name = basename($path);
$text = '';
$path = urlencode($path);
if($mime=='httpd/unix-directory') {
$results[]=new OC_Search_Result(basename($file),'',OC_Helper::linkTo( 'files', 'index.php', array('dir' => $file)),'Files');
$link = OC_Helper::linkTo( 'files', 'index.php', array('dir' => $path));
$type = 'Files';
}else{
$mimeBase=$fileData['mimepart'];
$link = OC_Helper::linkTo( 'files', 'download.php', array('file' => $path));
$mimeBase = $fileData['mimepart'];
switch($mimeBase) {
case 'audio':
break;
case 'text':
$results[]=new OC_Search_Result(basename($file),'',OC_Helper::linkTo( 'files', 'download.php', array('file' => $file) ),'Text');
$type = 'Text';
break;
case 'image':
$results[]=new OC_Search_Result(basename($file),'',OC_Helper::linkTo( 'files', 'download.php', array('file' => $file) ),'Images');
$type = 'Images';
break;
default:
if($mime=='application/xml') {
$results[]=new OC_Search_Result(basename($file),'',OC_Helper::linkTo( 'files', 'download.php', array('file' => $file) ),'Text');
$type = 'Text';
}else{
$results[]=new OC_Search_Result(basename($file),'',OC_Helper::linkTo( 'files', 'download.php', array('file' => $file) ),'Files');
$type = 'Files';
}
}
}
$results[] = new OC_Search_Result($name, $text, $link, $type);
}
return $results;
}

View File

@ -157,6 +157,7 @@ class OC_Template{
$this->vars = array();
if($renderas == 'user') {
$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]);
@ -374,6 +375,7 @@ class OC_Template{
$page = new OC_TemplateLayout($this->renderas);
if($this->renderas == 'user') {
$page->assign('requesttoken', $this->vars['requesttoken']);
$page->assign('requestlifespan', $this->vars['requestlifespan']);
}
// Add custom headers

View File

@ -416,14 +416,29 @@ class OC_Util {
}
/**
* @brief Register an get/post call. This is important to prevent CSRF attacks
* Todo: Write howto
* @brief Static lifespan (in seconds) when a request token expires.
* @see OC_Util::callRegister()
* @see OC_Util::isCallRegistered()
* @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.
*/
public static $callLifespan = 3600; // 3600 secs = 1 hour
/**
* @brief Register an get/post call. Important to prevent CSRF attacks.
* @todo Write howto: CSRF protection guide
* @return $token Generated token.
* @description
* Creates a 'request token' (random) and stores it inside the session.
* Ever subsequent (ajax) request must use such a valid token to succeed,
* otherwise the request will be denied as a protection against CSRF.
* The tokens expire after a fixed lifespan.
* @see OC_Util::$callLifespan
* @see OC_Util::isCallRegistered()
*/
public static function callRegister() {
//mamimum time before token exires
$maxtime=(60*60); // 1 hour
// generate a random token.
$token=mt_rand(1000,9000).mt_rand(1000,9000).mt_rand(1000,9000);
@ -436,7 +451,8 @@ class OC_Util {
foreach($_SESSION as $key=>$value) {
// search all tokens in the session
if(substr($key,0,12)=='requesttoken') {
if($value+$maxtime<time()) {
// check if static lifespan has expired
if($value+self::$callLifespan<time()) {
// remove outdated tokens
unset($_SESSION[$key]);
}
@ -447,14 +463,13 @@ class OC_Util {
return($token);
}
/**
* @brief Check an ajax get/post call if the request token is valid.
* @return boolean False if request token is not set or is invalid.
* @see OC_Util::$callLifespan
* @see OC_Util::calLRegister()
*/
public static function isCallRegistered() {
//mamimum time before token exires
$maxtime=(60*60); // 1 hour
if(isset($_GET['requesttoken'])) {
$token=$_GET['requesttoken'];
}elseif(isset($_POST['requesttoken'])) {
@ -467,7 +482,8 @@ class OC_Util {
}
if(isset($_SESSION['requesttoken-'.$token])) {
$timestamp=$_SESSION['requesttoken-'.$token];
if($timestamp+$maxtime<time()) {
// check if static lifespan has expired
if($timestamp+self::$callLifespan<time()) {
return false;
}else{
//token valid

View File

@ -25,6 +25,7 @@ OC.search.showResults=function(results){
parent.load(OC.filePath('search','templates','part.results.php'),function(){
OC.search.showResults.loaded=true;
$('#searchresults').click(function(event){
OC.search.hide();
event.stopPropagation();
});
$(window).click(function(event){