[Security] Address critical flaw in console rendering that allowed arbitrary command execution
This commit is contained in:
parent
ddb98df4af
commit
829453f805
11 changed files with 515 additions and 548 deletions
|
@ -3,6 +3,13 @@ This file is a running track of new features and fixes to each version of the pa
|
|||
|
||||
This project follows [Semantic Versioning](http://semver.org) guidelines.
|
||||
|
||||
## v0.6.3 (Courageous Carniadactylus)
|
||||
### Fixed
|
||||
* **[Security]** — Addresses an oversight in how the terminal rendered information sent from the server feed which allowed a malicious user to execute arbitrary commands on the game-server process itself by using a specifically crafted in-game command.
|
||||
|
||||
### Changed
|
||||
* Removed `jquery.terminal` and replaced it with an in-house developed terminal with less potential for security issues.
|
||||
|
||||
## v0.6.2 (Courageous Carniadactylus)
|
||||
### Fixed
|
||||
* Fixes a few typos throughout the panel, there are more don't worry.
|
||||
|
|
|
@ -39,6 +39,8 @@ AdminLTE - [license](https://github.com/almasaeed2010/AdminLTE/blob/master/LICEN
|
|||
|
||||
Animate.css - [license](https://github.com/daneden/animate.css/blob/master/LICENSE) - [homepage](http://daneden.github.io/animate.css/)
|
||||
|
||||
AnsiUp - [license](https://github.com/drudru/ansi_up/blob/master/Readme.md#license) - [homepage](https://github.com/drudru/ansi_up)
|
||||
|
||||
Async.js - [license](https://github.com/caolan/async/blob/master/LICENSE) - [homepage](https://github.com/caolan/async/)
|
||||
|
||||
Bootstrap - [license](https://github.com/twbs/bootstrap/blob/master/LICENSE) - [homepage](http://getbootstrap.com)
|
||||
|
@ -53,8 +55,6 @@ FontAwesome Animations - [license](https://github.com/l-lin/font-awesome-animati
|
|||
|
||||
jQuery - [license](https://github.com/jquery/jquery/blob/master/LICENSE.txt) - [homepage](http://jquery.com)
|
||||
|
||||
jQuery Terminal - [license](https://github.com/jcubic/jquery.terminal/blob/master/LICENSE) - [homepage](http://terminal.jcubic.pl)
|
||||
|
||||
Laravel Framework - [license](https://github.com/laravel/framework/blob/5.4/LICENSE.md) - [homepage](https://laravel.com)
|
||||
|
||||
Lodash - [license](https://github.com/lodash/lodash/blob/master/LICENSE) - [homepage](https://lodash.com/)
|
||||
|
|
|
@ -311,3 +311,90 @@ input.form-autocomplete-stop[readonly] {
|
|||
background: white;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
#terminal {
|
||||
font-family: monospace;
|
||||
color: #aaa;
|
||||
background: #000;
|
||||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
padding: 10px 10px 0;
|
||||
box-sizing: border-box;
|
||||
min-height: 30px;
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
border-radius: 5px 5px 0 0;
|
||||
}
|
||||
|
||||
#terminal > .cmd {
|
||||
padding: 1px 0;
|
||||
}
|
||||
|
||||
@keyframes blinky {
|
||||
0% {
|
||||
background: transparent;
|
||||
}
|
||||
100% {
|
||||
background: rgba(170, 170, 170, 0.9);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes blinky {
|
||||
0% {
|
||||
background: transparent;
|
||||
}
|
||||
100% {
|
||||
background: rgba(170, 170, 170, 0.9);
|
||||
}
|
||||
}
|
||||
|
||||
#terminal_input {
|
||||
width: 100%;
|
||||
background: #000;
|
||||
border-radius: 0 0 5px 5px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.terminal_input--input {
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
}
|
||||
|
||||
.terminal_input--text, .terminal_input--prompt {
|
||||
line-height: 14px;
|
||||
width: 100%;
|
||||
vertical-align: middle;
|
||||
font-size: 12px;
|
||||
font-family: monospace;
|
||||
margin-bottom: 0;
|
||||
background: transparent;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.terminal_input--text:before, .terminal_input--text:after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 7px;
|
||||
height: 14px;
|
||||
margin: 0 0 -12px -6px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.terminal_input--text:after {
|
||||
position: relative;
|
||||
bottom: 8px;
|
||||
left: 8px;
|
||||
background: #ff00;
|
||||
animation: blinky 0.6s linear infinite alternate;
|
||||
-webkit-animation: blinky 0.6s linear infinite alternate;
|
||||
}
|
||||
|
||||
.terminal_input--input {
|
||||
color: transparent;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
outline: none;
|
||||
}
|
||||
|
|
|
@ -20,39 +20,56 @@
|
|||
var CONSOLE_PUSH_COUNT = Pterodactyl.config.console_count || 10;
|
||||
var CONSOLE_PUSH_FREQ = Pterodactyl.config.console_freq || 200;
|
||||
var CONSOLE_OUTPUT_LIMIT = Pterodactyl.config.console_limit || 2000;
|
||||
|
||||
var InitialLogSent = false;
|
||||
var AnsiUp = new AnsiUp;
|
||||
|
||||
var $terminal = $('#terminal');
|
||||
var $ghostInput = $('.terminal_input--input');
|
||||
var $visibleInput = $('.terminal_input--text');
|
||||
var $scrollNotify = $('#terminalNotify');
|
||||
|
||||
$(document).ready(function () {
|
||||
$ghostInput.focus();
|
||||
$('.terminal_input--text, #terminal_input, #terminal, #terminalNotify').on('click', function () {
|
||||
$ghostInput.focus();
|
||||
});
|
||||
|
||||
$ghostInput.on('input', function () {
|
||||
$visibleInput.html($(this).val());
|
||||
});
|
||||
|
||||
$ghostInput.on('keyup', function (e) {
|
||||
if (e.which === 13) {
|
||||
Socket.emit((ConsoleServerStatus !== 0) ? 'send command' : 'set status', $(this).val());
|
||||
|
||||
$(this).val('');
|
||||
$visibleInput.html('');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$terminal.on('scroll', function () {
|
||||
if ($(this).scrollTop() + $(this).innerHeight() < $(this)[0].scrollHeight) {
|
||||
$scrollNotify.removeClass('hidden');
|
||||
} else {
|
||||
$scrollNotify.addClass('hidden');
|
||||
}
|
||||
});
|
||||
|
||||
window.scrollToBottom = function () {
|
||||
$terminal.scrollTop($terminal[0].scrollHeight);
|
||||
};
|
||||
|
||||
(function initConsole() {
|
||||
window.TerminalQueue = [];
|
||||
window.ConsoleServerStatus = 0;
|
||||
window.Terminal = $('#terminal').terminal(function (command, term) {
|
||||
Socket.emit((ConsoleServerStatus !== 0) ? 'send command' : 'set status', command);
|
||||
}, {
|
||||
greetings: '',
|
||||
name: Pterodactyl.server.uuid,
|
||||
height: 450,
|
||||
exit: false,
|
||||
echoCommand: false,
|
||||
outputLimit: CONSOLE_OUTPUT_LIMIT,
|
||||
prompt: Pterodactyl.server.username + ':~$ ',
|
||||
scrollOnEcho: false,
|
||||
scrollBottomOffset: 5,
|
||||
onBlur: function (terminal) {
|
||||
return false;
|
||||
}
|
||||
window.ConsoleElements = 0;
|
||||
|
||||
$scrollNotify.on('click', function () {
|
||||
window.scrollToBottom();
|
||||
$scrollNotify.addClass('hidden');
|
||||
});
|
||||
|
||||
window.TerminalNotifyElement = $('#terminalNotify');
|
||||
TerminalNotifyElement.on('click', function () {
|
||||
Terminal.scroll_to_bottom();
|
||||
TerminalNotifyElement.addClass('hidden');
|
||||
})
|
||||
|
||||
Terminal.on('scroll', function () {
|
||||
if (Terminal.is_bottom()) {
|
||||
TerminalNotifyElement.addClass('hidden');
|
||||
}
|
||||
})
|
||||
})();
|
||||
|
||||
(function pushOutputQueue() {
|
||||
|
@ -62,16 +79,22 @@ var InitialLogSent = false;
|
|||
|
||||
if (TerminalQueue.length > 0) {
|
||||
for (var i = 0; i < CONSOLE_PUSH_COUNT && TerminalQueue.length > 0; i++) {
|
||||
Terminal.echo(TerminalQueue[0], { flush: false });
|
||||
$terminal.append(
|
||||
'<div class="cmd">' + AnsiUp.ansi_to_html(TerminalQueue[0] + '\u001b[0m') + '</div>'
|
||||
);
|
||||
|
||||
if (! $scrollNotify.is(':visible')) {
|
||||
window.scrollToBottom();
|
||||
}
|
||||
|
||||
window.ConsoleElements++;
|
||||
TerminalQueue.shift();
|
||||
}
|
||||
|
||||
// Flush after looping through all.
|
||||
Terminal.flush();
|
||||
|
||||
// Show Warning
|
||||
if (! Terminal.is_bottom()) {
|
||||
TerminalNotifyElement.removeClass('hidden');
|
||||
var removeElements = window.ConsoleElements - CONSOLE_OUTPUT_LIMIT;
|
||||
if (removeElements > 0) {
|
||||
$('#terminal').find('.cmd').slice(0, removeElements).remove();
|
||||
window.ConsoleElements = window.ConsoleElements - removeElements;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,14 +122,18 @@ var InitialLogSent = false;
|
|||
|
||||
Socket.on('server log', function (data) {
|
||||
if (! InitialLogSent) {
|
||||
Terminal.clear();
|
||||
TerminalQueue.push(data);
|
||||
$('#terminal').html('');
|
||||
data.split(/\n/g).forEach(function (item) {
|
||||
TerminalQueue.push(item);
|
||||
});
|
||||
InitialLogSent = true;
|
||||
}
|
||||
});
|
||||
|
||||
Socket.on('console', function (data) {
|
||||
TerminalQueue.push(data.line);
|
||||
data.line.split(/\n/g).forEach(function (item) {
|
||||
TerminalQueue.push(item);
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
335
public/themes/pterodactyl/vendor/ansi/ansi_up.js
vendored
Normal file
335
public/themes/pterodactyl/vendor/ansi/ansi_up.js
vendored
Normal file
|
@ -0,0 +1,335 @@
|
|||
/* ansi_up.js
|
||||
* author : Dru Nelson
|
||||
* license : MIT
|
||||
* http://github.com/drudru/ansi_up
|
||||
*/
|
||||
(function (factory) {
|
||||
var v;
|
||||
if (typeof module === "object" && typeof module.exports === "object") {
|
||||
v = factory(require, exports);
|
||||
if ("undefined" !== typeof v) module.exports = v;
|
||||
}
|
||||
else if ("function" === typeof define && define.amd) {
|
||||
define(["require", "exports"], factory);
|
||||
}
|
||||
else {
|
||||
var req, exp = {};
|
||||
v = factory(req, exp);
|
||||
window.AnsiUp = exp.default;
|
||||
}
|
||||
})(function (require, exports) {
|
||||
|
||||
"use strict";
|
||||
function rgx(tmplObj) {
|
||||
var subst = [];
|
||||
for (var _i = 1; _i < arguments.length; _i++) {
|
||||
subst[_i - 1] = arguments[_i];
|
||||
}
|
||||
var regexText = tmplObj.raw[0];
|
||||
var wsrgx = /^\s+|\s+\n|\s+#[\s\S]+?\n/gm;
|
||||
var txt2 = regexText.replace(wsrgx, '');
|
||||
return new RegExp(txt2, 'm');
|
||||
}
|
||||
var AnsiUp = (function () {
|
||||
function AnsiUp() {
|
||||
this.VERSION = "2.0.1";
|
||||
this.ansi_colors = [
|
||||
[
|
||||
{ rgb: [0, 0, 0], class_name: "ansi-black" },
|
||||
{ rgb: [187, 0, 0], class_name: "ansi-red" },
|
||||
{ rgb: [0, 187, 0], class_name: "ansi-green" },
|
||||
{ rgb: [187, 187, 0], class_name: "ansi-yellow" },
|
||||
{ rgb: [0, 0, 187], class_name: "ansi-blue" },
|
||||
{ rgb: [187, 0, 187], class_name: "ansi-magenta" },
|
||||
{ rgb: [0, 187, 187], class_name: "ansi-cyan" },
|
||||
{ rgb: [255, 255, 255], class_name: "ansi-white" }
|
||||
],
|
||||
[
|
||||
{ rgb: [85, 85, 85], class_name: "ansi-bright-black" },
|
||||
{ rgb: [255, 85, 85], class_name: "ansi-bright-red" },
|
||||
{ rgb: [0, 255, 0], class_name: "ansi-bright-green" },
|
||||
{ rgb: [255, 255, 85], class_name: "ansi-bright-yellow" },
|
||||
{ rgb: [85, 85, 255], class_name: "ansi-bright-blue" },
|
||||
{ rgb: [255, 85, 255], class_name: "ansi-bright-magenta" },
|
||||
{ rgb: [85, 255, 255], class_name: "ansi-bright-cyan" },
|
||||
{ rgb: [255, 255, 255], class_name: "ansi-bright-white" }
|
||||
]
|
||||
];
|
||||
this.htmlFormatter = {
|
||||
transform: function (fragment, instance) {
|
||||
var txt = fragment.text;
|
||||
if (txt.length === 0)
|
||||
return txt;
|
||||
if (instance._escape_for_html)
|
||||
txt = instance.old_escape_for_html(txt);
|
||||
if (!fragment.bright && fragment.fg === null && fragment.bg === null)
|
||||
return txt;
|
||||
var styles = [];
|
||||
var classes = [];
|
||||
var fg = fragment.fg;
|
||||
var bg = fragment.bg;
|
||||
if (fg === null && fragment.bright)
|
||||
fg = instance.ansi_colors[1][7];
|
||||
if (!instance._use_classes) {
|
||||
if (fg)
|
||||
styles.push("color:rgb(" + fg.rgb.join(',') + ")");
|
||||
if (bg)
|
||||
styles.push("background-color:rgb(" + bg.rgb + ")");
|
||||
}
|
||||
else {
|
||||
if (fg) {
|
||||
if (fg.class_name !== 'truecolor') {
|
||||
classes.push(fg.class_name + "-fg");
|
||||
}
|
||||
else {
|
||||
styles.push("color:rgb(" + fg.rgb.join(',') + ")");
|
||||
}
|
||||
}
|
||||
if (bg) {
|
||||
if (bg.class_name !== 'truecolor') {
|
||||
classes.push(bg.class_name + "-bg");
|
||||
}
|
||||
else {
|
||||
styles.push("background-color:rgb(" + bg.rgb.join(',') + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
var class_string = '';
|
||||
var style_string = '';
|
||||
if (classes.length)
|
||||
class_string = " class=\"" + classes.join(' ') + "\"";
|
||||
if (styles.length)
|
||||
style_string = " style=\"" + styles.join(';') + "\"";
|
||||
return "<span" + class_string + style_string + ">" + txt + "</span>";
|
||||
},
|
||||
compose: function (segments, instance) {
|
||||
return segments.join("");
|
||||
}
|
||||
};
|
||||
this.textFormatter = {
|
||||
transform: function (fragment, instance) {
|
||||
return fragment.text;
|
||||
},
|
||||
compose: function (segments, instance) {
|
||||
return segments.join("");
|
||||
}
|
||||
};
|
||||
this.setup_256_palette();
|
||||
this._use_classes = false;
|
||||
this._escape_for_html = true;
|
||||
this.bright = false;
|
||||
this.fg = this.bg = null;
|
||||
this._buffer = '';
|
||||
}
|
||||
Object.defineProperty(AnsiUp.prototype, "use_classes", {
|
||||
get: function () {
|
||||
return this._use_classes;
|
||||
},
|
||||
set: function (arg) {
|
||||
this._use_classes = arg;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AnsiUp.prototype, "escape_for_html", {
|
||||
get: function () {
|
||||
return this._escape_for_html;
|
||||
},
|
||||
set: function (arg) {
|
||||
this._escape_for_html = arg;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
AnsiUp.prototype.setup_256_palette = function () {
|
||||
var _this = this;
|
||||
this.palette_256 = [];
|
||||
this.ansi_colors.forEach(function (palette) {
|
||||
palette.forEach(function (rec) {
|
||||
_this.palette_256.push(rec);
|
||||
});
|
||||
});
|
||||
var levels = [0, 95, 135, 175, 215, 255];
|
||||
for (var r = 0; r < 6; ++r) {
|
||||
for (var g = 0; g < 6; ++g) {
|
||||
for (var b = 0; b < 6; ++b) {
|
||||
var col = { rgb: [levels[r], levels[g], levels[b]], class_name: 'truecolor' };
|
||||
this.palette_256.push(col);
|
||||
}
|
||||
}
|
||||
}
|
||||
var grey_level = 8;
|
||||
for (var i = 0; i < 24; ++i, grey_level += 10) {
|
||||
var gry = { rgb: [grey_level, grey_level, grey_level], class_name: 'truecolor' };
|
||||
this.palette_256.push(gry);
|
||||
}
|
||||
};
|
||||
AnsiUp.prototype.old_escape_for_html = function (txt) {
|
||||
return txt.replace(/[&<>]/gm, function (str) {
|
||||
if (str === "&")
|
||||
return "&";
|
||||
if (str === "<")
|
||||
return "<";
|
||||
if (str === ">")
|
||||
return ">";
|
||||
});
|
||||
};
|
||||
AnsiUp.prototype.old_linkify = function (txt) {
|
||||
return txt.replace(/(https?:\/\/[^\s]+)/gm, function (str) {
|
||||
return "<a href=\"" + str + "\">" + str + "</a>";
|
||||
});
|
||||
};
|
||||
AnsiUp.prototype.detect_incomplete_ansi = function (txt) {
|
||||
return !(/.*?[\x40-\x7e]/.test(txt));
|
||||
};
|
||||
AnsiUp.prototype.detect_incomplete_link = function (txt) {
|
||||
var found = false;
|
||||
for (var i = txt.length - 1; i > 0; i--) {
|
||||
if (/\s|\x1B/.test(txt[i])) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (/(https?:\/\/[^\s]+)/.test(txt))
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
var prefix = txt.substr(i + 1, 4);
|
||||
if (prefix.length === 0)
|
||||
return -1;
|
||||
if ("http".indexOf(prefix) === 0)
|
||||
return (i + 1);
|
||||
};
|
||||
AnsiUp.prototype.ansi_to = function (txt, formatter) {
|
||||
var pkt = this._buffer + txt;
|
||||
this._buffer = '';
|
||||
var raw_text_pkts = pkt.split(/\x1B\[/);
|
||||
if (raw_text_pkts.length === 1)
|
||||
raw_text_pkts.push('');
|
||||
this.handle_incomplete_sequences(raw_text_pkts);
|
||||
var first_chunk = this.with_state(raw_text_pkts.shift());
|
||||
var blocks = new Array(raw_text_pkts.length);
|
||||
for (var i = 0, len = raw_text_pkts.length; i < len; ++i) {
|
||||
blocks[i] = (formatter.transform(this.process_ansi(raw_text_pkts[i]), this));
|
||||
}
|
||||
if (first_chunk.text.length > 0)
|
||||
blocks.unshift(formatter.transform(first_chunk, this));
|
||||
return formatter.compose(blocks, this);
|
||||
};
|
||||
AnsiUp.prototype.ansi_to_html = function (txt) {
|
||||
return this.ansi_to(txt, this.htmlFormatter);
|
||||
};
|
||||
AnsiUp.prototype.ansi_to_text = function (txt) {
|
||||
return this.ansi_to(txt, this.textFormatter);
|
||||
};
|
||||
AnsiUp.prototype.with_state = function (text) {
|
||||
return { bright: this.bright, fg: this.fg, bg: this.bg, text: text };
|
||||
};
|
||||
AnsiUp.prototype.handle_incomplete_sequences = function (chunks) {
|
||||
var last_chunk = chunks[chunks.length - 1];
|
||||
if ((last_chunk.length > 0) && this.detect_incomplete_ansi(last_chunk)) {
|
||||
this._buffer = "\x1B[" + last_chunk;
|
||||
chunks.pop();
|
||||
chunks.push('');
|
||||
}
|
||||
else {
|
||||
if (last_chunk.slice(-1) === "\x1B") {
|
||||
this._buffer = "\x1B";
|
||||
console.log("raw", chunks);
|
||||
chunks.pop();
|
||||
chunks.push(last_chunk.substr(0, last_chunk.length - 1));
|
||||
console.log(chunks);
|
||||
console.log(last_chunk);
|
||||
}
|
||||
if (chunks.length === 2 &&
|
||||
chunks[1] === "" &&
|
||||
chunks[0].slice(-1) === "\x1B") {
|
||||
this._buffer = "\x1B";
|
||||
last_chunk = chunks.shift();
|
||||
chunks.unshift(last_chunk.substr(0, last_chunk.length - 1));
|
||||
}
|
||||
}
|
||||
};
|
||||
AnsiUp.prototype.process_ansi = function (block) {
|
||||
if (!this._sgr_regex) {
|
||||
this._sgr_regex = (_a = ["\n ^ # beginning of line\n ([!<-?]?) # a private-mode char (!, <, =, >, ?)\n ([d;]*) # any digits or semicolons\n ([ -/]? # an intermediate modifier\n [@-~]) # the command\n ([sS]*) # any text following this CSI sequence\n "], _a.raw = ["\n ^ # beginning of line\n ([!\\x3c-\\x3f]?) # a private-mode char (!, <, =, >, ?)\n ([\\d;]*) # any digits or semicolons\n ([\\x20-\\x2f]? # an intermediate modifier\n [\\x40-\\x7e]) # the command\n ([\\s\\S]*) # any text following this CSI sequence\n "], rgx(_a));
|
||||
}
|
||||
var matches = block.match(this._sgr_regex);
|
||||
if (!matches) {
|
||||
return this.with_state(block);
|
||||
}
|
||||
var orig_txt = matches[4];
|
||||
if (matches[1] !== '' || matches[3] !== 'm') {
|
||||
return this.with_state(orig_txt);
|
||||
}
|
||||
var sgr_cmds = matches[2].split(';');
|
||||
while (sgr_cmds.length > 0) {
|
||||
var sgr_cmd_str = sgr_cmds.shift();
|
||||
var num = parseInt(sgr_cmd_str, 10);
|
||||
if (isNaN(num) || num === 0) {
|
||||
this.fg = this.bg = null;
|
||||
this.bright = false;
|
||||
}
|
||||
else if (num === 1) {
|
||||
this.bright = true;
|
||||
}
|
||||
else if (num === 22) {
|
||||
this.bright = false;
|
||||
}
|
||||
else if (num === 39) {
|
||||
this.fg = null;
|
||||
}
|
||||
else if (num === 49) {
|
||||
this.bg = null;
|
||||
}
|
||||
else if ((num >= 30) && (num < 38)) {
|
||||
var bidx = this.bright ? 1 : 0;
|
||||
this.fg = this.ansi_colors[bidx][(num - 30)];
|
||||
}
|
||||
else if ((num >= 90) && (num < 98)) {
|
||||
this.fg = this.ansi_colors[1][(num - 90)];
|
||||
}
|
||||
else if ((num >= 40) && (num < 48)) {
|
||||
this.bg = this.ansi_colors[0][(num - 40)];
|
||||
}
|
||||
else if ((num >= 100) && (num < 108)) {
|
||||
this.bg = this.ansi_colors[1][(num - 100)];
|
||||
}
|
||||
else if (num === 38 || num === 48) {
|
||||
if (sgr_cmds.length > 0) {
|
||||
var is_foreground = (num === 38);
|
||||
var mode_cmd = sgr_cmds.shift();
|
||||
if (mode_cmd === '5' && sgr_cmds.length > 0) {
|
||||
var palette_index = parseInt(sgr_cmds.shift(), 10);
|
||||
if (palette_index >= 0 && palette_index <= 255) {
|
||||
if (is_foreground)
|
||||
this.fg = this.palette_256[palette_index];
|
||||
else
|
||||
this.bg = this.palette_256[palette_index];
|
||||
}
|
||||
}
|
||||
if (mode_cmd === '2' && sgr_cmds.length > 2) {
|
||||
var r = parseInt(sgr_cmds.shift(), 10);
|
||||
var g = parseInt(sgr_cmds.shift(), 10);
|
||||
var b = parseInt(sgr_cmds.shift(), 10);
|
||||
if ((r >= 0 && r <= 255) && (g >= 0 && g <= 255) && (b >= 0 && b <= 255)) {
|
||||
var c = { rgb: [r, g, b], class_name: 'truecolor' };
|
||||
if (is_foreground)
|
||||
this.fg = c;
|
||||
else
|
||||
this.bg = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.with_state(orig_txt);
|
||||
var _a;
|
||||
};
|
||||
return AnsiUp;
|
||||
}());
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.default = AnsiUp;
|
||||
});
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,121 +0,0 @@
|
|||
/* global define, KeyboardEvent, module */
|
||||
// https://github.com/cvan/keyboardevent-key-polyfill/blob/master/LICENSE.md
|
||||
(function () {
|
||||
|
||||
var keyboardeventKeyPolyfill = {
|
||||
polyfill: polyfill,
|
||||
keys: {
|
||||
3: 'Cancel',
|
||||
6: 'Help',
|
||||
8: 'Backspace',
|
||||
9: 'Tab',
|
||||
12: 'Clear',
|
||||
13: 'Enter',
|
||||
16: 'Shift',
|
||||
17: 'Control',
|
||||
18: 'Alt',
|
||||
19: 'Pause',
|
||||
20: 'CapsLock',
|
||||
27: 'Escape',
|
||||
28: 'Convert',
|
||||
29: 'NonConvert',
|
||||
30: 'Accept',
|
||||
31: 'ModeChange',
|
||||
32: ' ',
|
||||
33: 'PageUp',
|
||||
34: 'PageDown',
|
||||
35: 'End',
|
||||
36: 'Home',
|
||||
37: 'ArrowLeft',
|
||||
38: 'ArrowUp',
|
||||
39: 'ArrowRight',
|
||||
40: 'ArrowDown',
|
||||
41: 'Select',
|
||||
42: 'Print',
|
||||
43: 'Execute',
|
||||
44: 'PrintScreen',
|
||||
45: 'Insert',
|
||||
46: 'Delete',
|
||||
48: ['0', ')'],
|
||||
49: ['1', '!'],
|
||||
50: ['2', '@'],
|
||||
51: ['3', '#'],
|
||||
52: ['4', '$'],
|
||||
53: ['5', '%'],
|
||||
54: ['6', '^'],
|
||||
55: ['7', '&'],
|
||||
56: ['8', '*'],
|
||||
57: ['9', '('],
|
||||
91: 'OS',
|
||||
93: 'ContextMenu',
|
||||
144: 'NumLock',
|
||||
145: 'ScrollLock',
|
||||
181: 'VolumeMute',
|
||||
182: 'VolumeDown',
|
||||
183: 'VolumeUp',
|
||||
186: [';', ':'],
|
||||
187: ['=', '+'],
|
||||
188: [',', '<'],
|
||||
189: ['-', '_'],
|
||||
190: ['.', '>'],
|
||||
191: ['/', '?'],
|
||||
192: ['`', '~'],
|
||||
219: ['[', '{'],
|
||||
220: ['\\', '|'],
|
||||
221: [']', '}'],
|
||||
222: ["'", '"'],
|
||||
224: 'Meta',
|
||||
225: 'AltGraph',
|
||||
246: 'Attn',
|
||||
247: 'CrSel',
|
||||
248: 'ExSel',
|
||||
249: 'EraseEof',
|
||||
250: 'Play',
|
||||
251: 'ZoomOut'
|
||||
}
|
||||
};
|
||||
|
||||
// Function keys (F1-24).
|
||||
var i;
|
||||
for (i = 1; i < 25; i++) {
|
||||
keyboardeventKeyPolyfill.keys[111 + i] = 'F' + i;
|
||||
}
|
||||
|
||||
// Printable ASCII characters.
|
||||
var letter = '';
|
||||
for (i = 65; i < 91; i++) {
|
||||
letter = String.fromCharCode(i);
|
||||
keyboardeventKeyPolyfill.keys[i] = [letter.toLowerCase(), letter.toUpperCase()];
|
||||
}
|
||||
|
||||
function polyfill () {
|
||||
if (!('KeyboardEvent' in window) ||
|
||||
'key' in KeyboardEvent.prototype) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Polyfill `key` on `KeyboardEvent`.
|
||||
var proto = {
|
||||
get: function (x) {
|
||||
var key = keyboardeventKeyPolyfill.keys[this.which || this.keyCode];
|
||||
|
||||
if (Array.isArray(key)) {
|
||||
key = key[+this.shiftKey];
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
};
|
||||
Object.defineProperty(KeyboardEvent.prototype, 'key', proto);
|
||||
return proto;
|
||||
}
|
||||
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define('keyboardevent-key-polyfill', keyboardeventKeyPolyfill);
|
||||
} else if (typeof exports !== 'undefined' && typeof module !== 'undefined') {
|
||||
module.exports = keyboardeventKeyPolyfill;
|
||||
} else if (window) {
|
||||
window.keyboardeventKeyPolyfill = keyboardeventKeyPolyfill;
|
||||
}
|
||||
|
||||
})();
|
|
@ -1,318 +0,0 @@
|
|||
/**@license
|
||||
* __ _____ ________ __
|
||||
* / // _ /__ __ _____ ___ __ _/__ ___/__ ___ ______ __ __ __ ___ / /
|
||||
* __ / // // // // // _ // _// // / / // _ // _// // // \/ // _ \/ /
|
||||
* / / // // // // // ___// / / // / / // ___// / / / / // // /\ // // / /__
|
||||
* \___//____ \\___//____//_/ _\_ / /_//____//_/ /_/ /_//_//_/ /_/ \__\_\___/
|
||||
* \/ /____/
|
||||
* http://terminal.jcubic.pl
|
||||
*
|
||||
* This is example of how to create custom formatter for jQuery Terminal
|
||||
*
|
||||
* Copyright (c) 2014-2016 Jakub Jankiewicz <http://jcubic.pl/me>
|
||||
* Released under the MIT license
|
||||
*
|
||||
*/
|
||||
(function($) {
|
||||
if (!$.terminal) {
|
||||
throw new Error('$.terminal is not defined');
|
||||
}
|
||||
// ---------------------------------------------------------------------
|
||||
// :: Replace overtyping (from man) formatting with terminal formatting
|
||||
// ---------------------------------------------------------------------
|
||||
$.terminal.overtyping = function(string) {
|
||||
return string.replace(/((?:_\x08.|.\x08_)+)/g, function(full) {
|
||||
var striped = full.replace(/_x08|\x08_|_\u0008|\u0008_/g, '');
|
||||
return '[[u;;]' + striped + ']';
|
||||
}).replace(/((?:.\x08.)+)/g, function(full) {
|
||||
return '[[b;#fff;]' + full.replace(/(.)(?:\x08|\u0008)\1/g,
|
||||
function(full, g) {
|
||||
return g;
|
||||
}) + ']';
|
||||
});
|
||||
};
|
||||
// ---------------------------------------------------------------------
|
||||
// :: Html colors taken from ANSI formatting in Linux Terminal
|
||||
// ---------------------------------------------------------------------
|
||||
$.terminal.ansi_colors = {
|
||||
normal: {
|
||||
black: '#000',
|
||||
red: '#A00',
|
||||
green: '#008400',
|
||||
yellow: '#A50',
|
||||
blue: '#00A',
|
||||
magenta: '#A0A',
|
||||
cyan: '#0AA',
|
||||
white: '#AAA'
|
||||
},
|
||||
faited: {
|
||||
black: '#000',
|
||||
red: '#640000',
|
||||
green: '#006100',
|
||||
yellow: '#737300',
|
||||
blue: '#000087',
|
||||
magenta: '#650065',
|
||||
cyan: '#008787',
|
||||
white: '#818181'
|
||||
},
|
||||
bold: {
|
||||
black: '#000',
|
||||
red: '#F55',
|
||||
green: '#44D544',
|
||||
yellow: '#FF5',
|
||||
blue: '#55F',
|
||||
magenta: '#F5F',
|
||||
cyan: '#5FF',
|
||||
white: '#FFF'
|
||||
},
|
||||
// XTerm 8-bit pallete
|
||||
palette: [
|
||||
'#000000', '#AA0000', '#00AA00', '#AA5500', '#0000AA', '#AA00AA',
|
||||
'#00AAAA', '#AAAAAA', '#555555', '#FF5555', '#55FF55', '#FFFF55',
|
||||
'#5555FF', '#FF55FF', '#55FFFF', '#FFFFFF', '#000000', '#00005F',
|
||||
'#000087', '#0000AF', '#0000D7', '#0000FF', '#005F00', '#005F5F',
|
||||
'#005F87', '#005FAF', '#005FD7', '#005FFF', '#008700', '#00875F',
|
||||
'#008787', '#0087AF', '#0087D7', '#0087FF', '#00AF00', '#00AF5F',
|
||||
'#00AF87', '#00AFAF', '#00AFD7', '#00AFFF', '#00D700', '#00D75F',
|
||||
'#00D787', '#00D7AF', '#00D7D7', '#00D7FF', '#00FF00', '#00FF5F',
|
||||
'#00FF87', '#00FFAF', '#00FFD7', '#00FFFF', '#5F0000', '#5F005F',
|
||||
'#5F0087', '#5F00AF', '#5F00D7', '#5F00FF', '#5F5F00', '#5F5F5F',
|
||||
'#5F5F87', '#5F5FAF', '#5F5FD7', '#5F5FFF', '#5F8700', '#5F875F',
|
||||
'#5F8787', '#5F87AF', '#5F87D7', '#5F87FF', '#5FAF00', '#5FAF5F',
|
||||
'#5FAF87', '#5FAFAF', '#5FAFD7', '#5FAFFF', '#5FD700', '#5FD75F',
|
||||
'#5FD787', '#5FD7AF', '#5FD7D7', '#5FD7FF', '#5FFF00', '#5FFF5F',
|
||||
'#5FFF87', '#5FFFAF', '#5FFFD7', '#5FFFFF', '#870000', '#87005F',
|
||||
'#870087', '#8700AF', '#8700D7', '#8700FF', '#875F00', '#875F5F',
|
||||
'#875F87', '#875FAF', '#875FD7', '#875FFF', '#878700', '#87875F',
|
||||
'#878787', '#8787AF', '#8787D7', '#8787FF', '#87AF00', '#87AF5F',
|
||||
'#87AF87', '#87AFAF', '#87AFD7', '#87AFFF', '#87D700', '#87D75F',
|
||||
'#87D787', '#87D7AF', '#87D7D7', '#87D7FF', '#87FF00', '#87FF5F',
|
||||
'#87FF87', '#87FFAF', '#87FFD7', '#87FFFF', '#AF0000', '#AF005F',
|
||||
'#AF0087', '#AF00AF', '#AF00D7', '#AF00FF', '#AF5F00', '#AF5F5F',
|
||||
'#AF5F87', '#AF5FAF', '#AF5FD7', '#AF5FFF', '#AF8700', '#AF875F',
|
||||
'#AF8787', '#AF87AF', '#AF87D7', '#AF87FF', '#AFAF00', '#AFAF5F',
|
||||
'#AFAF87', '#AFAFAF', '#AFAFD7', '#AFAFFF', '#AFD700', '#AFD75F',
|
||||
'#AFD787', '#AFD7AF', '#AFD7D7', '#AFD7FF', '#AFFF00', '#AFFF5F',
|
||||
'#AFFF87', '#AFFFAF', '#AFFFD7', '#AFFFFF', '#D70000', '#D7005F',
|
||||
'#D70087', '#D700AF', '#D700D7', '#D700FF', '#D75F00', '#D75F5F',
|
||||
'#D75F87', '#D75FAF', '#D75FD7', '#D75FFF', '#D78700', '#D7875F',
|
||||
'#D78787', '#D787AF', '#D787D7', '#D787FF', '#D7AF00', '#D7AF5F',
|
||||
'#D7AF87', '#D7AFAF', '#D7AFD7', '#D7AFFF', '#D7D700', '#D7D75F',
|
||||
'#D7D787', '#D7D7AF', '#D7D7D7', '#D7D7FF', '#D7FF00', '#D7FF5F',
|
||||
'#D7FF87', '#D7FFAF', '#D7FFD7', '#D7FFFF', '#FF0000', '#FF005F',
|
||||
'#FF0087', '#FF00AF', '#FF00D7', '#FF00FF', '#FF5F00', '#FF5F5F',
|
||||
'#FF5F87', '#FF5FAF', '#FF5FD7', '#FF5FFF', '#FF8700', '#FF875F',
|
||||
'#FF8787', '#FF87AF', '#FF87D7', '#FF87FF', '#FFAF00', '#FFAF5F',
|
||||
'#FFAF87', '#FFAFAF', '#FFAFD7', '#FFAFFF', '#FFD700', '#FFD75F',
|
||||
'#FFD787', '#FFD7AF', '#FFD7D7', '#FFD7FF', '#FFFF00', '#FFFF5F',
|
||||
'#FFFF87', '#FFFFAF', '#FFFFD7', '#FFFFFF', '#080808', '#121212',
|
||||
'#1C1C1C', '#262626', '#303030', '#3A3A3A', '#444444', '#4E4E4E',
|
||||
'#585858', '#626262', '#6C6C6C', '#767676', '#808080', '#8A8A8A',
|
||||
'#949494', '#9E9E9E', '#A8A8A8', '#B2B2B2', '#BCBCBC', '#C6C6C6',
|
||||
'#D0D0D0', '#DADADA', '#E4E4E4', '#EEEEEE'
|
||||
]
|
||||
};
|
||||
// ---------------------------------------------------------------------
|
||||
// :: Replace ANSI formatting with terminal formatting
|
||||
// ---------------------------------------------------------------------
|
||||
$.terminal.from_ansi = (function() {
|
||||
var color_list = {
|
||||
30: 'black',
|
||||
31: 'red',
|
||||
32: 'green',
|
||||
33: 'yellow',
|
||||
34: 'blue',
|
||||
35: 'magenta',
|
||||
36: 'cyan',
|
||||
37: 'white',
|
||||
|
||||
39: 'inherit' // default color
|
||||
};
|
||||
var background_list = {
|
||||
40: 'black',
|
||||
41: 'red',
|
||||
42: 'green',
|
||||
43: 'yellow',
|
||||
44: 'blue',
|
||||
45: 'magenta',
|
||||
46: 'cyan',
|
||||
47: 'white',
|
||||
|
||||
49: 'transparent' // default background
|
||||
};
|
||||
function format_ansi(code) {
|
||||
var controls = code.split(';');
|
||||
var num;
|
||||
var faited = false;
|
||||
var reverse = false;
|
||||
var bold = false;
|
||||
var styles = [];
|
||||
var output_color = '';
|
||||
var output_background = '';
|
||||
var _8bit_color = false;
|
||||
var _8bit_background = false;
|
||||
var process_8bit = false;
|
||||
var palette = $.terminal.ansi_colors.palette;
|
||||
function set_styles(num) {
|
||||
switch (num) {
|
||||
case 1:
|
||||
styles.push('b');
|
||||
bold = true;
|
||||
faited = false;
|
||||
break;
|
||||
case 4:
|
||||
styles.push('u');
|
||||
break;
|
||||
case 3:
|
||||
styles.push('i');
|
||||
break;
|
||||
case 5:
|
||||
process_8bit = true;
|
||||
break;
|
||||
case 38:
|
||||
_8bit_color = true;
|
||||
break;
|
||||
case 48:
|
||||
_8bit_background = true;
|
||||
break;
|
||||
case 2:
|
||||
faited = true;
|
||||
bold = false;
|
||||
break;
|
||||
case 7:
|
||||
reverse = true;
|
||||
break;
|
||||
default:
|
||||
if (controls.indexOf('5') === -1) {
|
||||
if (color_list[num]) {
|
||||
output_color = color_list[num];
|
||||
}
|
||||
if (background_list[num]) {
|
||||
output_background = background_list[num];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i in controls) {
|
||||
if (controls.hasOwnProperty(i)) {
|
||||
num = parseInt(controls[i], 10);
|
||||
if (process_8bit && (_8bit_background || _8bit_color)) {
|
||||
if (_8bit_color && palette[num]) {
|
||||
output_color = palette[num];
|
||||
}
|
||||
if (_8bit_background && palette[num]) {
|
||||
output_background = palette[num];
|
||||
}
|
||||
} else {
|
||||
set_styles(num);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (reverse) {
|
||||
if (output_color || output_background) {
|
||||
var tmp = output_background;
|
||||
output_background = output_color;
|
||||
output_color = tmp;
|
||||
} else {
|
||||
output_color = 'black';
|
||||
output_background = 'white';
|
||||
}
|
||||
}
|
||||
var colors, color, background, backgrounds;
|
||||
if (bold) {
|
||||
colors = backgrounds = $.terminal.ansi_colors.bold;
|
||||
} else if (faited) {
|
||||
colors = backgrounds = $.terminal.ansi_colors.faited;
|
||||
} else {
|
||||
colors = backgrounds = $.terminal.ansi_colors.normal;
|
||||
}
|
||||
if (_8bit_color) {
|
||||
color = output_color;
|
||||
} else if (output_color === 'inherit') {
|
||||
color = output_color;
|
||||
} else {
|
||||
color = colors[output_color];
|
||||
}
|
||||
if (_8bit_background) {
|
||||
background = output_background;
|
||||
} else if (output_background === 'transparent') {
|
||||
background = output_background;
|
||||
} else {
|
||||
background = backgrounds[output_background];
|
||||
}
|
||||
return [styles.join(''), color, background];
|
||||
}
|
||||
return function(input) {
|
||||
//merge multiple codes
|
||||
/*input = input.replace(/((?:\x1B\[[0-9;]*[A-Za-z])*)/g, function(group) {
|
||||
return group.replace(/m\x1B\[/g, ';');
|
||||
});*/
|
||||
var splitted = input.split(/(\x1B\[[0-9;]*[A-Za-z])/g);
|
||||
if (splitted.length === 1) {
|
||||
return input;
|
||||
}
|
||||
var output = [];
|
||||
//skip closing at the begining
|
||||
if (splitted.length > 3) {
|
||||
var str = splitted.slice(0, 3).join('');
|
||||
if (str.match(/^\[0*m$/)) {
|
||||
splitted = splitted.slice(3);
|
||||
}
|
||||
}
|
||||
var prev_color, prev_background, code, match;
|
||||
var inside = false;
|
||||
for (var i = 0; i < splitted.length; ++i) {
|
||||
match = splitted[i].match(/^\x1B\[([0-9;]*)([A-Za-z])$/);
|
||||
if (match) {
|
||||
switch (match[2]) {
|
||||
case 'm':
|
||||
if (+match[1] !== 0) {
|
||||
code = format_ansi(match[1]);
|
||||
}
|
||||
if (inside) {
|
||||
output.push(']');
|
||||
if (+match[1] === 0) {
|
||||
//just closing
|
||||
inside = false;
|
||||
prev_color = prev_background = '';
|
||||
} else {
|
||||
// someone forget to close - move to next
|
||||
code[1] = code[1] || prev_color;
|
||||
code[2] = code[2] || prev_background;
|
||||
output.push('[[' + code.join(';') + ']');
|
||||
// store colors to next use
|
||||
if (code[1]) {
|
||||
prev_color = code[1];
|
||||
}
|
||||
if (code[2]) {
|
||||
prev_background = code[2];
|
||||
}
|
||||
}
|
||||
} else if (+match[1] !== 0) {
|
||||
inside = true;
|
||||
code[1] = code[1] || prev_color;
|
||||
code[2] = code[2] || prev_background;
|
||||
output.push('[[' + code.join(';') + ']');
|
||||
// store colors to next use
|
||||
if (code[1]) {
|
||||
prev_color = code[1];
|
||||
}
|
||||
if (code[2]) {
|
||||
prev_background = code[2];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
output.push(splitted[i]);
|
||||
}
|
||||
}
|
||||
if (inside) {
|
||||
output.push(']');
|
||||
}
|
||||
return output.join(''); //.replace(/\[\[[^\]]+\]\]/g, '');
|
||||
};
|
||||
})();
|
||||
$.terminal.defaults.formatters.push($.terminal.overtyping);
|
||||
$.terminal.defaults.formatters.push($.terminal.from_ansi);
|
||||
})(jQuery);
|
|
@ -22,28 +22,36 @@
|
|||
<head>
|
||||
<title>{{ Settings::get('company', 'Pterodactyl') }} - Console → {{ $server->name }}</title>
|
||||
@include('layouts.scripts')
|
||||
{!! Theme::css('vendor/terminal/jquery.terminal.css') !!}
|
||||
{!! Theme::css('vendor/bootstrap/bootstrap.min.css') !!}
|
||||
{!! Theme::css('css/pterodactyl.css') !!}
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
</head>
|
||||
<body style="margin:0;width:100%;height:100%;">
|
||||
<div id="terminal" style="width:100%"></div>
|
||||
<body style="margin:0;width:100%;height:100%;background:#000;overflow: hidden;">
|
||||
<div id="terminal" style="width:100%;max-height: none !important;"></div>
|
||||
<div id="terminal_input">
|
||||
<span class="terminal_input--prompt">{{ $server->username }}:~$</span> <span class="terminal_input--text"></span>
|
||||
<input type="text" class="terminal_input--input" />
|
||||
</div>
|
||||
<div id="terminalNotify" class="terminal-notify hidden">
|
||||
<i class="fa fa-bell"></i>
|
||||
</div>
|
||||
</body>
|
||||
<script>window.SkipConsoleCharts = true</script>
|
||||
{!! Theme::js('js/laroute.js') !!}
|
||||
{!! Theme::js('vendor/ansi/ansi_up.js') !!}
|
||||
{!! Theme::js('vendor/jquery/jquery.min.js') !!}
|
||||
{!! Theme::js('vendor/socketio/socket.io.min.js') !!}
|
||||
{!! Theme::js('vendor/bootstrap-notify/bootstrap-notify.min.js') !!}
|
||||
{!! Theme::js('js/frontend/server.socket.js') !!}
|
||||
{!! Theme::js('vendor/mousewheel/jquery.mousewheel-min.js') !!}
|
||||
{!! Theme::js('vendor/terminal/jquery.terminal.min.js') !!}
|
||||
{!! Theme::js('vendor/terminal/unix_formatting.js') !!}
|
||||
{!! Theme::js('js/frontend/console.js') !!}
|
||||
<script>
|
||||
Terminal.resize($(window).innerWidth() - 20, $(window).innerHeight() - 20);
|
||||
$terminal.height($(window).innerHeight() - 40);
|
||||
$terminal.width($(window).innerWidth() - 40);
|
||||
$(window).on('resize', function () {
|
||||
Terminal.resize($(window).innerWidth() - 20, $(window).innerHeight() - 20);
|
||||
window.scrollToBottom();
|
||||
$terminal.height($(window).innerHeight() - 40);
|
||||
$terminal.width($(window).innerWidth() - 40);
|
||||
});
|
||||
</script>
|
||||
</html>
|
||||
|
|
|
@ -23,11 +23,6 @@
|
|||
{{ trans('server.index.title', [ 'name' => $server->name]) }}
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
@parent
|
||||
{!! Theme::css('vendor/terminal/jquery.terminal.css') !!}
|
||||
@endsection
|
||||
|
||||
@section('content-header')
|
||||
<h1>@lang('server.index.header')<small>@lang('server.index.header_sub')</small></h1>
|
||||
<ol class="breadcrumb">
|
||||
|
@ -42,6 +37,10 @@
|
|||
<div class="box">
|
||||
<div class="box-body position-relative">
|
||||
<div id="terminal" style="width:100%;"></div>
|
||||
<div id="terminal_input">
|
||||
<span class="terminal_input--prompt">{{ $server->username }}:~$</span> <span class="terminal_input--text"></span>
|
||||
<input type="text" class="terminal_input--input" />
|
||||
</div>
|
||||
<div id="terminalNotify" class="terminal-notify hidden">
|
||||
<i class="fa fa-bell"></i>
|
||||
</div>
|
||||
|
@ -81,10 +80,9 @@
|
|||
|
||||
@section('footer-scripts')
|
||||
@parent
|
||||
{!! Theme::js('vendor/ansi/ansi_up.js') !!}
|
||||
{!! Theme::js('js/frontend/server.socket.js') !!}
|
||||
{!! Theme::js('vendor/mousewheel/jquery.mousewheel-min.js') !!}
|
||||
{!! Theme::js('vendor/terminal/jquery.terminal.min.js') !!}
|
||||
{!! Theme::js('vendor/terminal/unix_formatting.js') !!}
|
||||
{!! Theme::js('js/frontend/console.js') !!}
|
||||
{!! Theme::js('vendor/chartjs/chart.min.js') !!}
|
||||
{!! Theme::js('vendor/jquery/date-format.min.js') !!}
|
||||
|
|
Loading…
Reference in a new issue