Handles file permissions. Protect against overwriting changes.

remotes/origin/stable
Tom Needham 13 years ago
parent 65c37abef9
commit f7f19af816
  1. 28
      apps/files_texteditor/ajax/loadfile.php
  2. 49
      apps/files_texteditor/ajax/mtime.php
  3. 67
      apps/files_texteditor/ajax/savefile.php
  4. 145
      apps/files_texteditor/js/editor.js

@ -28,13 +28,23 @@ require_once('../../../lib/base.php');
OC_JSON::checkLoggedIn(); OC_JSON::checkLoggedIn();
// Set the session key for the file we are about to edit. // Set the session key for the file we are about to edit.
$path = isset($_GET['path']) ? $_GET['path'] : false; $dir = isset($_GET['dir']) ? $_GET['dir'] : '';
$filename = isset($_GET['file']) ? $_GET['file'] : '';
if($path){ if(!empty($filename))
$sessionname = md5('oc_file_hash_'.$path); {
$filecontents = OC_Filesystem::file_get_contents($path); $path = $dir.'/'.$filename;
OC_Filesystem::update_session_file_hash($sessionname,sha1(htmlspecialchars($filecontents))); if(OC_Filesystem::is_writeable($path))
OC_JSON::success(); {
$mtime = OC_Filesystem::filemtime($path);
$filecontents = OC_Filesystem::file_get_contents($path);
OC_JSON::success(array('data' => array('filecontents' => $filecontents, 'write' => 'true', 'mtime' => $mtime)));
}
else
{
$mtime = OC_Filesystem::filemtime($path);
$filecontents = OC_Filesystem::file_get_contents($path);
OC_JSON::success(array('data' => array('filecontents' => $filecontents, 'write' => 'false', 'mtime' => $mtime)));
}
} else { } else {
OC_JSON::error(); OC_JSON::error(array('data' => array( 'message' => 'Invalid file path supplied.')));
} }

@ -0,0 +1,49 @@
<?php
/**
* ownCloud - files_texteditor
*
* @author Tom Needham
* @copyright 2011 Tom Needham contact@tomneedham.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/>.
*
*/
// Init owncloud
require_once('../../../lib/base.php');
// Check if we are a user
OC_JSON::checkLoggedIn();
// Get the path from GET
$path = isset($_GEt['path']) ? $_GET['path'] : '';
if($path != '')
{
// Find the mtime
$mtime = OC_Filesystem::filemtime($path);
if($mtime)
{
OC_JSON::success(array('data' => array('path' => $path, 'mtime' => $mtime)));
}
else
{
OC_JSON::error();
}
}
else
{
OC_JSON::error();
}

@ -27,47 +27,36 @@ require_once('../../../lib/base.php');
// Check if we are a user // Check if we are a user
OC_JSON::checkLoggedIn(); OC_JSON::checkLoggedIn();
// Save the file data // Get paramteres
$filecontents = htmlspecialchars_decode($_POST['filecontents']); $filecontents = htmlspecialchars_decode($_POST['filecontents']);
$file = $_POST['file']; $path = isset($_POST['path']) ? $_POST['path'] : '';
$dir = $_POST['dir']; $mtime = isset($_POST['mtime']) ? $_POST['mtime'] : '';
$path = $dir.'/'.$file;
$force = isset($_POST['force']) ? $_POST['force'] : false;
$sessionname = sha1('oc_file_hash_'.$path);
function do_save($path,$filecontents){
$sessionname = md5('oc_file_hash_'.$path);
OC_Filesystem::update_session_file_hash($sessionname,sha1(htmlspecialchars($filecontents)));
OC_Filesystem::file_put_contents($path, $filecontents);
}
// Check if file modified whilst editing? if($path != '' && $mtime != '')
if(isset($_SESSION[$sessionname])){ {
if(!empty($_SESSION[$sessionname])){ // Get file mtime
// Compare to current hash of file. $filemtime = OC_Filesystem::filemtime($path);
$savedfilecontents = htmlspecialchars(OC_Filesystem::file_get_contents($path)); if($mtime != $filemtime)
$hash = md5($savedfilecontents); {
$originalhash = $_SESSION[$sessionname]; // Then the file has changed since opening
// Compare with hash taken when file was opened OC_JSON::error();
if($hash != $originalhash){ }
// Someone has played with the file while you were editing else
// Force save? {
if($force){ // File same as when opened
do_save($path, $filecontents); // Save file
OC_JSON::success(); if(OC_Filesystem::is_writeable($path))
} else { {
// No force OC_Filesystem::file_put_contents($path, $filecontents);
OC_JSON::error(array('data' => array( 'message' => $l10n->t('The file has been edited since you opened it. Overwrite the file?')))); OC_JSON::success();
} }
} else { else
// No body has edited it whilst you were, so save the file {
// Update the session hash. // Not writeable!
do_save($path,$filecontents); OC_JSON::error(array('data' => array( 'message' => 'Insufficient permissions')));
OC_JSON::success(); }
}
} }
} else { } else {
// No session value set for soem reason, just save the file. OC_JSON::error(array('data' => array( 'message' => 'File path or mtime not supplied')));
do_save($path,$filecontents); }
OC_JSON::success();
}

