fix: wrap DayZ post_install scripts in CDATA, add XML editor auto-sanitizer
- dayz_arma2co_win32.xml: wrap post_install in CDATA to fix raw '<' breaking XML parsing; fix dbPass generation to use portable tr form - dayz_epoch_mod_win32.xml: same CDATA wrapping; replace < literals so bash actually receives real '<' redirect characters - config_servers.php: add config_games_sanitize_xml_scripts() that wraps bare '<' in script-like nodes with CDATA before saving raw XML; add config_games_script_node_names() helper; structured-editor save now uses createCDATASection() for post_install/pre_start/etc. nodes so shell characters survive DOM round-trips intact Agent-Logs-Url: https://github.com/GameServerPanel/GSP/sessions/1afce49e-510d-49a6-9d11-0b7118d3cf85 Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com>
This commit is contained in:
parent
6dbac841e3
commit
de80f89619
3 changed files with 62 additions and 16 deletions
|
|
@ -169,6 +169,50 @@ function config_games_validate_xml_file(string $config_file): array
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Script-like element names whose text content is shell/batch code.
|
||||||
|
* These nodes should be stored as CDATA sections so that characters such as
|
||||||
|
* '<', '>', '&', etc. survive round-trips through the XML parser unchanged.
|
||||||
|
*/
|
||||||
|
function config_games_script_node_names(): array
|
||||||
|
{
|
||||||
|
return ['pre_install', 'post_install', 'pre_start', 'post_start', 'precmd', 'postcmd'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-sanitize raw XML text: for every script-like element whose text content
|
||||||
|
* contains a bare '<' outside an existing CDATA block, wrap that content in a
|
||||||
|
* CDATA section so the file becomes well-formed. Non-script elements are left
|
||||||
|
* untouched.
|
||||||
|
*
|
||||||
|
* This is applied to raw XML submitted through the editor's "Raw XML" path
|
||||||
|
* before the validation step, giving a best-effort fix rather than a hard
|
||||||
|
* rejection for the most common authoring mistake.
|
||||||
|
*
|
||||||
|
* @param string $xml Raw XML string (may be malformed).
|
||||||
|
* @return string XML string with script content wrapped in CDATA where needed.
|
||||||
|
*/
|
||||||
|
function config_games_sanitize_xml_scripts(string $xml): string
|
||||||
|
{
|
||||||
|
$tags = config_games_script_node_names();
|
||||||
|
foreach ($tags as $tag) {
|
||||||
|
$xml = preg_replace_callback(
|
||||||
|
'/<' . preg_quote($tag, '/') . '(\s[^>]*)?>(?!\s*<!\[CDATA\[)(.*?)<\/' . preg_quote($tag, '/') . '>/si',
|
||||||
|
function ($m) use ($tag) {
|
||||||
|
$attrs = $m[1];
|
||||||
|
$content = $m[2];
|
||||||
|
// Only wrap if the content contains raw < that are not XML entities/tags.
|
||||||
|
if (strpos($content, '<') === false) {
|
||||||
|
return $m[0];
|
||||||
|
}
|
||||||
|
return '<' . $tag . $attrs . '><![CDATA[' . $content . ']]></' . $tag . '>';
|
||||||
|
},
|
||||||
|
$xml
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $xml;
|
||||||
|
}
|
||||||
|
|
||||||
function config_games_print_editor_css()
|
function config_games_print_editor_css()
|
||||||
{
|
{
|
||||||
static $printed = false;
|
static $printed = false;
|
||||||
|
|
@ -388,13 +432,19 @@ function config_games_save_xml($db, $home_cfg_id, array $nodesPayload)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$hasChildren = !empty($nodeData['has_children']);
|
$hasChildren = !empty($nodeData['has_children']);
|
||||||
|
$nodeName = strtolower(substr($path, (int)strrpos($path, '/') + 1));
|
||||||
|
$isScriptNode = in_array($nodeName, config_games_script_node_names(), true);
|
||||||
if (array_key_exists('value', (array)$nodeData)) {
|
if (array_key_exists('value', (array)$nodeData)) {
|
||||||
$normalizedValue = config_games_normalize_newlines($nodeData['value']);
|
$normalizedValue = config_games_normalize_newlines($nodeData['value']);
|
||||||
while ($domNode->firstChild) {
|
while ($domNode->firstChild) {
|
||||||
$domNode->removeChild($domNode->firstChild);
|
$domNode->removeChild($domNode->firstChild);
|
||||||
}
|
}
|
||||||
if ($normalizedValue !== '') {
|
if ($normalizedValue !== '') {
|
||||||
$domNode->appendChild($dom->createTextNode($normalizedValue));
|
if ($isScriptNode) {
|
||||||
|
$domNode->appendChild($dom->createCDATASection($normalizedValue));
|
||||||
|
} else {
|
||||||
|
$domNode->appendChild($dom->createTextNode($normalizedValue));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} elseif (!$hasChildren) {
|
} elseif (!$hasChildren) {
|
||||||
while ($domNode->firstChild) {
|
while ($domNode->firstChild) {
|
||||||
|
|
@ -530,9 +580,11 @@ function exec_ogp_module() {
|
||||||
if ($cfg_info !== FALSE) {
|
if ($cfg_info !== FALSE) {
|
||||||
$config_file = SERVER_CONFIG_LOCATION . $cfg_info['home_cfg_file'];
|
$config_file = SERVER_CONFIG_LOCATION . $cfg_info['home_cfg_file'];
|
||||||
$raw_content = $_POST['raw_xml_content'];
|
$raw_content = $_POST['raw_xml_content'];
|
||||||
|
// Apply best-effort auto-fix: wrap bare '<' chars in script blocks with CDATA.
|
||||||
|
$sanitized_content = config_games_sanitize_xml_scripts($raw_content);
|
||||||
// Write to a temp file for validation
|
// Write to a temp file for validation
|
||||||
$tmp = tempnam(sys_get_temp_dir(), 'gsp_xml_');
|
$tmp = tempnam(sys_get_temp_dir(), 'gsp_xml_');
|
||||||
file_put_contents($tmp, $raw_content);
|
file_put_contents($tmp, $sanitized_content);
|
||||||
$xmlErrors = config_games_validate_xml_file($tmp);
|
$xmlErrors = config_games_validate_xml_file($tmp);
|
||||||
@unlink($tmp);
|
@unlink($tmp);
|
||||||
if (!empty($xmlErrors)) {
|
if (!empty($xmlErrors)) {
|
||||||
|
|
@ -542,7 +594,7 @@ function exec_ogp_module() {
|
||||||
}
|
}
|
||||||
echo "</ul></div>";
|
echo "</ul></div>";
|
||||||
} else {
|
} else {
|
||||||
if (file_put_contents($config_file, $raw_content) !== false) {
|
if (file_put_contents($config_file, $sanitized_content) !== false) {
|
||||||
print_success(get_lang('configs_updated_ok'));
|
print_success(get_lang('configs_updated_ok'));
|
||||||
$config = read_server_config($config_file);
|
$config = read_server_config($config_file);
|
||||||
if ($config !== FALSE) {
|
if ($config !== FALSE) {
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ Make sure if you install a MOD, you list the name here or else it wont get loade
|
||||||
</param>
|
</param>
|
||||||
</server_params>
|
</server_params>
|
||||||
|
|
||||||
<post_install>
|
<post_install><![CDATA[
|
||||||
|
|
||||||
mkdir -p ./cfg
|
mkdir -p ./cfg
|
||||||
touch ./cfg/dayz_arma2co_win32.xml.txt
|
touch ./cfg/dayz_arma2co_win32.xml.txt
|
||||||
|
|
@ -81,7 +81,7 @@ rm -f dayzmod1.9.0.tar
|
||||||
|
|
||||||
#Create Database ---------------------------------------
|
#Create Database ---------------------------------------
|
||||||
|
|
||||||
dbPass=$(</dev/urandom tr -dc 'A-Za-z0-9_' | head -c 12)
|
dbPass=$(tr -dc 'A-Za-z0-9_' </dev/urandom | head -c 12)
|
||||||
srvID=${PWD##*/}
|
srvID=${PWD##*/}
|
||||||
dbID="server_${srvID}"
|
dbID="server_${srvID}"
|
||||||
|
|
||||||
|
|
@ -105,8 +105,6 @@ VALUES (1, ${srvID}, '${dbID}', '${dbPass}', '${dbID}', 1);
|
||||||
mysql --force "${dbID}" < 1.9.0_fresh.sql
|
mysql --force "${dbID}" < 1.9.0_fresh.sql
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Create alsoRun.bat -----------------------------------
|
# Create alsoRun.bat -----------------------------------
|
||||||
|
|
||||||
printf '%s\r\n' \
|
printf '%s\r\n' \
|
||||||
|
|
@ -119,8 +117,7 @@ printf '%s\r\n' \
|
||||||
'for /f "tokens=2 delims==" %%P in ('"'"'wmic process where "ExecutablePath='"'"'%cd:\=\\%\\bec.exe'"'"'" get ProcessId /value ^| find "="'"'"') do >"..\_alsoRun.pid" echo %%P' \
|
'for /f "tokens=2 delims==" %%P in ('"'"'wmic process where "ExecutablePath='"'"'%cd:\=\\%\\bec.exe'"'"'" get ProcessId /value ^| find "="'"'"') do >"..\_alsoRun.pid" echo %%P' \
|
||||||
> _alsoRun.bat
|
> _alsoRun.bat
|
||||||
|
|
||||||
|
]]></post_install>
|
||||||
</post_install>
|
|
||||||
<pre_start>
|
<pre_start>
|
||||||
</pre_start>
|
</pre_start>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ Make sure if you install a MOD, you list the name here or else it wont get loade
|
||||||
</param>
|
</param>
|
||||||
</server_params>
|
</server_params>
|
||||||
|
|
||||||
<post_install>
|
<post_install><![CDATA[
|
||||||
|
|
||||||
mkdir -p ./cfg
|
mkdir -p ./cfg
|
||||||
touch ./cfg/epochmod_win32.xml
|
touch ./cfg/epochmod_win32.xml
|
||||||
|
|
@ -81,7 +81,7 @@ rm -f epochmod.tar
|
||||||
|
|
||||||
#Create Database ---------------------------------------
|
#Create Database ---------------------------------------
|
||||||
|
|
||||||
dbPass=$(</dev/urandom tr -dc 'A-Za-z0-9_' | head -c 12)
|
dbPass=$(tr -dc 'A-Za-z0-9_' </dev/urandom | head -c 12)
|
||||||
srvID=${PWD##*/}
|
srvID=${PWD##*/}
|
||||||
dbID="server_${srvID}"
|
dbID="server_${srvID}"
|
||||||
|
|
||||||
|
|
@ -102,9 +102,7 @@ INSERT INTO panel.gsp_mysql_databases
|
||||||
VALUES (1, ${srvID}, '${dbID}', '${dbPass}', '${dbID}', 1);
|
VALUES (1, ${srvID}, '${dbID}', '${dbPass}', '${dbID}', 1);
|
||||||
"
|
"
|
||||||
|
|
||||||
mysql --force "${dbID}" < 1.9.0_fresh.sql
|
mysql --force "${dbID}" < 1.9.0_fresh.sql
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Create _alsoRun.bat -----------------------------------
|
# Create _alsoRun.bat -----------------------------------
|
||||||
|
|
@ -119,8 +117,7 @@ printf '%s\r\n' \
|
||||||
'for /f "tokens=2 delims==" %%P in ('"'"'wmic process where "ExecutablePath='"'"'%cd:\=\\%\\bec.exe'"'"'" get ProcessId /value ^| find "="'"'"') do >"..\_alsoRun.pid" echo %%P' \
|
'for /f "tokens=2 delims==" %%P in ('"'"'wmic process where "ExecutablePath='"'"'%cd:\=\\%\\bec.exe'"'"'" get ProcessId /value ^| find "="'"'"') do >"..\_alsoRun.pid" echo %%P' \
|
||||||
> _alsoRun.bat
|
> _alsoRun.bat
|
||||||
|
|
||||||
|
]]></post_install>
|
||||||
</post_install>
|
|
||||||
<pre_start>
|
<pre_start>
|
||||||
</pre_start>
|
</pre_start>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue