Skip to content
This repository was archived by the owner on Dec 14, 2023. It is now read-only.

Commit 8625c41

Browse files
author
mattpass
committed
Overhauled terminal XHR response and tweaked the UI a little
1 parent 6e31578 commit 8625c41

File tree

3 files changed

+104
-62
lines changed

3 files changed

+104
-62
lines changed

assets/css/terminal.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ html, body {width: 100%; height: 100%}
3030
.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}
3131
.commandLine {width: 100%; padding: 8px 2px 8px 0; color: #fff}
3232
.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}
33-
.commandLine .path {display: inline-block; height: 24px; margin-top: -4px; padding: 5px 5px 5px 0; margin-bottom: 5px; background: #278bd2; color: #fff}
33+
.commandLine .cwd {display: inline-block; height: 24px; margin-top: -4px; padding: 5px 5px 5px 0; margin-bottom: 5px; background: #278bd2; color: #fff}
3434
.commandLine .promptVLine {display: inline-block; width: 1px; height: 12px; margin-top: -5px; margin-left: 3px; background: #b58901}
3535
.commandLine .promptHLine {display: inline-block; color: #b58901}
3636
.commandLine .promptArrow {display: inline-block; margin-left:-1px}

lib/terminal-xhr.php

Lines changed: 92 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,95 @@
11
<?php
2-
include(dirname(__FILE__)."/headers.php");
3-
include(dirname(__FILE__)."/settings.php");
2+
include dirname(__FILE__) . "/headers.php";
3+
include dirname(__FILE__) . "/settings.php";
44

5+
// Set some common aliases
6+
$aliases = array(
7+
'la' => 'ls -la',
8+
'll' => 'ls -lvhF',
9+
);
510

6-
function proc_open_enabled() {
7-
$disabled = explode(',', ini_get('disable_functions'));
8-
return !in_array('proc_open', $disabled);
11+
// If we have a current working dir in session, change to that dir
12+
if (true === isset($_SESSION['cwd'])) {
13+
chdir($_SESSION['cwd']);
914
}
1015

11-
if(!proc_open_enabled()) {
12-
exit("<span style=\"color: #fff\">Sorry but you can't use this terminal if your proc_open is disabled</span>\n\n");
13-
}
16+
// Get current user and cwd
17+
$user = str_replace("\n", "", shell_exec("whoami"));
18+
$cwd = str_replace("\n", "", shell_exec("pwd"));
1419

15-
$aliases = array(
16-
'la' => 'ls -la',
17-
'll' => 'ls -lvhF',
18-
);
20+
// Check if we have proc_open_enabled
21+
// (Used later to handle commands)
22+
function proc_open_enabled() {
23+
$disabled = explode(',', ini_get('disable_functions'));
24+
return false === in_array('proc_open', $disabled);
25+
}
1926

20-
// Get current working dir
21-
$user = str_replace("\n","",shell_exec("whoami"));
22-
$cwd = getcwd();
27+
// Return HTML prompt plus the command the user provided last
28+
function returnHTMLPromptCommand($cmd) {
29+
global $user, $cwd;
30+
// Begin output with prompt and user command
31+
return '<div class="commandLine"><div class="user">&nbsp;&nbsp;' . $user . '&nbsp;</div>'.
32+
'<div class="cwd">&nbsp;' . $cwd . '&nbsp;</div> : ' . date("H:m:s") .
33+
'<br>' .
34+
'<div class="promptVLine"></div><div class="promptHLine">─<div class="promptArrow">▶</div></div> ' . $cmd . '</div></div><br>';
35+
}
2336

24-
// If we have a command
25-
if(!empty($_REQUEST['command'])) {
26-
// Strip any slashes from it
27-
if(get_magic_quotes_gpc()) {
28-
$_REQUEST['command'] = stripslashes($_REQUEST['command']);
29-
}
37+
// If proc_open isn't enabled, display prompt, command and a message re needing this enabled
38+
if (false === proc_open_enabled()) {
39+
echo json_encode([
40+
"output" => returnHTMLPromptCommand($_REQUEST['command'] . "<br><br>Sorry but you can't use this terminal if your proc_open is disabled"),
41+
"user" => $user,
42+
"cwd" => $cwd
43+
]);
44+
exit;
45+
}
3046

31-
// Begin output with prompt and user command
32-
$output = '<div class="commandLine"><div class="user">&nbsp;&nbsp;'.$user.'&nbsp;</div>'.
33-
'<div class="path">&nbsp;'.$cwd.'&nbsp;</div> : '.date("H:m:s").
34-
'<br>'.
35-
'<div class="promptVLine"></div><div class="promptHLine">─<div class="promptArrow">▶</div></div> '.$_REQUEST['command'].'</div><br><br>';
47+
// If in demo mode, display message and go no further
48+
if (true === $demoMode) {
49+
echo json_encode([
50+
"output" => returnHTMLPromptCommand($_REQUEST['command'] . "<br><br>Sorry, shell usage not enabled in demo mode"),
51+
"user" => $user,
52+
"cwd" => $cwd
53+
]);
54+
exit;
3655
}
3756

3857
// If in demo mode, display message and go no further
39-
if ($demoMode) {
40-
$output .= "Sorry, shell usage not enabled in demo mode\n\n";
41-
echo $output;
42-
exit;
58+
if (false === isset($_REQUEST['command'])) {
59+
echo json_encode([
60+
"output" => returnHTMLPromptCommand($_REQUEST['command'] . "<br><br>Sorry, no command received"),
61+
"user" => $user,
62+
"cwd" => $cwd
63+
]);
64+
exit;
4365
}
4466

67+
// Strip any slashes from command
68+
$_REQUEST['command'] = stripslashes($_REQUEST['command']);
69+
70+
// Start output with the prompt and command they provided last
71+
$output = returnHTMLPromptCommand($_REQUEST['command']);
72+
4573
// If command contains cd but no dir
46-
if (preg_match('/^[[:blank:]]*cd[[:blank:]]*$/', @$_REQUEST['command'])) {
47-
$_SESSION['cwd'] = getcwd(); //dirname(__FILE__);
74+
if (preg_match('/^[[:blank:]]*cd[[:blank:]]*$/', $_REQUEST['command'])) {
75+
$_SESSION['cwd'] = $cwd;
76+
$output .= returnHTMLPromptCommand("cd");
4877
// Else cd to a dir
49-
} elseif (preg_match('/^[[:blank:]]*cd[[:blank:]]+([^;]+)$/', @$_REQUEST['command'], $regs)) {
78+
} elseif (preg_match('/^[[:blank:]]*cd[[:blank:]]+([^;]+)$/', $_REQUEST['command'], $regs)) {
5079
// The current command is 'cd', which we have to handle as an internal shell command
51-
// Absolute/relative path ?
52-
($regs[1][0] == '/') ? $newDir = $regs[1] : $newDir = $_SESSION['cwd'].'/'.$regs[1];
80+
$newDir = "/" === $regs[1][0] ? $regs[1] : $_SESSION['cwd'] . "/" . $regs[1];
5381

5482
// Tidy up appearance on /./
55-
while (strpos($newDir, '/./') !== false) {
83+
while (false !== strpos($newDir, '/./')) {
5684
$newDir = str_replace('/./', '/', $newDir);
5785
}
5886
// Tidy up appearance on //
59-
while (strpos($newDir, '//') !== false) {
87+
while (false !== strpos($newDir, '//')) {
6088
$newDir = str_replace('//', '/', $newDir);
6189
}
6290
// Tidy up appearance on other variations
63-
while (preg_match('|/\.\.(?!\.)|', $newDir)) {
64-
$newDir = preg_replace('|/?[^/]+/\.\.(?!\.)|', '', $newDir);
91+
while (preg_match('/\/\.\.(?!\.)/', $newDir)) {
92+
$newDir = preg_replace('/\/?[^\/]+\/\.\.(?!\.)/', '', $newDir);
6593
}
6694

6795
// Empty dir
@@ -70,36 +98,35 @@ function proc_open_enabled() {
7098
}
7199

72100
// Test if we could change to that dir, else display error
73-
(@chdir($newDir)) ? $_SESSION['cwd'] = $newDir : $output .= "\n\nCould not change to: $newDir\n\n";
101+
(@chdir($newDir)) ? $_SESSION['cwd'] = $newDir : $output .= "Could not change to: $newDir\n\n";
74102
} else {
75-
// The command is not a 'cd' command, so we execute it after
76-
// changing the directory and save the output.
77-
chdir($_SESSION['cwd']);
103+
// The command is not a 'cd' command
78104

79105
// Alias expansion
80-
$length = strcspn(@$_REQUEST['command'], " \t");
81-
$token = substr(@$_REQUEST['command'], 0, $length);
82-
if (isset($aliases[$token])) {
83-
$_REQUEST['command'] = $aliases[$token].substr($_REQUEST['command'], $length);
106+
$length = strcspn($_REQUEST['command'], " \t");
107+
$token = substr($_REQUEST['command'], 0, $length);
108+
if (true === isset($aliases[$token])) {
109+
$_REQUEST['command'] = $aliases[$token] . substr($_REQUEST['command'], $length);
84110
}
85111

86112
// Open a proc with array and $io return
87113
$p = proc_open(
88-
@$_REQUEST['command'],
114+
$_REQUEST['command'],
89115
array(
90116
1 => array('pipe', 'w'),
91117
2 => array('pipe', 'w')
92118
),
93119
$io
94120
);
95-
121+
96122
// Read output sent to stdout
97-
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;
98-
$output .= htmlspecialchars(fgets($io[1]),ENT_COMPAT, 'UTF-8');
123+
while (false === feof($io[1])) {
124+
// this will return always false ... and will loop forever until "fork: retry: no child processes" will show if proc_open is disabled;
125+
$output .= htmlspecialchars(fgets($io[1]), ENT_COMPAT, 'UTF-8');
99126
}
100127
// Read output sent to stderr
101-
while (!feof($io[2])) {
102-
$output .= htmlspecialchars(fgets($io[2]),ENT_COMPAT, 'UTF-8');
128+
while (false === feof($io[2])) {
129+
$output .= htmlspecialchars(fgets($io[2]), ENT_COMPAT, 'UTF-8');
103130
}
104131
$output .= "\n";
105132

@@ -109,6 +136,16 @@ function proc_open_enabled() {
109136
proc_close($p);
110137
}
111138

112-
// Finally, output our string
113-
echo $output;
139+
// Change to the cwd in session
140+
chdir($_SESSION['cwd']);
141+
// and again ask for current user and working dir
142+
$user = str_replace("\n","",shell_exec("whoami"));
143+
$cwd = str_replace("\n","",shell_exec("pwd"));
144+
145+
// Finally, output our JSON data
146+
echo json_encode([
147+
"output" => $output,
148+
"user" => $user,
149+
"cwd" => $cwd
150+
]);
114151

terminal.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,15 @@
6060
if (xhr.status==200) {
6161
// Set the output to also include our response and scroll down to bottom
6262
var newOutput = document.createElement("DIV");
63-
newOutput.innerHTML = xhr.responseText;
63+
responseText = xhr.responseText;
64+
responseJSON = JSON.parse(responseText);
65+
newOutput.innerHTML = responseJSON.output;
66+
document.getElementById("user").innerHTML = "&nbsp;&nbsp" + responseJSON.user + "&nbsp;";
67+
document.getElementById("user").innerHTML = "&nbsp;&nbsp" + responseJSON.user + "&nbsp;";
68+
document.getElementById("cwd").innerHTML = "&nbsp;" + responseJSON.cwd + "&nbsp;";
6469
var cmdElem = document.getElementById("commandLine");
6570
cmdElem.parentNode.insertBefore(newOutput, cmdElem);
66-
document.getElementById("terminal").contentWindow.document.documentElement.scrollTop = document.getElementById('output').scrollHeight;
71+
parent.document.getElementById("terminal").contentWindow.document.documentElement.scrollTop = document.getElementById('output').scrollHeight;
6772

6873
// Add command onto end of history array or set as last item in array
6974
if (currentLine == 0 || commandHistory[commandHistory.length-1].indexOf("[[ICEcoder]]:") !== 0) {
@@ -86,19 +91,19 @@
8691
</script>
8792
</head>
8893

89-
<body>
94+
<body onclick="document.getElementById('command').focus()">
9095
<?php
96+
chdir($_SESSION['cwd']);
9197
$user = str_replace("\n","",shell_exec("whoami"));
92-
$cwd = getcwd();
98+
$cwd = str_replace("\n","",shell_exec("pwd"));
9399
?>
94100

95101
<form name="shell" onsubmit="sendCmd(document.getElementById('command').value); return false" method="POST">
96102
<pre class="output" id="output"><span style="color: #0a0">ICEcoder v<?php echo $ICEcoder["versionNo"];?> terminal</span>
97103
This is a full powered terminal, but will have the permissions of the '<?php echo $user;?>' user.
98104
The more access rights you give that user, the more this terminal has.
99105

100-
<div class="commandLine" id="commandLine"><div class="user">&nbsp;&nbsp;<?php echo $user;?>&nbsp;</div><div class="path">&nbsp;<?php echo $cwd;?>&nbsp;</div>
101-
<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>
106+
<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>
102107
</form>
103108

104109
</body>

0 commit comments

Comments
 (0)