@ -77,81 +77,42 @@ function editorIsShown(){
return is_editor_shown; return is_editor_shown;
} }
function updateSessionFileHash(path){
$.get(OC.filePath('files_texteditor','ajax','loadfile.php'),
{ path: path },
function(jsondata){
if(jsondata.status=='failure'){
alert('Failed to update session file hash.');
}
}, "json");}
function doFileSave(){ function doFileSave(){
if(editorIsShown()){ if(editorIsShown()){
// Get file path
var path = $('#editor').attr('data-dir')+'/'+$('#editor').attr('data-filename');
// Get original mtime
var mtime = $('#editor').attr('data-mtime');
// Show saving spinner
$("#editor_save").die('click',doFileSave); $("#editor_save").die('click',doFileSave);
$('#editor_save').after('<img id="saving_icon" src="'+OC.filePath('core','img','loading.gif')+'"></img>'); $('#editor_save').after('<img id="saving_icon" src="'+OC.filePath('core','img','loading.gif')+'"></img>');
var filecontents = window.aceEditor.getSession().getValue(); // Get the data
var dir = $('#editor').attr('data-dir'); var filecontents = window.aceEditor.getSession().getValue();
var file = $('#editor').attr('data-filename'); // Send the data
$.post(OC.filePath('files_texteditor','ajax','savefile.php'), { filecontents: filecontents, file: file, dir: dir },function(jsondata){ $.post(OC.filePath('files_texteditor','ajax','savefile.php'), { filecontents: filecontents, path: path, mtime: mtime },function(jsondata){
if(jsondata.status!='success'){
if(jsondata.status == 'failure'){ // Save failed
var answer = confirm(jsondata.data.message); $('#saving_icon').remove();
if(answer){ $('#editor_save').after('<p id="save_result" style="float: left">Failed to save file</p>');
$.post(OC.filePath('files_texteditor','ajax','savefile.php'),{ filecontents: filecontents, file: file, dir: dir, force: 'true' },function(jsondata){ setTimeout(function() {
if(jsondata.status =='success'){ $('#save_result').fadeOut('slow',function(){
$('#saving_icon').remove(); $(this).remove();
$('#editor_save').after('<p id="save_result" style="float: left">Saved!</p>') $("#editor_save").live('click',doFileSave);
setTimeout(function() { });
$('#save_result').fadeOut('slow',function(){ }, 2000);
$(this).remove(); } else {
$("#editor_save").live('click',doFileSave); // Save OK
}); $('#saving_icon').remove();
}, 2000); $('#editor_save').after('<p id="save_result" style="float: left">Saved</p>')
} setTimeout(function() {
else { $('#save_result').fadeOut('slow',function(){
// Save error $(this).remove();
$('#saving_icon').remove(); $("#editor_save").live('click',doFileSave);
$('#editor_save').after('<p id="save_result" style="float: left">Failed!</p>'); });
setTimeout(function() { }, 2000);
$('#save_result').fadeOut('slow',function(){ }
$(this).remove(); },'json');
$("#editor_save").live('click',doFileSave); }
});
}, 2000);
}
}, 'json');
}
else {
// Don't save!
$('#saving_icon').remove();
// Temporary measure until we get a tick icon
$('#editor_save').after('<p id="save_result" style="float: left">Saved!</p>');
setTimeout(function() {
$('#save_result').fadeOut('slow',function(){
$(this).remove();
$("#editor_save").live('click',doFileSave);
});
}, 2000);
}
}
else if(jsondata.status == 'success'){
// Success
$('#saving_icon').remove();
// Temporary measure until we get a tick icon
$('#editor_save').after('<p id="save_result" style="float: left">Saved!</p>');
setTimeout(function() {
$('#save_result').fadeOut('slow',function(){
$(this).remove();
$("#editor_save").live('click',doFileSave);
});
}, 2000);
}
}, 'json');
giveEditorFocus();
} else {
return;
}
}; };
function giveEditorFocus(){ function giveEditorFocus(){
@ -162,24 +123,34 @@ function showFileEditor(dir,filename){
if(!editorIsShown()){ if(!editorIsShown()){
// Loads the file editor and display it. // Loads the file editor and display it.
var data = $.ajax({ var data = $.ajax({
url: OC.filePath('files','ajax','download.php')+'?files='+encodeURIComponent(filename)+'&dir='+encodeURIComponent(dir), url: OC.filePath('files_texteditor','ajax','loadfile.php'),
data: 'file='+encodeURIComponent(filename)+'&dir='+encodeURIComponent(dir),
complete: function(data){ complete: function(data){
// Initialise the editor result = jQuery.parseJSON(data.responseText);
updateSessionFileHash(dir+'/'+filename); if(result.status == 'success'){
showControls(filename); // Save mtime
$('table').fadeOut('slow', function() { $('#editor').attr('data-mtime', result.data.mtime);
$('#editor').text(data.responseText); // Initialise the editor
// encodeURIComponenet? showControls(filename);
$('#editor').attr('data-dir', dir); $('table').fadeOut('slow', function() {
$('#editor').attr('data-filename', filename); $('#editor').text(result.data.filecontents);
window.aceEditor = ace.edit("editor"); $('#editor').attr('data-dir', dir);
aceEditor.setShowPrintMargin(false); $('#editor').attr('data-filename', filename);
setEditorSize(); window.aceEditor = ace.edit("editor");
setSyntaxMode(getFileExtension(filename)); aceEditor.setShowPrintMargin(false);
OC.addScript('files_texteditor','aceeditor/theme-clouds', function(){ if(result.data.write=='false'){
window.aceEditor.setTheme("ace/theme/clouds"); aceEditor.setReadOnly(true);
}
setEditorSize();
setSyntaxMode(getFileExtension(filename));
OC.addScript('files_texteditor','aceeditor/theme-clouds', function(){
window.aceEditor.setTheme("ace/theme/clouds");
});
}); });
}); } else {
// Failed to get the file.
alert(result.data.message);
}
// End success // End success
} }
// End ajax // End ajax

Loading…
Cancel
Save