mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-11-23 06:34:54 +03:00
XTerm improvements.
This commit is contained in:
parent
04a8804ff1
commit
58029d3b16
@ -1212,11 +1212,15 @@ function createMeshCore(agent) {
|
|||||||
|
|
||||||
var python = fs.existsSync('/usr/bin/python') ? '/usr/bin/python' : false;
|
var python = fs.existsSync('/usr/bin/python') ? '/usr/bin/python' : false;
|
||||||
var shell = bash || sh;
|
var shell = bash || sh;
|
||||||
|
var env = { HISTCONTROL: 'ignoreboth', TERM: 'xterm' }; // LINES: '100', COLUMNS: '100'
|
||||||
var options = { uid: (this.httprequest.protocol == 8) ? require('user-sessions').consoleUid() : null, env: { HISTCONTROL: 'ignoreboth', TERM: 'xterm' } };
|
if (this.httprequest.xoptions) {
|
||||||
var setupcommands = 'alias ls=\'ls --color=auto\'\n';
|
if (this.httprequest.xoptions.rows) { env.LINES = ('' + this.httprequest.xoptions.rows); }
|
||||||
if (shell == sh) setupcommands += 'stty erase ^H\n';
|
if (this.httprequest.xoptions.cols) { env.COLUMNS = ('' + this.httprequest.xoptions.cols); }
|
||||||
setupcommands += 'clear\n';
|
}
|
||||||
|
var options = { uid: (this.httprequest.protocol == 8) ? require('user-sessions').consoleUid() : null, env: env };
|
||||||
|
var setupcommands = ' alias ls=\'ls --color=auto\'\n';
|
||||||
|
if (shell == sh) setupcommands += ' stty erase ^H\n';
|
||||||
|
setupcommands += ' clear\n';
|
||||||
|
|
||||||
if (script && shell && process.platform == 'linux') {
|
if (script && shell && process.platform == 'linux') {
|
||||||
this.httprequest.process = childProcess.execFile(script, ['script', '--return', '--quiet', '-c', '"' + shell + '"', '/dev/null'], options); // Start as active user
|
this.httprequest.process = childProcess.execFile(script, ['script', '--return', '--quiet', '-c', '"' + shell + '"', '/dev/null'], options); // Start as active user
|
||||||
@ -1760,22 +1764,41 @@ function createMeshCore(agent) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.type == 'options') {
|
switch (obj.type) {
|
||||||
|
case 'options': {
|
||||||
// These are additional connection options passed in the control channel.
|
// These are additional connection options passed in the control channel.
|
||||||
//sendConsoleText('options: ' + JSON.stringify(obj));
|
//sendConsoleText('options: ' + JSON.stringify(obj));
|
||||||
delete obj.type;
|
delete obj.type;
|
||||||
ws.httprequest.xoptions = obj;
|
ws.httprequest.xoptions = obj;
|
||||||
} else if (obj.type == 'close') {
|
break;
|
||||||
|
}
|
||||||
|
case 'close': {
|
||||||
// We received the close on the websocket
|
// We received the close on the websocket
|
||||||
//sendConsoleText('Tunnel #' + ws.tunnel.index + ' WebSocket control close');
|
//sendConsoleText('Tunnel #' + ws.tunnel.index + ' WebSocket control close');
|
||||||
try { ws.close(); } catch (e) { }
|
try { ws.close(); } catch (e) { }
|
||||||
} else if (obj.type == 'webrtc0') { // Browser indicates we can start WebRTC switch-over.
|
break;
|
||||||
|
}
|
||||||
|
case 'termsize': {
|
||||||
|
if (ws.httprequest.protocol == 1) { // Terminal
|
||||||
|
// Indicates a change in terminal size
|
||||||
|
if (process.platform == 'win32') {
|
||||||
|
if (ws.httprequest._term == null) return;
|
||||||
|
//sendConsoleText('Win32-TermSize: ' + obj.cols + 'x' + obj.rows);
|
||||||
|
// TODO
|
||||||
|
} else {
|
||||||
|
if (ws.httprequest.process == null) return;
|
||||||
|
//sendConsoleText('Linux-TermSize: ' + obj.cols + 'x' + obj.rows);
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'webrtc0': { // Browser indicates we can start WebRTC switch-over.
|
||||||
if (ws.httprequest.protocol == 1) { // Terminal
|
if (ws.httprequest.protocol == 1) { // Terminal
|
||||||
// This is a terminal data stream, unpipe the terminal now and indicate to the other side that terminal data will no longer be received over WebSocket
|
// This is a terminal data stream, unpipe the terminal now and indicate to the other side that terminal data will no longer be received over WebSocket
|
||||||
if (process.platform == 'win32') {
|
if (process.platform == 'win32') {
|
||||||
ws.httprequest._term.unpipe(ws);
|
ws.httprequest._term.unpipe(ws);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ws.httprequest.process.stdout.unpipe(ws);
|
ws.httprequest.process.stdout.unpipe(ws);
|
||||||
ws.httprequest.process.stderr.unpipe(ws);
|
ws.httprequest.process.stderr.unpipe(ws);
|
||||||
}
|
}
|
||||||
@ -1789,14 +1812,15 @@ function createMeshCore(agent) {
|
|||||||
ws.rtcchannel.on('data', onTunnelData);
|
ws.rtcchannel.on('data', onTunnelData);
|
||||||
}
|
}
|
||||||
ws.write("{\"ctrlChannel\":\"102938\",\"type\":\"webrtc1\"}"); // End of data marker
|
ws.write("{\"ctrlChannel\":\"102938\",\"type\":\"webrtc1\"}"); // End of data marker
|
||||||
} else if (obj.type == 'webrtc1') {
|
break;
|
||||||
|
}
|
||||||
|
case 'webrtc1': {
|
||||||
if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) { // Terminal
|
if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) { // Terminal
|
||||||
// Switch the user input from websocket to webrtc at this point.
|
// Switch the user input from websocket to webrtc at this point.
|
||||||
if (process.platform == 'win32') {
|
if (process.platform == 'win32') {
|
||||||
ws.unpipe(ws.httprequest._term);
|
ws.unpipe(ws.httprequest._term);
|
||||||
ws.rtcchannel.pipe(ws.httprequest._term, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
ws.rtcchannel.pipe(ws.httprequest._term, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ws.unpipe(ws.httprequest.process.stdin);
|
ws.unpipe(ws.httprequest.process.stdin);
|
||||||
ws.rtcchannel.pipe(ws.httprequest.process.stdin, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
ws.rtcchannel.pipe(ws.httprequest.process.stdin, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
||||||
}
|
}
|
||||||
@ -1808,20 +1832,23 @@ function createMeshCore(agent) {
|
|||||||
ws.resume(); // Resume the websocket to keep receiving control data
|
ws.resume(); // Resume the websocket to keep receiving control data
|
||||||
}
|
}
|
||||||
ws.write('{\"ctrlChannel\":\"102938\",\"type\":\"webrtc2\"}'); // Indicates we will no longer get any data on websocket, switching to WebRTC at this point.
|
ws.write('{\"ctrlChannel\":\"102938\",\"type\":\"webrtc2\"}'); // Indicates we will no longer get any data on websocket, switching to WebRTC at this point.
|
||||||
} else if (obj.type == 'webrtc2') {
|
break;
|
||||||
|
}
|
||||||
|
case 'webrtc2': {
|
||||||
// Other side received websocket end of data marker, start sending data on WebRTC channel
|
// Other side received websocket end of data marker, start sending data on WebRTC channel
|
||||||
if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) { // Terminal
|
if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) { // Terminal
|
||||||
if (process.platform == 'win32') {
|
if (process.platform == 'win32') {
|
||||||
ws.httprequest._term.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
ws.httprequest._term.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ws.httprequest.process.stdout.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
ws.httprequest.process.stdout.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||||
ws.httprequest.process.stderr.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
ws.httprequest.process.stderr.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||||
}
|
}
|
||||||
} else if (ws.httprequest.protocol == 2) { // Desktop
|
} else if (ws.httprequest.protocol == 2) { // Desktop
|
||||||
ws.httprequest.desktop.kvm.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
ws.httprequest.desktop.kvm.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
||||||
}
|
}
|
||||||
} else if (obj.type == 'offer') {
|
break;
|
||||||
|
}
|
||||||
|
case 'offer': {
|
||||||
// This is a WebRTC offer.
|
// This is a WebRTC offer.
|
||||||
if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) return; // TODO: Terminal is currently broken with WebRTC. Reject WebRTC upgrade for now.
|
if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) return; // TODO: Terminal is currently broken with WebRTC. Reject WebRTC upgrade for now.
|
||||||
ws.webrtc = rtc.createConnection();
|
ws.webrtc = rtc.createConnection();
|
||||||
@ -1848,6 +1875,8 @@ function createMeshCore(agent) {
|
|||||||
var sdp = null;
|
var sdp = null;
|
||||||
try { sdp = ws.webrtc.setOffer(obj.sdp); } catch (ex) { }
|
try { sdp = ws.webrtc.setOffer(obj.sdp); } catch (ex) { }
|
||||||
if (sdp != null) { ws.write({ type: 'answer', ctrlChannel: '102938', sdp: sdp }); }
|
if (sdp != null) { ws.write({ type: 'answer', ctrlChannel: '102938', sdp: sdp }); }
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "meshcentral",
|
"name": "meshcentral",
|
||||||
"version": "0.4.7-s",
|
"version": "0.4.7-t",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"Remote Management",
|
"Remote Management",
|
||||||
"Intel AMT",
|
"Intel AMT",
|
||||||
|
@ -34,8 +34,8 @@ function IntToStrX(v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF, (v
|
|||||||
function MakeToArray(v) { if (!v || v == null || typeof v == 'object') return v; return [v]; }
|
function MakeToArray(v) { if (!v || v == null || typeof v == 'object') return v; return [v]; }
|
||||||
function SplitArray(v) { return v.split(','); }
|
function SplitArray(v) { return v.split(','); }
|
||||||
function Clone(v) { return JSON.parse(JSON.stringify(v)); }
|
function Clone(v) { return JSON.parse(JSON.stringify(v)); }
|
||||||
function EscapeHtml(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, '''); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
|
function EscapeHtml(x) { if (typeof x == 'string') return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, '''); if (typeof x == 'boolean') return x; if (typeof x == 'number') return x; }
|
||||||
function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, ''').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, ' '); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
|
function EscapeHtmlBreaks(x) { if (typeof x == 'string') return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, ''').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, ' '); if (typeof x == 'boolean') return x; if (typeof x == 'number') return x; }
|
||||||
|
|
||||||
// Move an element from one position in an array to a new position
|
// Move an element from one position in an array to a new position
|
||||||
function ArrayElementMove(arr, from, to) { arr.splice(to, 0, arr.splice(from, 1)[0]); };
|
function ArrayElementMove(arr, from, to) { arr.splice(to, 0, arr.splice(from, 1)[0]); };
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body style="overflow:hidden;background-color:black">
|
<body style="overflow:hidden;background-color:black">
|
||||||
<div id=p11 class="noselect" style="overflow:hidden">
|
<div id=p11 class="noselect" style="overflow:hidden">
|
||||||
<div id=deskarea0>
|
<div id=deskarea0 style="position:relative">
|
||||||
<div id=deskarea1 class="areaHead">
|
<div id=deskarea1 class="areaHead">
|
||||||
<div class="toright2">
|
<div class="toright2">
|
||||||
</div>
|
</div>
|
||||||
@ -36,7 +36,7 @@
|
|||||||
<div id="bigfail" style="display:none;left:calc((100vh / 2))"><b>✗</b></div>
|
<div id="bigfail" style="display:none;left:calc((100vh / 2))"><b>✗</b></div>
|
||||||
<div id="metadatadiv" style="padding:20px;color:lightgrey;text-align:left;display:none"></div>
|
<div id="metadatadiv" style="padding:20px;color:lightgrey;text-align:left;display:none"></div>
|
||||||
<div id=terminal style="max-height:calc(100vh - 54px);height:calc(100vh - 54px);"></div>
|
<div id=terminal style="max-height:calc(100vh - 54px);height:calc(100vh - 54px);"></div>
|
||||||
<div id=p11DeskConsoleMsg style="display:none;cursor:pointer;position:absolute;left:30px;top:17px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=clearConsoleMsg()></div>
|
<div id=TermConsoleMsg style="cursor:pointer;z-index:10;position:absolute;left:30px;top:17px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=clearConsoleMsg()></div>
|
||||||
</div>
|
</div>
|
||||||
<div id=deskarea4 class="areaHead">
|
<div id=deskarea4 class="areaHead">
|
||||||
<div class="toright2">
|
<div class="toright2">
|
||||||
@ -75,6 +75,7 @@
|
|||||||
var authRelayCookie = '{{{authRelayCookie}}}';
|
var authRelayCookie = '{{{authRelayCookie}}}';
|
||||||
var serverPublicNamePort = '{{{serverDnsName}}}:{{{serverPublicPort}}}';
|
var serverPublicNamePort = '{{{serverDnsName}}}:{{{serverPublicPort}}}';
|
||||||
var StatusStrs = ["Disconnected", "Connecting...", "Setup...", "Connected", "Intel® AMT Connected"];
|
var StatusStrs = ["Disconnected", "Connecting...", "Setup...", "Connected", "Intel® AMT Connected"];
|
||||||
|
var resizeTimer = null;
|
||||||
|
|
||||||
function start() {
|
function start() {
|
||||||
// Parse any URL arguments
|
// Parse any URL arguments
|
||||||
@ -123,6 +124,12 @@
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send the new terminal size to the agent
|
||||||
|
function sendResize() {
|
||||||
|
resizeTimer = null;
|
||||||
|
if ((term != null) && (tunnel != null)) { tunnel.sendCtrlMsg(JSON.stringify({ ctrlChannel: '102938', type: 'termsize', cols: term.cols, rows: term.rows })); }
|
||||||
|
}
|
||||||
|
|
||||||
// Called when the connect/disconnect button is pressed
|
// Called when the connect/disconnect button is pressed
|
||||||
function connectButton() {
|
function connectButton() {
|
||||||
if (!tunnel) {
|
if (!tunnel) {
|
||||||
@ -133,17 +140,15 @@
|
|||||||
if (termfit) { term.loadAddon(termfit); }
|
if (termfit) { term.loadAddon(termfit); }
|
||||||
term.open(Q('terminal'));
|
term.open(Q('terminal'));
|
||||||
term.onData(function (data) { if (tunnel != null) { tunnel.sendText(data); } })
|
term.onData(function (data) { if (tunnel != null) { tunnel.sendText(data); } })
|
||||||
term.onResize(function (size) {
|
term.onResize(function (size) { if (resizeTimer == null) { resizeTimer = setTimeout(sendResize, 200); } });
|
||||||
//console.log('Resize', size);
|
|
||||||
//term.resize(size.cols, size.rows);
|
|
||||||
//if (tunnel != null) { tunnel.send(String.fromCharCode(27) + '[8;' + size.cols + ';' + size.rows + 't') }
|
|
||||||
});
|
|
||||||
if (termfit) { termfit.fit(); }
|
if (termfit) { termfit.fit(); }
|
||||||
|
|
||||||
// Setup a terminal tunnel to the agent
|
// Setup a terminal tunnel to the agent
|
||||||
tunnel = CreateAgentRedirect(meshserver, CreateRemoteTunnel(tunnelUpdate), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
|
tunnel = CreateAgentRedirect(meshserver, CreateRemoteTunnel(tunnelUpdate), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
|
||||||
|
tunnel.options = { cols: term.cols, rows: term.rows };
|
||||||
tunnel.Start(args.nodeid);
|
tunnel.Start(args.nodeid);
|
||||||
tunnel.onStateChanged = onTunnelStateChange;
|
tunnel.onStateChanged = onTunnelStateChange;
|
||||||
|
tunnel.onConsoleMessageChange = function (server, msg) { setConsoleMsg(msg); };
|
||||||
} else {
|
} else {
|
||||||
tunnel.Stop();
|
tunnel.Stop();
|
||||||
}
|
}
|
||||||
@ -162,9 +167,7 @@
|
|||||||
case 0:
|
case 0:
|
||||||
// Disconnected, clear the terminal
|
// Disconnected, clear the terminal
|
||||||
term.dispose();
|
term.dispose();
|
||||||
term = null;
|
term = termfit = tunnel = null;
|
||||||
termfit = null;
|
|
||||||
tunnel = null;
|
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
// Connected
|
// Connected
|
||||||
@ -177,6 +180,11 @@
|
|||||||
updateButtons();
|
updateButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Console messages
|
||||||
|
var termConsoleMsgTimer = null;
|
||||||
|
function clearConsoleMsg() { QV('TermConsoleMsg', false); if (termConsoleMsgTimer) { clearTimeout(termConsoleMsgTimer); termConsoleMsgTimer = null; } }
|
||||||
|
function setConsoleMsg(msg) { QH('TermConsoleMsg', EscapeHtml(msg).split('\n').join('<br />')); QV('TermConsoleMsg', true); termConsoleMsgTimer = setTimeout(clearConsoleMsg, 8000); }
|
||||||
|
|
||||||
//
|
//
|
||||||
// POPUP DIALOG
|
// POPUP DIALOG
|
||||||
//
|
//
|
||||||
|
Loading…
Reference in New Issue
Block a user