Overhauled terminal XHR response and tweaked the UI a little

This commit is contained in:
mattpass
2020-07-19 22:44:08 +01:00
parent 6e31578498
commit 8625c41cf9
3 changed files with 106 additions and 64 deletions

View File

@@ -30,7 +30,7 @@ html, body {width: 100%; height: 100%}
.output {position: absolute; display: block; top: 0; padding: 15px 18px 8px 13px; width: 100%; min-height: 100%; border: 0; background: rgba(0,0,0,0.92); color: #ccc}
.commandLine {width: 100%; padding: 8px 2px 8px 0; color: #fff}
.commandLine .user {display: inline-block; height: 24px; margin-top: -4px; margin-left: -13px; padding: 5px 5px 5px 0; margin-bottom: 5px; background: #b58901; color: #000}
.commandLine .path {display: inline-block; height: 24px; margin-top: -4px; padding: 5px 5px 5px 0; margin-bottom: 5px; background: #278bd2; color: #fff}
.commandLine .cwd {display: inline-block; height: 24px; margin-top: -4px; padding: 5px 5px 5px 0; margin-bottom: 5px; background: #278bd2; color: #fff}
.commandLine .promptVLine {display: inline-block; width: 1px; height: 12px; margin-top: -5px; margin-left: 3px; background: #b58901}
.commandLine .promptHLine {display: inline-block; color: #b58901}
.commandLine .promptArrow {display: inline-block; margin-left:-1px}

View File

@@ -1,67 +1,95 @@
<?php
include(dirname(__FILE__)."/headers.php");
include(dirname(__FILE__)."/settings.php");
function proc_open_enabled() {
$disabled = explode(',', ini_get('disable_functions'));
return !in_array('proc_open', $disabled);
}
if(!proc_open_enabled()) {
exit("<span style=\"color: #fff\">Sorry but you can't use this terminal if your proc_open is disabled</span>\n\n");
}
include dirname(__FILE__) . "/headers.php";
include dirname(__FILE__) . "/settings.php";
// Set some common aliases
$aliases = array(
'la' => 'ls -la',
'll' => 'ls -lvhF',
'la' => 'ls -la',
'll' => 'ls -lvhF',
);
// Get current working dir
$user = str_replace("\n","",shell_exec("whoami"));
$cwd = getcwd();
// If we have a current working dir in session, change to that dir
if (true === isset($_SESSION['cwd'])) {
chdir($_SESSION['cwd']);
}
// If we have a command
if(!empty($_REQUEST['command'])) {
// Strip any slashes from it
if(get_magic_quotes_gpc()) {
$_REQUEST['command'] = stripslashes($_REQUEST['command']);
}
// Get current user and cwd
$user = str_replace("\n", "", shell_exec("whoami"));
$cwd = str_replace("\n", "", shell_exec("pwd"));
// Begin output with prompt and user command
$output = '<div class="commandLine"><div class="user">&nbsp;&nbsp;'.$user.'&nbsp;</div>'.
'<div class="path">&nbsp;'.$cwd.'&nbsp;</div> : '.date("H:m:s").
'<br>'.
'<div class="promptVLine"></div><div class="promptHLine">─<div class="promptArrow">▶</div></div> '.$_REQUEST['command'].'</div><br><br>';
// Check if we have proc_open_enabled
// (Used later to handle commands)
function proc_open_enabled() {
$disabled = explode(',', ini_get('disable_functions'));
return false === in_array('proc_open', $disabled);
}
// Return HTML prompt plus the command the user provided last
function returnHTMLPromptCommand($cmd) {
global $user, $cwd;
// Begin output with prompt and user command
return '<div class="commandLine"><div class="user">&nbsp;&nbsp;' . $user . '&nbsp;</div>'.
'<div class="cwd">&nbsp;' . $cwd . '&nbsp;</div> : ' . date("H:m:s") .
'<br>' .
'<div class="promptVLine"></div><div class="promptHLine">─<div class="promptArrow">▶</div></div> ' . $cmd . '</div></div><br>';
}
// If proc_open isn't enabled, display prompt, command and a message re needing this enabled
if (false === proc_open_enabled()) {
echo json_encode([
"output" => returnHTMLPromptCommand($_REQUEST['command'] . "<br><br>Sorry but you can't use this terminal if your proc_open is disabled"),
"user" => $user,
"cwd" => $cwd
]);
exit;
}
// If in demo mode, display message and go no further
if ($demoMode) {
$output .= "Sorry, shell usage not enabled in demo mode\n\n";
echo $output;
exit;
if (true === $demoMode) {
echo json_encode([
"output" => returnHTMLPromptCommand($_REQUEST['command'] . "<br><br>Sorry, shell usage not enabled in demo mode"),
"user" => $user,
"cwd" => $cwd
]);
exit;
}
// If in demo mode, display message and go no further
if (false === isset($_REQUEST['command'])) {
echo json_encode([
"output" => returnHTMLPromptCommand($_REQUEST['command'] . "<br><br>Sorry, no command received"),
"user" => $user,
"cwd" => $cwd
]);
exit;
}
// Strip any slashes from command
$_REQUEST['command'] = stripslashes($_REQUEST['command']);
// Start output with the prompt and command they provided last
$output = returnHTMLPromptCommand($_REQUEST['command']);
// If command contains cd but no dir
if (preg_match('/^[[:blank:]]*cd[[:blank:]]*$/', @$_REQUEST['command'])) {
$_SESSION['cwd'] = getcwd(); //dirname(__FILE__);
if (preg_match('/^[[:blank:]]*cd[[:blank:]]*$/', $_REQUEST['command'])) {
$_SESSION['cwd'] = $cwd;
$output .= returnHTMLPromptCommand("cd");
// Else cd to a dir
} elseif (preg_match('/^[[:blank:]]*cd[[:blank:]]+([^;]+)$/', @$_REQUEST['command'], $regs)) {
} elseif (preg_match('/^[[:blank:]]*cd[[:blank:]]+([^;]+)$/', $_REQUEST['command'], $regs)) {
// The current command is 'cd', which we have to handle as an internal shell command
// Absolute/relative path ?
($regs[1][0] == '/') ? $newDir = $regs[1] : $newDir = $_SESSION['cwd'].'/'.$regs[1];
$newDir = "/" === $regs[1][0] ? $regs[1] : $_SESSION['cwd'] . "/" . $regs[1];
// Tidy up appearance on /./
while (strpos($newDir, '/./') !== false) {
while (false !== strpos($newDir, '/./')) {
$newDir = str_replace('/./', '/', $newDir);
}
// Tidy up appearance on //
while (strpos($newDir, '//') !== false) {
while (false !== strpos($newDir, '//')) {
$newDir = str_replace('//', '/', $newDir);
}
// Tidy up appearance on other variations
while (preg_match('|/\.\.(?!\.)|', $newDir)) {
$newDir = preg_replace('|/?[^/]+/\.\.(?!\.)|', '', $newDir);
while (preg_match('/\/\.\.(?!\.)/', $newDir)) {
$newDir = preg_replace('/\/?[^\/]+\/\.\.(?!\.)/', '', $newDir);
}
// Empty dir
@@ -70,36 +98,35 @@ if (preg_match('/^[[:blank:]]*cd[[:blank:]]*$/', @$_REQUEST['command'])) {
}
// Test if we could change to that dir, else display error
(@chdir($newDir)) ? $_SESSION['cwd'] = $newDir : $output .= "\n\nCould not change to: $newDir\n\n";
(@chdir($newDir)) ? $_SESSION['cwd'] = $newDir : $output .= "Could not change to: $newDir\n\n";
} else {
// The command is not a 'cd' command, so we execute it after
// changing the directory and save the output.
chdir($_SESSION['cwd']);
// The command is not a 'cd' command
// Alias expansion
$length = strcspn(@$_REQUEST['command'], " \t");
$token = substr(@$_REQUEST['command'], 0, $length);
if (isset($aliases[$token])) {
$_REQUEST['command'] = $aliases[$token].substr($_REQUEST['command'], $length);
$length = strcspn($_REQUEST['command'], " \t");
$token = substr($_REQUEST['command'], 0, $length);
if (true === isset($aliases[$token])) {
$_REQUEST['command'] = $aliases[$token] . substr($_REQUEST['command'], $length);
}
// Open a proc with array and $io return
$p = proc_open(
@$_REQUEST['command'],
$_REQUEST['command'],
array(
1 => array('pipe', 'w'),
2 => array('pipe', 'w')
),
$io
);
// Read output sent to stdout
while (!feof($io[1])) { /// this will return always false ... and will loop forever until "fork: retry: no child processes" will show if proc_open is disabled;
$output .= htmlspecialchars(fgets($io[1]),ENT_COMPAT, 'UTF-8');
while (false === feof($io[1])) {
// this will return always false ... and will loop forever until "fork: retry: no child processes" will show if proc_open is disabled;
$output .= htmlspecialchars(fgets($io[1]), ENT_COMPAT, 'UTF-8');
}
// Read output sent to stderr
while (!feof($io[2])) {
$output .= htmlspecialchars(fgets($io[2]),ENT_COMPAT, 'UTF-8');
while (false === feof($io[2])) {
$output .= htmlspecialchars(fgets($io[2]), ENT_COMPAT, 'UTF-8');
}
$output .= "\n";
@@ -109,6 +136,16 @@ if (preg_match('/^[[:blank:]]*cd[[:blank:]]*$/', @$_REQUEST['command'])) {
proc_close($p);
}
// Finally, output our string
echo $output;
// Change to the cwd in session
chdir($_SESSION['cwd']);
// and again ask for current user and working dir
$user = str_replace("\n","",shell_exec("whoami"));
$cwd = str_replace("\n","",shell_exec("pwd"));
// Finally, output our JSON data
echo json_encode([
"output" => $output,
"user" => $user,
"cwd" => $cwd
]);

View File

@@ -60,10 +60,15 @@ sendCmd = function(command) {
if (xhr.status==200) {
// Set the output to also include our response and scroll down to bottom
var newOutput = document.createElement("DIV");
newOutput.innerHTML = xhr.responseText;
responseText = xhr.responseText;
responseJSON = JSON.parse(responseText);
newOutput.innerHTML = responseJSON.output;
document.getElementById("user").innerHTML = "&nbsp;&nbsp" + responseJSON.user + "&nbsp;";
document.getElementById("user").innerHTML = "&nbsp;&nbsp" + responseJSON.user + "&nbsp;";
document.getElementById("cwd").innerHTML = "&nbsp;" + responseJSON.cwd + "&nbsp;";
var cmdElem = document.getElementById("commandLine");
cmdElem.parentNode.insertBefore(newOutput, cmdElem);
document.getElementById("terminal").contentWindow.document.documentElement.scrollTop = document.getElementById('output').scrollHeight;
parent.document.getElementById("terminal").contentWindow.document.documentElement.scrollTop = document.getElementById('output').scrollHeight;
// Add command onto end of history array or set as last item in array
if (currentLine == 0 || commandHistory[commandHistory.length-1].indexOf("[[ICEcoder]]:") !== 0) {
@@ -86,10 +91,11 @@ sendCmd = function(command) {
</script>
</head>
<body>
<body onclick="document.getElementById('command').focus()">
<?php
chdir($_SESSION['cwd']);
$user = str_replace("\n","",shell_exec("whoami"));
$cwd = getcwd();
$cwd = str_replace("\n","",shell_exec("pwd"));
?>
<form name="shell" onsubmit="sendCmd(document.getElementById('command').value); return false" method="POST">
@@ -97,8 +103,7 @@ $cwd = getcwd();
This is a full powered terminal, but will have the permissions of the '<?php echo $user;?>' user.
The more access rights you give that user, the more this terminal has.
<div class="commandLine" id="commandLine"><div class="user">&nbsp;&nbsp;<?php echo $user;?>&nbsp;</div><div class="path">&nbsp;<?php echo $cwd;?>&nbsp;</div>
<div class="promptVLine"></div><div class="promptHLine">─<div class="promptArrow">▶</div></div> <input type="text" class="command" id="command" onkeyup="key(event)" tabindex="1" autocomplete="off"></div></pre>
<div class="commandLine" id="commandLine"><div class="user" id="user">&nbsp;&nbsp;<?php echo $user;?>&nbsp;</div><div class="cwd" id="cwd">&nbsp;<?php echo $cwd;?>&nbsp;</div> : <?php echo date("H:m:s");?><br><div class="promptVLine"></div><div class="promptHLine">─<div class="promptArrow">▶</div></div> <input type="text" class="command" id="command" onkeyup="key(event)" tabindex="1" autocomplete="off"></div></pre>
</form>
</body>