liteFM fixes
This commit is contained in:
parent
b9727fdfa7
commit
751874ea8c
5 changed files with 280 additions and 84 deletions
|
|
@ -234,7 +234,7 @@ function downloadFile(home_id, file_id, file_size, file_name)
|
||||||
function getFilePart()
|
function getFilePart()
|
||||||
{
|
{
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
xhr.open('POST', "home.php?m=litefm&home_id="+home_id+"&item="+file_id+"&name="+file_name+"&p=get&type=cleared&size="+file_size+"&did="+did, true);
|
xhr.open('POST', "home.php?m=litefm&home_id="+home_id+"&item="+file_id+"&name="+encodeURIComponent(file_name)+"&p=get&type=cleared&size="+file_size+"&did="+did, true);
|
||||||
xhr.responseType = 'arraybuffer';
|
xhr.responseType = 'arraybuffer';
|
||||||
xhr.onload = function(e) {
|
xhr.onload = function(e) {
|
||||||
if(this.response.byteLength != 0)
|
if(this.response.byteLength != 0)
|
||||||
|
|
@ -283,6 +283,15 @@ function downloadFile(home_id, file_id, file_size, file_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
|
function escapeHtml(value) {
|
||||||
|
return String(value)
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''');
|
||||||
|
}
|
||||||
|
|
||||||
/* translation & info */
|
/* translation & info */
|
||||||
var select_at_least_one_item = $('#dialog').attr('data-select_at_least_one_item'),
|
var select_at_least_one_item = $('#dialog').attr('data-select_at_least_one_item'),
|
||||||
ask_delete = $('#dialog').attr('data-ask_delete'),
|
ask_delete = $('#dialog').attr('data-ask_delete'),
|
||||||
|
|
@ -389,7 +398,7 @@ $(document).ready(function(){
|
||||||
item = $(this).attr('data-item');
|
item = $(this).attr('data-item');
|
||||||
value = $(this).attr('value');
|
value = $(this).attr('value');
|
||||||
addpost.items.push(item);
|
addpost.items.push(item);
|
||||||
items += "<br>"+value;
|
items += "<br>"+escapeHtml(value);
|
||||||
});
|
});
|
||||||
if(items != '')
|
if(items != '')
|
||||||
{
|
{
|
||||||
|
|
@ -434,9 +443,9 @@ $(document).ready(function(){
|
||||||
var items = '';
|
var items = '';
|
||||||
$('input[class="item"]:checked').each(function(){
|
$('input[class="item"]:checked').each(function(){
|
||||||
item = $(this).attr('data-item');
|
item = $(this).attr('data-item');
|
||||||
value = $(this).attr('value').replace('"', """);
|
value = $(this).attr('value');
|
||||||
addpost.items.push(item);
|
addpost.items.push(item);
|
||||||
items += "<br><input class='rename' type=text style='width:100%;' name='"+item+"' value=\""+value+"\">";
|
items += "<br><input class='rename' type=text style='width:100%;' name='"+item+"' value=\""+escapeHtml(value)+"\">";
|
||||||
});
|
});
|
||||||
if(items != '')
|
if(items != '')
|
||||||
{
|
{
|
||||||
|
|
@ -487,7 +496,7 @@ $(document).ready(function(){
|
||||||
item = $(this).attr('data-item');
|
item = $(this).attr('data-item');
|
||||||
value = $(this).attr('value');
|
value = $(this).attr('value');
|
||||||
addpost.items.push(item);
|
addpost.items.push(item);
|
||||||
items += "<br>"+value;
|
items += "<br>"+escapeHtml(value);
|
||||||
});
|
});
|
||||||
if(items != '')
|
if(items != '')
|
||||||
{
|
{
|
||||||
|
|
@ -550,7 +559,7 @@ $(document).ready(function(){
|
||||||
item = $(this).attr('data-item');
|
item = $(this).attr('data-item');
|
||||||
value = $(this).attr('value');
|
value = $(this).attr('value');
|
||||||
addpost.items.push(item);
|
addpost.items.push(item);
|
||||||
items += "<br>"+value;
|
items += "<br>"+escapeHtml(value);
|
||||||
});
|
});
|
||||||
if(items != '')
|
if(items != '')
|
||||||
{
|
{
|
||||||
|
|
@ -611,7 +620,7 @@ $(document).ready(function(){
|
||||||
item = $(this).attr('data-item');
|
item = $(this).attr('data-item');
|
||||||
value = $(this).attr('value');
|
value = $(this).attr('value');
|
||||||
addpost.items.push(item);
|
addpost.items.push(item);
|
||||||
items += "<br>"+value;
|
items += "<br>"+escapeHtml(value);
|
||||||
});
|
});
|
||||||
if(items != '')
|
if(items != '')
|
||||||
{
|
{
|
||||||
|
|
@ -675,7 +684,7 @@ $(document).ready(function(){
|
||||||
if(ext.match(/^(tar|tgz|gz|Z|zip|bz2|tbz|lzma|xz|txz)$/i) != null)
|
if(ext.match(/^(tar|tgz|gz|Z|zip|bz2|tbz|lzma|xz|txz)$/i) != null)
|
||||||
{
|
{
|
||||||
addpost.items.push(item);
|
addpost.items.push(item);
|
||||||
items += "<br>"+value;
|
items += "<br>"+escapeHtml(value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if(items != '')
|
if(items != '')
|
||||||
|
|
@ -902,7 +911,7 @@ $(document).ready(function(){
|
||||||
}
|
}
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
url: 'home.php?m=litefm&home_id='+home_id+'&type=cleared&pid='+file['pid']+'&size='+file['size']+'&filename='+file['filename']+"&data_type=json",
|
url: 'home.php?m=litefm&home_id='+home_id+'&type=cleared&pid='+file['pid']+'&size='+file['size']+'&filename='+encodeURIComponent(file['filename'])+"&data_type=json",
|
||||||
dataType:'json',
|
dataType:'json',
|
||||||
async: false,
|
async: false,
|
||||||
success: function(data){
|
success: function(data){
|
||||||
|
|
@ -978,7 +987,7 @@ $(document).ready(function(){
|
||||||
addpost.set_attr = $(this).attr('data-set_attr'),
|
addpost.set_attr = $(this).attr('data-set_attr'),
|
||||||
addpost.file_name = $(this).attr('data-file_name');
|
addpost.file_name = $(this).attr('data-file_name');
|
||||||
addpost.item = $(this).attr('data-item');
|
addpost.item = $(this).attr('data-item');
|
||||||
$('#dialog').html(ask_change_attr.replace("%file_name%",addpost.file_name));
|
$('#dialog').html(ask_change_attr.replace("%file_name%",escapeHtml(addpost.file_name)));
|
||||||
$('#dialog').dialog({
|
$('#dialog').dialog({
|
||||||
autoOpen: true,
|
autoOpen: true,
|
||||||
width: 450,
|
width: 450,
|
||||||
|
|
@ -1016,7 +1025,7 @@ $(document).ready(function(){
|
||||||
item = $(this).attr('data-item');
|
item = $(this).attr('data-item');
|
||||||
value = $(this).attr('value');
|
value = $(this).attr('value');
|
||||||
addpost.items.push(item);
|
addpost.items.push(item);
|
||||||
items += "<br>"+value;
|
items += "<br>"+escapeHtml(value);
|
||||||
});
|
});
|
||||||
if(items != '')
|
if(items != '')
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,9 @@ if(preg_match("/t/",$server_home['access_rights']) > 0)
|
||||||
{
|
{
|
||||||
$module_buttons = array();
|
$module_buttons = array();
|
||||||
|
|
||||||
|
// WE DONT WANT A FTP BUTTON, BUT WE DO NEED THE FTP FUNCTIONALITY, SO WE WILL NOT ADD A FTP BUTTON TO THE GAME MONITOR, BUT WE WILL STILL ALLOW THE USER TO ACCESS THE FTP MODULE FOR THIS HOME
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
$module_buttons = array(
|
$module_buttons = array(
|
||||||
"<a class='monitorbutton' href='?m=ftp&home_id=".$server_home['home_id']."'>
|
"<a class='monitorbutton' href='?m=ftp&home_id=".$server_home['home_id']."'>
|
||||||
|
|
|
||||||
|
|
@ -68,31 +68,30 @@ function exec_ogp_module()
|
||||||
if (!isset($_SESSION[$cwd_session_key]) || !is_string($_SESSION[$cwd_session_key])) {
|
if (!isset($_SESSION[$cwd_session_key]) || !is_string($_SESSION[$cwd_session_key])) {
|
||||||
$_SESSION[$cwd_session_key] = '';
|
$_SESSION[$cwd_session_key] = '';
|
||||||
}
|
}
|
||||||
$path = clean_path($home_cfg['home_path']."/".$_SESSION[$cwd_session_key]);
|
$path = litefm_safe_join_home_path($home_cfg['home_path'], $_SESSION[$cwd_session_key]);
|
||||||
|
if ($path === false)
|
||||||
|
{
|
||||||
|
print_failure(get_lang("unallowed_char"));
|
||||||
|
echo "<table class='center'><tr><td><a href='?m=gamemanager&p=game_monitor&home_id=".$home_cfg['home_id']."'><< ".get_lang('back')."</a></td></tr></table>";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$home_root = clean_path($home_cfg['home_path']);
|
||||||
|
if (!$remote->rfile_exists($home_root))
|
||||||
|
{
|
||||||
|
print_failure("Server files have not been installed yet.");
|
||||||
|
echo "<table class='center'><tr><td><a href='?m=gamemanager&p=game_monitor&home_id=".$home_cfg['home_id']."'><< ".get_lang('back')."</a></td></tr></table>";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$remote->rfile_exists($path))
|
if (!$remote->rfile_exists($path))
|
||||||
{
|
{
|
||||||
while(!$remote->rfile_exists($path))
|
$requested_rel_path = isset($_SESSION[$cwd_session_key]) ? trim((string)$_SESSION[$cwd_session_key], '/') : '';
|
||||||
{
|
$requested_rel_path = $requested_rel_path === '' ? '/' : $requested_rel_path;
|
||||||
$current_cwd = isset($_SESSION[$cwd_session_key]) ? (string)$_SESSION[$cwd_session_key] : '';
|
print_failure("Directory not found: " . litefm_escape_html($requested_rel_path));
|
||||||
if ($current_cwd === '' || $current_cwd === '.' || $current_cwd === DIRECTORY_SEPARATOR) {
|
|
||||||
print_failure("Server files have not been installed yet.");
|
|
||||||
echo "<table class='center'><tr><td><a href='?m=gamemanager&p=game_monitor&home_id=".$home_cfg['home_id']."'><< ".get_lang('back')."</a></td></tr></table>";
|
echo "<table class='center'><tr><td><a href='?m=gamemanager&p=game_monitor&home_id=".$home_cfg['home_id']."'><< ".get_lang('back')."</a></td></tr></table>";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$parent_cwd = dirname($current_cwd);
|
|
||||||
if (!is_string($parent_cwd) || $parent_cwd === '.' || $parent_cwd === DIRECTORY_SEPARATOR) {
|
|
||||||
$parent_cwd = '';
|
|
||||||
}
|
|
||||||
$_SESSION[$cwd_session_key] = $parent_cwd;
|
|
||||||
$path = clean_path($home_cfg['home_path']."/".$_SESSION[$cwd_session_key]);
|
|
||||||
if($path == clean_path($home_cfg['home_path']."/"))
|
|
||||||
{
|
|
||||||
print_failure("Server files have not been installed yet.");
|
|
||||||
echo "<table class='center'><tr><td><a href='?m=gamemanager&p=game_monitor&home_id=".$home_cfg['home_id']."'><< ".get_lang('back')."</a></td></tr></table>";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get File Operations Keys
|
// Get File Operations Keys
|
||||||
$fo_keys = get_file_operations_keys();
|
$fo_keys = get_file_operations_keys();
|
||||||
|
|
@ -112,7 +111,12 @@ function exec_ogp_module()
|
||||||
{
|
{
|
||||||
$bytes = $_GET['size'];
|
$bytes = $_GET['size'];
|
||||||
$totalsize = $bytes / 1024;
|
$totalsize = $bytes / 1024;
|
||||||
$filename = $_GET['filename'];
|
$filename = litefm_decode_name_param($_GET['filename']);
|
||||||
|
if (!litefm_is_valid_path_component($filename))
|
||||||
|
{
|
||||||
|
echo json_encode(array('pct' => 0, 'complete' => false));
|
||||||
|
return;
|
||||||
|
}
|
||||||
$kbytes = $remote->rsync_progress( clean_path( $path."/".$filename ) );
|
$kbytes = $remote->rsync_progress( clean_path( $path."/".$filename ) );
|
||||||
list($totalsize,$mbytes,$pct) = explode(";",do_progress($kbytes,$totalsize));
|
list($totalsize,$mbytes,$pct) = explode(";",do_progress($kbytes,$totalsize));
|
||||||
$totalmbytes = round($totalsize / 1024, 2);
|
$totalmbytes = round($totalsize / 1024, 2);
|
||||||
|
|
@ -177,10 +181,9 @@ function exec_ogp_module()
|
||||||
// if file not uploaded then skip it
|
// if file not uploaded then skip it
|
||||||
if ( !is_uploaded_file($_FILES['files']['tmp_name'][$i]) )
|
if ( !is_uploaded_file($_FILES['files']['tmp_name'][$i]) )
|
||||||
continue;
|
continue;
|
||||||
// now we can move uploaded files
|
$filename = basename((string)$_FILES['files']['name'][$i]);
|
||||||
$bad_chars = preg_replace( "/([[:alnum:]_\.-]*)/", "", $_FILES['files']['name'][$i] );
|
if (!litefm_is_valid_path_component($filename))
|
||||||
$bad_arr = str_split( $bad_chars );
|
continue;
|
||||||
$filename = str_replace( $bad_arr, "", $_FILES['files']['name'][$i] );
|
|
||||||
$dest_file_path = clean_path( $upload_folder_path . "/" . $filename . ".txt" );
|
$dest_file_path = clean_path( $upload_folder_path . "/" . $filename . ".txt" );
|
||||||
$file_url = str_replace( "home.php", $dest_file_path, $url );
|
$file_url = str_replace( "home.php", $dest_file_path, $url );
|
||||||
if( file_exists( $dest_file_path ) )
|
if( file_exists( $dest_file_path ) )
|
||||||
|
|
@ -205,7 +208,17 @@ function exec_ogp_module()
|
||||||
elseif( isset( $_POST['create_folder'] ) and $fo['create_folder'] == "1" )
|
elseif( isset( $_POST['create_folder'] ) and $fo['create_folder'] == "1" )
|
||||||
{
|
{
|
||||||
$folder_name = stripslashes($_POST['folder_name']);
|
$folder_name = stripslashes($_POST['folder_name']);
|
||||||
|
if (!litefm_is_valid_path_component($folder_name))
|
||||||
|
{
|
||||||
|
print_failure(get_lang("unallowed_char"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
$folder_path = clean_path( $path . "/" . $folder_name );
|
$folder_path = clean_path( $path . "/" . $folder_name );
|
||||||
|
if (!litefm_path_within_home($home_cfg['home_path'], $folder_path))
|
||||||
|
{
|
||||||
|
print_failure(get_lang("unallowed_char"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
$remote->shell_action('create_dir', $folder_path);
|
$remote->shell_action('create_dir', $folder_path);
|
||||||
$db->logger( get_lang("create_folder") . ": " . $folder_path );
|
$db->logger( get_lang("create_folder") . ": " . $folder_path );
|
||||||
}
|
}
|
||||||
|
|
@ -242,8 +255,18 @@ function exec_ogp_module()
|
||||||
if(isset($_SESSION['fm_files_'.$home_id][$item]))
|
if(isset($_SESSION['fm_files_'.$home_id][$item]))
|
||||||
{
|
{
|
||||||
$item_path = clean_path( $path . "/" . $_SESSION['fm_files_'.$home_id][$item] );
|
$item_path = clean_path( $path . "/" . $_SESSION['fm_files_'.$home_id][$item] );
|
||||||
$new_item = removeInvalidFileNameCharacters(stripslashes($_POST['values'][$i]));
|
$new_item = stripslashes($_POST['values'][$i]);
|
||||||
|
if (!litefm_is_valid_path_component($new_item))
|
||||||
|
{
|
||||||
|
print_failure(get_lang("unallowed_char"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$new_item_path = clean_path( $path . "/" . $new_item );
|
$new_item_path = clean_path( $path . "/" . $new_item );
|
||||||
|
if (!litefm_path_within_home($home_cfg['home_path'], $new_item_path))
|
||||||
|
{
|
||||||
|
print_failure(get_lang("unallowed_char"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if ($item_path != $new_item_path)
|
if ($item_path != $new_item_path)
|
||||||
{
|
{
|
||||||
$remote->shell_action('rename', "$item_path;$new_item_path");
|
$remote->shell_action('rename', "$item_path;$new_item_path");
|
||||||
|
|
@ -256,8 +279,18 @@ function exec_ogp_module()
|
||||||
// Move Files/Folders
|
// Move Files/Folders
|
||||||
elseif( isset( $_POST['move'] ) and $fo['move'] == "1" )
|
elseif( isset( $_POST['move'] ) and $fo['move'] == "1" )
|
||||||
{
|
{
|
||||||
$selected_path = preg_replace("#[/\.\./]+#","/", stripslashes($_POST['selected_path']));
|
$selected_path = litefm_normalize_relative_path(stripslashes($_POST['selected_path']));
|
||||||
$destination = clean_path($home_cfg['home_path']. "/" . $selected_path);
|
if ($selected_path === false)
|
||||||
|
{
|
||||||
|
print_failure(get_lang("unallowed_char"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$destination = litefm_safe_join_home_path($home_cfg['home_path'], $selected_path);
|
||||||
|
if ($destination === false)
|
||||||
|
{
|
||||||
|
print_failure(get_lang("unallowed_char"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if($path != $destination)
|
if($path != $destination)
|
||||||
{
|
{
|
||||||
if($remote->rfile_exists($destination))
|
if($remote->rfile_exists($destination))
|
||||||
|
|
@ -278,8 +311,18 @@ function exec_ogp_module()
|
||||||
// Copy Files/Folders
|
// Copy Files/Folders
|
||||||
elseif( isset( $_POST['copy'] ) and $fo['copy'] == "1" )
|
elseif( isset( $_POST['copy'] ) and $fo['copy'] == "1" )
|
||||||
{
|
{
|
||||||
$selected_path = preg_replace("#[/\.\./]+#","/", stripslashes($_POST['selected_path']));
|
$selected_path = litefm_normalize_relative_path(stripslashes($_POST['selected_path']));
|
||||||
$destination = clean_path($home_cfg['home_path']. "/" . $selected_path);
|
if ($selected_path === false)
|
||||||
|
{
|
||||||
|
print_failure(get_lang("unallowed_char"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$destination = litefm_safe_join_home_path($home_cfg['home_path'], $selected_path);
|
||||||
|
if ($destination === false)
|
||||||
|
{
|
||||||
|
print_failure(get_lang("unallowed_char"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if($path != $destination)
|
if($path != $destination)
|
||||||
{
|
{
|
||||||
if($remote->rfile_exists($destination))
|
if($remote->rfile_exists($destination))
|
||||||
|
|
@ -320,8 +363,18 @@ function exec_ogp_module()
|
||||||
// uncompress
|
// uncompress
|
||||||
elseif( isset( $_POST['uncompress'] ) and $fo['uncompress'] == "1" )
|
elseif( isset( $_POST['uncompress'] ) and $fo['uncompress'] == "1" )
|
||||||
{
|
{
|
||||||
$selected_path = preg_replace("#[/\.\./]+#","/", stripslashes($_POST['selected_path']));
|
$selected_path = litefm_normalize_relative_path(stripslashes($_POST['selected_path']));
|
||||||
$destination = clean_path($home_cfg['home_path']. "/" . $selected_path);
|
if ($selected_path === false)
|
||||||
|
{
|
||||||
|
print_failure(get_lang("unallowed_char"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$destination = litefm_safe_join_home_path($home_cfg['home_path'], $selected_path);
|
||||||
|
if ($destination === false)
|
||||||
|
{
|
||||||
|
print_failure(get_lang("unallowed_char"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if($remote->rfile_exists($destination))
|
if($remote->rfile_exists($destination))
|
||||||
{
|
{
|
||||||
foreach ((array)$_POST['items'] as $item)
|
foreach ((array)$_POST['items'] as $item)
|
||||||
|
|
@ -338,8 +391,20 @@ function exec_ogp_module()
|
||||||
// Create file
|
// Create file
|
||||||
elseif( isset( $_POST['create_file'] ) and $fo['create_file'] == "1" )
|
elseif( isset( $_POST['create_file'] ) and $fo['create_file'] == "1" )
|
||||||
{
|
{
|
||||||
$file_name = removeInvalidFileNameCharacters(stripslashes($_POST['file_name']));
|
$file_name = stripslashes($_POST['file_name']);
|
||||||
|
if (!litefm_is_valid_path_component($file_name))
|
||||||
|
{
|
||||||
|
print_failure(get_lang("unallowed_char"));
|
||||||
|
$file_name = "";
|
||||||
|
}
|
||||||
|
if ($file_name === "")
|
||||||
|
return;
|
||||||
$destination = clean_path( $path . "/" . $file_name);
|
$destination = clean_path( $path . "/" . $file_name);
|
||||||
|
if (!litefm_path_within_home($home_cfg['home_path'], $destination))
|
||||||
|
{
|
||||||
|
print_failure(get_lang("unallowed_char"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
$remote->shell_action('touch', $destination);
|
$remote->shell_action('touch', $destination);
|
||||||
$db->logger( get_lang("create_file") . ": $destination" );
|
$db->logger( get_lang("create_file") . ": $destination" );
|
||||||
}
|
}
|
||||||
|
|
@ -437,7 +502,12 @@ function exec_ogp_module()
|
||||||
|
|
||||||
if (!is_array($dirlist))
|
if (!is_array($dirlist))
|
||||||
{
|
{
|
||||||
if(isset($_SESSION['fm_cwd_'.$home_id]))
|
if ($remote->rfile_exists($path))
|
||||||
|
{
|
||||||
|
print_failure("Directory exists but cannot be opened. Check permissions.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
elseif(isset($_SESSION['fm_cwd_'.$home_id]))
|
||||||
{
|
{
|
||||||
unset($_SESSION['fm_cwd_'.$home_id]);
|
unset($_SESSION['fm_cwd_'.$home_id]);
|
||||||
$view->refresh("?m=litefm&home_id=$home_id",0);
|
$view->refresh("?m=litefm&home_id=$home_id",0);
|
||||||
|
|
@ -475,21 +545,25 @@ function exec_ogp_module()
|
||||||
$dirlist['directorys'] = array_orderby($dirlist['directorys'], 'filename', SORT_ASC);
|
$dirlist['directorys'] = array_orderby($dirlist['directorys'], 'filename', SORT_ASC);
|
||||||
foreach ((array)$dirlist['directorys'] as $directory)
|
foreach ((array)$dirlist['directorys'] as $directory)
|
||||||
{
|
{
|
||||||
$directory['filename'] = removeInvalidFileNameCharacters($directory['filename']);
|
$directoryName = $directory['filename'];
|
||||||
|
if (!litefm_is_valid_path_component($directoryName))
|
||||||
|
continue;
|
||||||
|
$encodedDirectoryName = rawurlencode($directoryName);
|
||||||
|
$escapedDirectoryName = litefm_escape_html($directoryName);
|
||||||
|
|
||||||
echo "<tr>\n".
|
echo "<tr>\n".
|
||||||
"<td>".
|
"<td>".
|
||||||
"<input type=checkbox name='folder' data-item='$i' value=\"" . str_replace('"', """, $directory['filename']) . "\" class='item' />\n".
|
"<input type=checkbox name='folder' data-item='$i' value=\"" . $escapedDirectoryName . "\" class='item' />\n".
|
||||||
"</td>".
|
"</td>".
|
||||||
"<td align=left>".
|
"<td align=left>".
|
||||||
"<img class=\"viewitem\" src=\"" . check_theme_image("images/folder.png") . "\" alt=\"Directory\" /> ".
|
"<img class=\"viewitem\" src=\"" . check_theme_image("images/folder.png") . "\" alt=\"Directory\" /> ".
|
||||||
"<a href=\"?m=litefm&home_id=$home_id&item=$i&name=" . urlencode($directory['filename']) . "&type=directory\">".
|
"<a href=\"?m=litefm&home_id=$home_id&item=$i&name=" . $encodedDirectoryName . "&type=directory\">".
|
||||||
$directory['filename'] . "</a></td>";
|
$escapedDirectoryName . "</a></td>";
|
||||||
if( $os == "linux" )
|
if( $os == "linux" )
|
||||||
echo "<td>-</td>";
|
echo "<td>-</td>";
|
||||||
echo "<td>-</td> <td>" . $directory['user'] . " " . $directory['group']. "</td>\n".
|
echo "<td>-</td> <td>" . $directory['user'] . " " . $directory['group']. "</td>\n".
|
||||||
"</tr>\n";
|
"</tr>\n";
|
||||||
$_SESSION['fm_files_'.$home_id][$i] = $directory['filename'];
|
$_SESSION['fm_files_'.$home_id][$i] = $directoryName;
|
||||||
$i++;
|
$i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -499,12 +573,16 @@ function exec_ogp_module()
|
||||||
$dirlist['files'] = array_orderby($dirlist['files'], 'filename', SORT_ASC);
|
$dirlist['files'] = array_orderby($dirlist['files'], 'filename', SORT_ASC);
|
||||||
foreach ((array)$dirlist['files'] as $file)
|
foreach ((array)$dirlist['files'] as $file)
|
||||||
{
|
{
|
||||||
$file['filename'] = removeInvalidFileNameCharacters($file['filename']);
|
$fileName = $file['filename'];
|
||||||
|
if (!litefm_is_valid_path_component($fileName))
|
||||||
|
continue;
|
||||||
|
$encodedFileName = rawurlencode($fileName);
|
||||||
|
$escapedFileName = litefm_escape_html($fileName);
|
||||||
|
|
||||||
if( $os == "linux" )
|
if( $os == "linux" )
|
||||||
{
|
{
|
||||||
if($isAdmin){
|
if($isAdmin){
|
||||||
$secureFile = "<td><div data-item='$i' data-file_name=\"" . str_replace('"', """, $file['filename']) . "\" class='chattrButton ";
|
$secureFile = "<td><div data-item='$i' data-file_name=\"" . litefm_escape_html($file['filename']) . "\" class='chattrButton ";
|
||||||
if( preg_match( "/i/", $file['attr'] ) ){
|
if( preg_match( "/i/", $file['attr'] ) ){
|
||||||
$secureFile .= "locked' data-set_attr='-i' ><i></i><span>". get_lang("chattr_no");
|
$secureFile .= "locked' data-set_attr='-i' ><i></i><span>". get_lang("chattr_no");
|
||||||
}else{
|
}else{
|
||||||
|
|
@ -526,15 +604,15 @@ function exec_ogp_module()
|
||||||
|
|
||||||
echo "<tr>\n".
|
echo "<tr>\n".
|
||||||
"<td>".
|
"<td>".
|
||||||
"<input type=checkbox name='file' data-item='$i' value=\"" . str_replace('"', """, $file['filename']) . "\" class='item' />\n".
|
"<input type=checkbox name='file' data-item='$i' value=\"" . $escapedFileName . "\" class='item' />\n".
|
||||||
"</td>".
|
"</td>".
|
||||||
"<td align=left id='fileid$i' >";
|
"<td align=left id='fileid$i' >";
|
||||||
echo "<img class=\"viewitem\" src=\"" . check_theme_image("images/txt.png") . "\" alt=\"Text file\" /> ".
|
echo "<img class=\"viewitem\" src=\"" . check_theme_image("images/txt.png") . "\" alt=\"Text file\" /> ".
|
||||||
"<a href=\"?m=litefm&home_id=$home_id&item=$i&p=read_file&name=" . urlencode($file['filename']) . "&type=file\">". get_lang("button_edit") ."</a>".
|
"<a href=\"?m=litefm&home_id=$home_id&item=$i&p=read_file&name=" . $encodedFileName . "&type=file\">". get_lang("button_edit") ."</a>".
|
||||||
"<a href=\"javascript:downloadFile($home_id, $i, {$file['size']}, '".str_replace("'", "\'", $file['filename'])."');\" id=\"jsDwl$i\" >" .$file['filename'] . "</a> ".
|
"<a href=\"javascript:downloadFile($home_id, $i, {$file['size']}, '".str_replace("'", "\\'", $fileName)."');\" id=\"jsDwl$i\" >" .$escapedFileName . "</a> ".
|
||||||
"</td>$secureFile<td>" . $file['size'] . "</td> <td>" . $file['user'] . " " . $file['group']. "</td>\n";
|
"</td>$secureFile<td>" . $file['size'] . "</td> <td>" . $file['user'] . " " . $file['group']. "</td>\n";
|
||||||
echo "</tr>\n";
|
echo "</tr>\n";
|
||||||
$_SESSION['fm_files_'.$home_id][$i] = $file['filename'];
|
$_SESSION['fm_files_'.$home_id][$i] = $fileName;
|
||||||
$i++;
|
$i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -544,12 +622,15 @@ function exec_ogp_module()
|
||||||
$dirlist['binarys'] = array_orderby($dirlist['binarys'], 'filename', SORT_ASC);
|
$dirlist['binarys'] = array_orderby($dirlist['binarys'], 'filename', SORT_ASC);
|
||||||
foreach ((array)$dirlist['binarys'] as $binary)
|
foreach ((array)$dirlist['binarys'] as $binary)
|
||||||
{
|
{
|
||||||
$binary['filename'] = removeInvalidFileNameCharacters($binary['filename']);
|
$binaryName = $binary['filename'];
|
||||||
|
if (!litefm_is_valid_path_component($binaryName))
|
||||||
|
continue;
|
||||||
|
$escapedBinaryName = litefm_escape_html($binaryName);
|
||||||
|
|
||||||
if( $os == "linux" )
|
if( $os == "linux" )
|
||||||
{
|
{
|
||||||
if($isAdmin){
|
if($isAdmin){
|
||||||
$secureFile = "<td><div data-item='$i' data-file_name=\"" . str_replace('"', """, $binary['filename']) . "\" class='chattrButton ";
|
$secureFile = "<td><div data-item='$i' data-file_name=\"" . litefm_escape_html($binary['filename']) . "\" class='chattrButton ";
|
||||||
if( preg_match( "/i/", $binary['attr'] ) ){
|
if( preg_match( "/i/", $binary['attr'] ) ){
|
||||||
$secureFile .= "locked' data-set_attr='-i' ><i></i><span>". get_lang("chattr_no");
|
$secureFile .= "locked' data-set_attr='-i' ><i></i><span>". get_lang("chattr_no");
|
||||||
}else{
|
}else{
|
||||||
|
|
@ -571,14 +652,14 @@ function exec_ogp_module()
|
||||||
|
|
||||||
echo "<tr>\n".
|
echo "<tr>\n".
|
||||||
"<td>".
|
"<td>".
|
||||||
"<input type=checkbox name='binary' data-item='$i' value=\"" . str_replace('"', """, $binary['filename']) . "\" class='item' />\n".
|
"<input type=checkbox name='binary' data-item='$i' value=\"" . $escapedBinaryName . "\" class='item' />\n".
|
||||||
"</td>".
|
"</td>".
|
||||||
"<td align=left id='fileid$i' >";
|
"<td align=left id='fileid$i' >";
|
||||||
echo "<img class=\"viewitem\" src=\"" . check_theme_image("images/exec.png") . "\" alt=\"Binary file\" /> ".
|
echo "<img class=\"viewitem\" src=\"" . check_theme_image("images/exec.png") . "\" alt=\"Binary file\" /> ".
|
||||||
"<a href=\"javascript:downloadFile($home_id, $i, {$binary['size']}, '".str_replace("'", "\'", $binary['filename'])."');\" id=\"jsDwl$i\" >" .$binary['filename'] . "</a> ".
|
"<a href=\"javascript:downloadFile($home_id, $i, {$binary['size']}, '".str_replace("'", "\\'", $binaryName)."');\" id=\"jsDwl$i\" >" .$escapedBinaryName . "</a> ".
|
||||||
"</td>$secureFile<td>" . $binary['size'] . "</td><td>" . $binary['user'] . " " . $binary['group']. "</td>\n";
|
"</td>$secureFile<td>" . $binary['size'] . "</td><td>" . $binary['user'] . " " . $binary['group']. "</td>\n";
|
||||||
echo "</tr>\n";
|
echo "</tr>\n";
|
||||||
$_SESSION['fm_files_'.$home_id][$i] = $binary['filename'];
|
$_SESSION['fm_files_'.$home_id][$i] = $binaryName;
|
||||||
$i++;
|
$i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -589,7 +670,7 @@ function exec_ogp_module()
|
||||||
// Dialog translation && info
|
// Dialog translation && info
|
||||||
$user = $db->getUserById($_SESSION['user_id']);
|
$user = $db->getUserById($_SESSION['user_id']);
|
||||||
echo "<div id='dialog' ".
|
echo "<div id='dialog' ".
|
||||||
"data-folder=\"" . clean_path("/".str_replace('"', """, @$_SESSION['fm_cwd_'.$home_id])) . "\" " .
|
"data-folder=\"" . litefm_escape_html(clean_path("/".(@$_SESSION['fm_cwd_'.$home_id] ?? ''))) . "\" " .
|
||||||
"data-select_at_least_one_item='" . get_lang("select_at_least_one_item") . "' " .
|
"data-select_at_least_one_item='" . get_lang("select_at_least_one_item") . "' " .
|
||||||
"data-ask_delete='" . get_lang("delete_item") . "' " .
|
"data-ask_delete='" . get_lang("delete_item") . "' " .
|
||||||
"data-ask_rename='" . get_lang("rename_item") . "' " .
|
"data-ask_rename='" . get_lang("rename_item") . "' " .
|
||||||
|
|
@ -615,7 +696,7 @@ function exec_ogp_module()
|
||||||
"data-dest_email='" . get_lang("dest_email") . "' " .
|
"data-dest_email='" . get_lang("dest_email") . "' " .
|
||||||
"data-user_email='" . $user['users_email'] . "' ";
|
"data-user_email='" . $user['users_email'] . "' ";
|
||||||
if($isAdmin)
|
if($isAdmin)
|
||||||
echo "data-ask_change_attr=\"" . get_lang_f( 'secure_item', clean_path( str_replace('"', """, $path) . "/%file_name%" ) ) . "\" ";
|
echo "data-ask_change_attr=\"" . litefm_escape_html(get_lang_f( 'secure_item', clean_path( $path . "/%file_name%" ) )) . "\" ";
|
||||||
echo "></div>";
|
echo "></div>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,74 @@
|
||||||
|
|
||||||
require_once('includes/lib_remote.php');
|
require_once('includes/lib_remote.php');
|
||||||
|
|
||||||
|
function litefm_decode_name_param($value)
|
||||||
|
{
|
||||||
|
return rawurldecode((string)$value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function litefm_escape_html($value)
|
||||||
|
{
|
||||||
|
return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
function litefm_is_valid_path_component($name)
|
||||||
|
{
|
||||||
|
if (!is_string($name) || $name === '' || $name === '.' || $name === '..') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (strpos($name, "\0") !== false || strpos($name, '/') !== false || strpos($name, '\\') !== false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function litefm_normalize_relative_path($relativePath)
|
||||||
|
{
|
||||||
|
$relativePath = str_replace('\\', '/', (string)$relativePath);
|
||||||
|
$relativePath = preg_replace('#/+#', '/', $relativePath);
|
||||||
|
$relativePath = trim($relativePath, '/');
|
||||||
|
if ($relativePath === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (strpos($relativePath, "\0") !== false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (preg_match('#(^|/)\.{1,2}(/|$)#', $relativePath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach (explode('/', $relativePath) as $segment) {
|
||||||
|
if (!litefm_is_valid_path_component($segment)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $relativePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
function litefm_path_within_home($homePath, $candidatePath)
|
||||||
|
{
|
||||||
|
$homeNorm = str_replace('\\', '/', clean_path((string)$homePath));
|
||||||
|
$candidateNorm = str_replace('\\', '/', clean_path((string)$candidatePath));
|
||||||
|
$homeCmp = strtolower(rtrim($homeNorm, '/'));
|
||||||
|
$candidateCmp = strtolower($candidateNorm);
|
||||||
|
if ($candidateCmp === $homeCmp) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return strpos($candidateCmp, $homeCmp . '/') === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function litefm_safe_join_home_path($homePath, $relativePath)
|
||||||
|
{
|
||||||
|
$normalizedRel = litefm_normalize_relative_path($relativePath);
|
||||||
|
if ($normalizedRel === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$fullPath = clean_path(rtrim((string)$homePath, '/') . '/' . $normalizedRel);
|
||||||
|
if (!litefm_path_within_home($homePath, $fullPath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $fullPath;
|
||||||
|
}
|
||||||
|
|
||||||
function do_progress($kbytes,$totalsize)
|
function do_progress($kbytes,$totalsize)
|
||||||
{
|
{
|
||||||
if( $totalsize != 0 )
|
if( $totalsize != 0 )
|
||||||
|
|
@ -54,7 +122,12 @@ function litefm_check($home_id)
|
||||||
{
|
{
|
||||||
if (isset($_GET['item']) and !isset($_GET['upload']) and !isset( $_POST['delete'] ) and !isset( $_POST['create_folder'] ) and !isset( $_POST['secureButton'] ) and !isset( $_POST['delete_check'] ) and !isset( $_POST['secure_check'] ))
|
if (isset($_GET['item']) and !isset($_GET['upload']) and !isset( $_POST['delete'] ) and !isset( $_POST['create_folder'] ) and !isset( $_POST['secureButton'] ) and !isset( $_POST['delete_check'] ) and !isset( $_POST['secure_check'] ))
|
||||||
{
|
{
|
||||||
$fileName = !empty($_POST['name']) ? urldecode($_POST['name']) : urldecode($_GET['name']);
|
$fileName = !empty($_POST['name']) ? litefm_decode_name_param($_POST['name']) : litefm_decode_name_param(isset($_GET['name']) ? $_GET['name'] : '');
|
||||||
|
if (!litefm_is_valid_path_component($fileName))
|
||||||
|
{
|
||||||
|
print_failure("Path decode failed");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
if(isset($_GET['type'])){
|
if(isset($_GET['type'])){
|
||||||
$type = $_GET['type'];
|
$type = $_GET['type'];
|
||||||
}else{
|
}else{
|
||||||
|
|
@ -66,23 +139,29 @@ function litefm_check($home_id)
|
||||||
|
|
||||||
$path = $_SESSION['fm_files_'.$home_id][$_GET['item']];
|
$path = $_SESSION['fm_files_'.$home_id][$_GET['item']];
|
||||||
if($path == $fileName){
|
if($path == $fileName){
|
||||||
// Make sure nobody tries to get outside thier game server by referencing the .. directory
|
if($type != "file"){
|
||||||
if(preg_match("/\/\.\.\/|\||;/", $path))
|
$nextPath = trim((string)@$_SESSION['fm_cwd_'.$home_id], '/');
|
||||||
|
$nextPath = $nextPath === '' ? $path : $nextPath . '/' . $path;
|
||||||
|
$normalizedNext = litefm_normalize_relative_path($nextPath);
|
||||||
|
if($normalizedNext === false)
|
||||||
{
|
{
|
||||||
print_failure(get_lang("unallowed_char"));
|
print_failure(get_lang("unallowed_char"));
|
||||||
$_SESSION['fm_cwd_'.$home_id] = NULL;
|
$_SESSION['fm_cwd_'.$home_id] = NULL;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
else
|
$_SESSION['fm_cwd_'.$home_id] = $normalizedNext;
|
||||||
{
|
|
||||||
if($type != "file"){
|
|
||||||
$_SESSION['fm_cwd_'.$home_id] = @$_SESSION['fm_cwd_'.$home_id] . "/" . $path;
|
|
||||||
$_SESSION['fm_cwd_'.$home_id] = clean_path($_SESSION['fm_cwd_'.$home_id]);
|
|
||||||
}else{
|
}else{
|
||||||
if((isset($_SESSION['fm_cwd_'.$home_id]) and !endsWith($_SESSION['fm_cwd_'.$home_id], $path)) or !isset($_SESSION['fm_cwd_'.$home_id])){
|
if((isset($_SESSION['fm_cwd_'.$home_id]) and !endsWith($_SESSION['fm_cwd_'.$home_id], $path)) or !isset($_SESSION['fm_cwd_'.$home_id])){
|
||||||
$_SESSION['fm_cwd_'.$home_id] = @$_SESSION['fm_cwd_'.$home_id] . "/" . $path;
|
$nextPath = trim((string)@$_SESSION['fm_cwd_'.$home_id], '/');
|
||||||
$_SESSION['fm_cwd_'.$home_id] = clean_path($_SESSION['fm_cwd_'.$home_id]);
|
$nextPath = $nextPath === '' ? $path : $nextPath . '/' . $path;
|
||||||
|
$normalizedNext = litefm_normalize_relative_path($nextPath);
|
||||||
|
if($normalizedNext === false)
|
||||||
|
{
|
||||||
|
print_failure(get_lang("unallowed_char"));
|
||||||
|
$_SESSION['fm_cwd_'.$home_id] = NULL;
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
$_SESSION['fm_cwd_'.$home_id] = $normalizedNext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,23 @@ In-panel file manager and file editor for customer server homes.
|
||||||
- remote file listings
|
- remote file listings
|
||||||
- read/write operations
|
- read/write operations
|
||||||
|
|
||||||
|
Current listing flow uses `remote_dirlistfm`, where agent filenames are treated as exact values and preserved by the Panel.
|
||||||
|
|
||||||
## User Workflow
|
## User Workflow
|
||||||
|
|
||||||
- browse files
|
- browse files
|
||||||
- upload/download
|
- upload/download
|
||||||
- edit common configs
|
- edit common configs
|
||||||
|
|
||||||
|
Special-character names are supported end-to-end in browse/navigation/actions, including:
|
||||||
|
|
||||||
|
- `@3739421199`
|
||||||
|
- `@CF`
|
||||||
|
- `My Mod Folder`
|
||||||
|
- `[Server] Configs`
|
||||||
|
- `profile.backup`
|
||||||
|
- `mod+keys`
|
||||||
|
|
||||||
## Admin Workflow
|
## Admin Workflow
|
||||||
|
|
||||||
- set file management permissions
|
- set file management permissions
|
||||||
|
|
@ -43,9 +54,22 @@ In-panel file manager and file editor for customer server homes.
|
||||||
- protected control files
|
- protected control files
|
||||||
- shared secret exposure
|
- shared secret exposure
|
||||||
|
|
||||||
|
Path safety model:
|
||||||
|
|
||||||
|
- Preserve exact filename display and action values (no destructive filename stripping).
|
||||||
|
- Escape output for HTML rendering only.
|
||||||
|
- Encode filename tokens in links using `rawurlencode`; decode with `rawurldecode`.
|
||||||
|
- Reject invalid path components (`..`, path separators, NUL byte).
|
||||||
|
- Normalize relative paths and verify final resolved paths remain inside the assigned game home.
|
||||||
|
- Distinguish user-facing errors:
|
||||||
|
- `Server files have not been installed yet.` (home missing)
|
||||||
|
- `Directory not found: <relative path>` (missing subdirectory)
|
||||||
|
- `Directory exists but cannot be opened. Check permissions.` (listing/access failure)
|
||||||
|
- `Path decode failed` (invalid filename token)
|
||||||
|
|
||||||
## Known Issues
|
## Known Issues
|
||||||
|
|
||||||
- should be hardened around safe roots and backups
|
- very large uploads/downloads still depend on chunking/browser limits
|
||||||
|
|
||||||
## Missing Functionality
|
## Missing Functionality
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue