mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-11-27 02:04:30 +03:00
Draft addition of terminal to mobile site.
This commit is contained in:
parent
d189871623
commit
9269c29bf0
@ -12,6 +12,7 @@
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="{{{domainurl}}}favicon-16x16.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{{{domainurl}}}favicon-32x32.png">
|
||||
<link rel="apple-touch-icon" href="/favicon-303x303.png" />
|
||||
<link type="text/css" href="styles/xterm.css" media="screen" rel="stylesheet" title="CSS" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="#ffffff">
|
||||
<meta name="apple-mobile-web-app-title" content="{{{title}}}">
|
||||
@ -22,6 +23,8 @@
|
||||
<script type="text/javascript" src="scripts/amt-0.2.0{{{min}}}.js"></script>
|
||||
<script type="text/javascript" src="scripts/amt-redir-ws-0.1.0{{{min}}}.js"></script>
|
||||
<script type="text/javascript" src="scripts/amt-desktop-0.0.2{{{min}}}.js"></script>
|
||||
<script type="text/javascript" src="scripts/xterm{{{min}}}.js"></script>
|
||||
<script type="text/javascript" src="scripts/xterm-addon-fit{{{min}}}.js"></script>
|
||||
<script type="text/javascript" src="scripts/zlib{{{min}}}.js"></script>
|
||||
<script type="text/javascript" src="scripts/zlib-inflate{{{min}}}.js"></script>
|
||||
<script type="text/javascript" src="scripts/zlib-adler32{{{min}}}.js"></script>
|
||||
@ -627,6 +630,33 @@
|
||||
border-bottom:1px solid black;
|
||||
}
|
||||
|
||||
#termTable {
|
||||
width: 100%;
|
||||
padding: 0px;
|
||||
padding: 0px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.fulldesk #termTable {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#termarea3x {
|
||||
background: black;
|
||||
text-align: center;
|
||||
height: 500px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#Term {
|
||||
background: black;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body id="body" onload="if (typeof(startup) !== 'undefined') startup();" style="overflow-y:hidden;margin:0;padding:0;border:0;font-size:13px;font-family:\'Trebuchet MS\', Arial, Helvetica, sans-serif">
|
||||
@ -888,6 +918,41 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id=p10terminal style="overflow:hidden;position:absolute;top:55px;bottom:0px;width:100%;display:none">
|
||||
<div id=termTable style="position:relative">
|
||||
<table style="width:100%" cellpadding=0 cellspacing=0>
|
||||
<tr>
|
||||
<td class="areaHead">
|
||||
<div class="toright2">
|
||||
</div>
|
||||
<div>
|
||||
<input type="button" id="autoconnectbutton2" value="AutoConnect" onclick=autoConnectTerminal(event) onkeypress="return false" onkeydown="return false" style="display:none" />
|
||||
<span id="connectbutton2span"><input type="button" id="connectbutton2" cmenu="termConnectButton" value="Connect" onclick=connectTerminal(event,1) onkeypress="return false" onkeydown="return false" disabled="disabled" /></span>
|
||||
<span id="disconnectbutton2span"> <input type="button" id="disconnectbutton2" value="Disconnect" onclick=connectTerminal(event,0) onkeypress="return false" onkeydown="return false" /></span>
|
||||
<span id="termstatus" style="line-height:22px">Disconnected</span><span id="termtitle"></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="termarea3x">
|
||||
<div id="termarea3xdiv" style="width:100%;height:100%"></div>
|
||||
<pre id="Term"></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="areaFoot">
|
||||
<div class="toright2">
|
||||
</div>
|
||||
<div>
|
||||
|
||||
<input id="termActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() />
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id=p12TermConsoleMsg style="display:none;cursor:pointer;position:absolute;left:30px;top:45px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=p12clearConsoleMsg()></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id=p10files style="position:absolute;top:55px;bottom:0px;width:100%;display:none">
|
||||
<table id="p13toolbar" style="width:100%;height:111px" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
@ -1179,15 +1244,20 @@
|
||||
var StatusStrs = ["Disconnected", "Connecting...", "Setup...", "Connected", "Intel® AMT Connected"];
|
||||
var agentsStr = ["Unknown", "Windows 32bit console", "Windows 64bit console", "Windows 32bit service", "Windows 64bit service", "Linux 32bit", "Linux 64bit", "MIPS", "XENx86", "Android ARM", "Linux ARM", "macOS x86-32bit", "Android x86", "PogoPlug ARM", "Android", "Linux Poky x86-32bit", "macOS x86-64bit", "ChromeOS", "Linux Poky x86-64bit", "Linux NoKVM x86-32bit", "Linux NoKVM x86-64bit", "Windows MinCore console", "Windows MinCore service", "NodeJS", "ARM-Linaro", "ARMv6l / ARMv7l", "ARMv8 64bit", "ARMv6l / ARMv7l / NoKVM", "MIPS24KC (OpenWRT)", "Apple Silicon", "FreeBSD x86-64", "Unknown", "Linux ARM 64 bit (glibc/2.24 NOKVM)", "Alpine Linux x86 64 Bit (MUSL)", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "MIPSEL24KC (OpenWRT)", "ARMADA/CORTEX-A53/MUSL (OpenWRT)"];
|
||||
var files;
|
||||
var terminal;
|
||||
var passRequirements = '{{{passRequirements}}}';
|
||||
if (passRequirements != '') { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); }
|
||||
var sessionActivity = Date.now();
|
||||
var deskPinchZoom;
|
||||
var deskKeyboardShortcuts = [];
|
||||
var nightMode = setNightMode();
|
||||
var xterm = null;
|
||||
var xtermfit = null;
|
||||
var xtermResizeTimer = null;
|
||||
|
||||
// Console Message Display Timers
|
||||
var p11DeskConsoleMsgTimer = null;
|
||||
var p12TermConsoleMsgTimer = null;
|
||||
var p13FilesConsoleMsgTimer = null;
|
||||
|
||||
function startup() {
|
||||
@ -3316,6 +3386,7 @@
|
||||
|
||||
// Show node last 7 days timeline
|
||||
//drawDeviceTimeline();
|
||||
setupTerminal();
|
||||
setupFiles();
|
||||
if (meshrights & 16) { setupConsole(); }
|
||||
|
||||
@ -3389,6 +3460,7 @@
|
||||
QV('p10files', currentDevicePanel == 2);
|
||||
QV('p10details', currentDevicePanel == 3);
|
||||
QV('p10console', currentDevicePanel == 4);
|
||||
QV('p10terminal', currentDevicePanel == 5);
|
||||
var menus = [];
|
||||
if (currentDevicePanel != 0) { menus.push({ n: "General", f: 'setupDeviceMenu(0)' }); }
|
||||
|
||||
@ -3398,6 +3470,13 @@
|
||||
(((currentNode.agent == null) && ((typeof currentNode.intelamt.sku !== 'number') || ((currentNode.intelamt.sku & 8) != 0))) || (currentNode.agent && (currentNode.agent.caps & 1)))
|
||||
) { menus.push({ n: "Desktop", f: 'setupDeviceMenu(1)' }); }
|
||||
|
||||
if ((currentDevicePanel != 5) &&
|
||||
(urlargs.term == 1) &&
|
||||
(currentNode != null) &&
|
||||
((meshrights & 8) || (meshrights & 256)) && ((meshrights == 0xFFFFFFFF) || ((meshrights & 65536) == 0)) &&
|
||||
(((currentNode.agent == null) && ((typeof currentNode.intelamt.sku !== 'number') || ((currentNode.intelamt.sku & 8) != 0))) || (currentNode.agent && (currentNode.agent.caps & 2)))
|
||||
) { menus.push({ n: "Terminal", f: 'setupDeviceMenu(5)' }); }
|
||||
|
||||
if ((currentDevicePanel != 2) && (currentNode != null) && (meshrights & 8) && ((meshrights == 0xFFFFFFFF) || ((meshrights & 1024) == 0)) && ((currentNode.mtype == 2) && (currentNode.agent.caps & 4))) { menus.push({ n: "Files", f: 'setupDeviceMenu(2)' }); }
|
||||
if ((currentDevicePanel != 3) && (currentNode != null)) { menus.push({ n: "Details", f: 'setupDeviceMenu(3)' }); }
|
||||
if ((currentDevicePanel != 4) && (currentNode != null) && (meshrights & 0x00000010)) { menus.push({ n: "Console", f: 'setupDeviceMenu(4)' }); }
|
||||
@ -3766,6 +3845,7 @@
|
||||
}
|
||||
|
||||
function p11clearConsoleMsg() { QH('p11DeskConsoleMsg', ''); QV('p11DeskConsoleMsg', false); if (p11DeskConsoleMsgTimer) { clearTimeout(p11DeskConsoleMsgTimer); p11DeskConsoleMsgTimer = null; } }
|
||||
function p12clearConsoleMsg() { QH('p12TermConsoleMsg', ''); QV('p12TermConsoleMsg', false); if (p12TermConsoleMsgTimer) { clearTimeout(p12TermConsoleMsgTimer); p12TermConsoleMsgTimer = null; } }
|
||||
function p13clearConsoleMsg() { QH('p13FilesConsoleMsg', ''); QV('p13FilesConsoleMsg', false); if (p13FilesConsoleMsgTimer) { clearTimeout(p13FilesConsoleMsgTimer); p13FilesConsoleMsgTimer = null; } }
|
||||
|
||||
function onDesktopStateChange(xdesktop, state) {
|
||||
@ -4201,6 +4281,164 @@
|
||||
function dmousewheel(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null) && desktop.m.mousewheel) { if (fullscreen) { e.addx = Q('p10desktop').scrollLeft * (1 / fullscreenzoom); e.addy = Q('p10desktop').scrollTop * (1 / fullscreenzoom); } desktop.m.mousewheel(e); haltEvent(e); return true; } return false; }
|
||||
function drotate(x) { if (!xxdialogMode && desktop != null) { desktop.m.setRotation(desktop.m.rotation + x); deskAdjust(); } }
|
||||
|
||||
|
||||
//
|
||||
// TERMINAL
|
||||
//
|
||||
|
||||
var terminalNode;
|
||||
function setupTerminal() {
|
||||
// Setup the terminal
|
||||
if ((terminalNode != currentNode) && (terminal != null)) { terminal.Stop(); terminal = null; }
|
||||
terminalNode = currentNode;
|
||||
updateTerminalButtons();
|
||||
}
|
||||
|
||||
// Show and enable the right buttons
|
||||
function updateTerminalButtons() {
|
||||
var mtype = (currentNode.agent == 1) ? 1 : 2;
|
||||
var termState = ((terminal != null) && (terminal.state != 0));
|
||||
|
||||
// Show the right buttons
|
||||
QV('disconnectbutton2span', (termState == true));
|
||||
QV('connectbutton2span', (termState == false) && (currentNode.agent != null) && (currentNode.agent.caps & 2));
|
||||
|
||||
// Enable buttons
|
||||
var online = ((terminalNode.conn & 1) != 0); // If Agent (1) connected, enable Terminal
|
||||
QE('connectbutton2', online);
|
||||
}
|
||||
|
||||
// Called when the terminal state changes
|
||||
function onTerminalStateChange(xterminal, state) {
|
||||
var xstate = state;
|
||||
if ((xstate == 3) && (xterminal.contype == 2)) { xstate++; }
|
||||
var str = StatusStrs[xstate];
|
||||
if (terminal.webRtcActive == true) { str += ", WebRTC"; }
|
||||
QH('termstatus', str);
|
||||
switch (state) {
|
||||
case 0:
|
||||
// Disconnected, clear the terminal
|
||||
QH('termtitle', '');
|
||||
xterm.dispose();
|
||||
xterm = xtermfit = null;
|
||||
if (terminal != null) { terminal.Stop(); terminal = null; }
|
||||
break;
|
||||
case 3:
|
||||
xterm.focus();
|
||||
break;
|
||||
default:
|
||||
//console.log('Unhandled onTerminalStateChange state', state);
|
||||
break;
|
||||
}
|
||||
updateTerminalButtons();
|
||||
}
|
||||
|
||||
// Handles a tunnel to a remote shell
|
||||
function CreateRemoteTunnel(onTunnelUpdate, options) {
|
||||
var obj = { protocol: 1 };
|
||||
if ((options != null) && (typeof options.protocol == 'number')) { obj.protocol = options.protocol; }
|
||||
obj.onTunnelUpdate = onTunnelUpdate;
|
||||
obj.xxStateChange = function (state) { }
|
||||
obj.ProcessBinaryData = function (data) { obj.onTunnelUpdate(data); }
|
||||
obj.ProcessData = function (data) { obj.onTunnelUpdate(data); }
|
||||
obj.terminalEmulation = 1;
|
||||
obj.fxEmulation = 0;
|
||||
obj.lineFeed = '\r\n';
|
||||
return obj;
|
||||
}
|
||||
|
||||
function tunnelUpdate(data) { if (typeof data == 'string') { xterm.writeUtf8(data); } else { xterm.writeUtf8(new Uint8Array(data)); } }
|
||||
|
||||
// Send the new terminal size to the agent
|
||||
function xTermSendResize() {
|
||||
xtermResizeTimer = null;
|
||||
if ((xterm != null) && (terminal != null) && (terminal.sendCtrlMsg != null)) { terminal.sendCtrlMsg(JSON.stringify({ ctrlChannel: '102938', type: 'termsize', cols: xterm.cols, rows: xterm.rows })); }
|
||||
}
|
||||
|
||||
function connectTerminal(e, contype, options) {
|
||||
p12clearConsoleMsg();
|
||||
if (!terminal) {
|
||||
// Terminal setup
|
||||
var termoptions = { protocol: ((options != null) && (typeof options.protocol == 'number')) ? options.protocol : 1 };
|
||||
if (options && options.requireLogin) { termoptions.requireLogin = true; }
|
||||
/*
|
||||
if ([1, 2, 3, 4, 21, 22].indexOf(currentNode.agent.id) == -1) {
|
||||
if (Q('termSizeList').value == 1) { termoptions.cols = 80; termoptions.rows = 25; termoptions.xterm = true; }
|
||||
else if (Q('termSizeList').value == 2) { termoptions.cols = 100; termoptions.rows = 30; termoptions.xterm = true; }
|
||||
else if (Q('termSizeList').value == 3) {
|
||||
// TODO: Try to improve terminal auto-size.
|
||||
termoptions.cols = Math.floor((Q('column_l').clientWidth - 60) / 10);
|
||||
termoptions.rows = Math.floor((Q('column_l').clientHeight - 120) / 20);
|
||||
termoptions.xterm = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If shift is pressed
|
||||
if ((e && (e.shiftKey == true))) {
|
||||
if (currentNode.agent.id > 4) {
|
||||
if (termoptions.protocol == 1) { termoptions.protocol = 7; } // Switch to user shell
|
||||
} else {
|
||||
if (termoptions.protocol == 1) { termoptions.protocol = 6; } // Switch to Powershell
|
||||
}
|
||||
}
|
||||
|
||||
// If the server requires a shell type
|
||||
if ((serverinfo.linuxshell) != null && (currentNode.agent.id > 4)) {
|
||||
if (serverinfo.linuxshell == 'root') { termoptions.protocol = 1; delete termoptions.requireLogin; }
|
||||
if (serverinfo.linuxshell == 'user') { termoptions.protocol = 8; delete termoptions.requireLogin; }
|
||||
if (serverinfo.linuxshell == 'login') { termoptions.protocol = 1; termoptions.requireLogin = true; }
|
||||
}
|
||||
*/
|
||||
// Setup a mesh agent xterm terminal
|
||||
QV('termarea3xdiv', true);
|
||||
QV('Term', false);
|
||||
|
||||
// Setup the terminal with auto-fit
|
||||
if (xterm != null) { xterm.dispose(); }
|
||||
xtermfit = new FitAddon.FitAddon();
|
||||
xterm = new Terminal();
|
||||
if (xtermfit) { xterm.loadAddon(xtermfit); }
|
||||
xterm.open(Q('termarea3xdiv')); // termarea3x
|
||||
xterm.onData(function (data) { if (terminal != null) { terminal.sendText(data); } })
|
||||
if (xtermfit) { xtermfit.fit(); }
|
||||
xterm.onTitleChange(function (title) { QH('termtitle', ' - ' + EscapeHtml(title)); });
|
||||
xterm.onResize(function (size) {
|
||||
// Despam resize
|
||||
if (xtermResizeTimer) clearTimeout(xtermResizeTimer);
|
||||
xtermResizeTimer = setTimeout(xTermSendResize, 200);
|
||||
});
|
||||
|
||||
// Setup a terminal tunnel to the agent
|
||||
terminal = CreateAgentRedirect(meshserver, CreateRemoteTunnel(tunnelUpdate, termoptions), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
|
||||
terminal.debugmode = debugmode;
|
||||
terminal.m.debugmode = debugmode;
|
||||
terminal.options = termoptions;
|
||||
terminal.options = { cols: xterm.cols, rows: xterm.rows };
|
||||
if (termoptions.requireLogin) { terminal.options.requireLogin = true; }
|
||||
terminal.Start(terminalNode._id);
|
||||
terminal.onStateChanged = onTerminalStateChange;
|
||||
terminal.contype = 1;
|
||||
terminal.attemptWebRTC = false; // Never do WebRTC on terminal, because of a race condition we can't do it.
|
||||
terminal.onConsoleMessageChange = function (server, msg) {
|
||||
if (terminal.consoleMessage) {
|
||||
Q('p12TermConsoleMsg').innerHTML += formatAgentConsoleMessage(terminal.consoleMessage, terminal.consoleMessageId, terminal.consoleMessageArgs);
|
||||
QV('p12TermConsoleMsg', true);
|
||||
if (p12TermConsoleMsgTimer != null) { clearTimeout(p12TermConsoleMsgTimer); }
|
||||
if (terminal.consoleMessageTimeout) { p12TermConsoleMsgTimer = setTimeout(p12clearConsoleMsg, terminal.consoleMessageTimeout * 1000); }
|
||||
} else {
|
||||
p12clearConsoleMsg();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
//QH('Term', '');
|
||||
terminal.Stop();
|
||||
terminal = null;
|
||||
if (fullscreen) { deskToggleFull(); }
|
||||
}
|
||||
Q('connectbutton2').blur(); // Deselect the connect button so the button does not get key presses.
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FILES
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user