Updated User-Consent and Notification flow for Terminal

Bryan Roe committed May 16, 2020 at 21:10 UTC 1e6b3be3e2bbae59bff2568fe0fcbdef0b102646
1 file changed +205 -177
agents/meshcore.js
+205 -177
@@ -1134,14 +1134,21 @@ function createMeshCore(agent) {
1134 if (this.httprequest.state == 0) {
1135 // Check if this is a relay connection
1136 if ((data == 'c') || (data == 'cr')) { this.httprequest.state = 1; /*sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid);*/ }
1137 - } else {
1137 + }
1138 + else
1139 + {
1140 // Handle tunnel data
1141 if (this.httprequest.protocol == 0) { // 1 = Terminal (admin), 2 = Desktop, 5 = Files, 6 = PowerShell (admin), 7 = Plugin Data Exchange, 8 = Terminal (user), 9 = PowerShell (user)
1142 // Take a look at the protocol
1143 if ((data.length > 3) && (data[0] == '{')) { onTunnelControlData(data, this); return; }
1144 this.httprequest.protocol = parseInt(data);
1145 if (typeof this.httprequest.protocol != 'number') { this.httprequest.protocol = 0; }
1144 - if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6) || (this.httprequest.protocol == 8) || (this.httprequest.protocol == 9)) {
1146 + if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6) || (this.httprequest.protocol == 8) || (this.httprequest.protocol == 9))
1147 + {
1148 + //
1149 + // Remote Terminal
1150 + //
1151 +
1152 // Check user access rights for terminal
1153 if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOTERMINAL) != 0))) {
1154 // Disengage this tunnel, user does not have the rights to do this!!
@@ -1151,23 +1158,40 @@ function createMeshCore(agent) {
1158 return;
1159 }
1160
1161 + if (process.platform == 'win32')
1162 + {
1163 + if (!require('win-terminal').PowerShellCapable() && (this.httprequest.protocol == 6 || this.httprequest.protocol == 9))
1164 + {
1165 + this.httprequest.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'PowerShell is not supported on this version of windows', msgid: 1 }));
1166 + this.httprequest.s.end();
1167 + return;
1168 + }
1169 + }
1170 +
1171 var prom = require('promise');
1172 this.httprequest.tpromise = new prom(function (res, rej) { this._res = res; this._rej = rej; });
1173 + this.httprequest.tpromise.that = this;
1174 + this.httprequest.tpromise.httprequest = this.httprequest;
1175
1157 - this.end = function () {
1176 + this.end = function ()
1177 + {
1178 + if (this.httprequest.tpromise._consent) { this.httprequest.tpromise._consent.close(); }
1179 // Remove the terminal session to the count to update the server
1159 - if (this.httprequest.userid != null) {
1180 + if (this.httprequest.userid != null)
1181 + {
1182 if (tunnelUserCount.terminal[this.httprequest.userid] != null) { tunnelUserCount.terminal[this.httprequest.userid]--; if (tunnelUserCount.terminal[this.httprequest.userid] <= 0) { delete tunnelUserCount.terminal[this.httprequest.userid]; } }
1183 try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (ex) { }
1184 }
1185
1164 - if (process.platform == 'win32') {
1186 + if (process.platform == 'win32')
1187 + {
1188 // Unpipe the web socket
1189 this.unpipe(this.httprequest._term);
1190 if (this.httprequest._term) { this.httprequest._term.unpipe(this); }
1191
1192 // Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends).
1170 - if (this.rtcchannel) {
1193 + if (this.rtcchannel)
1194 + {
1195 this.rtcchannel.unpipe(this.httprequest._term);
1196 if (this.httprequest._term) { this.httprequest._term.unpipe(this.rtcchannel); }
1197 }
@@ -1175,219 +1199,223 @@ function createMeshCore(agent) {
1199 // Clean up
1200 if (this.httprequest._term) { this.httprequest._term.end(); }
1201 this.httprequest._term = null;
1178 - } else {
1179 - // TODO!!
1202 }
1203 };
1204
1183 - // Remote terminal using native pipes
1184 - if (process.platform == 'win32')
1205 + // Perform User-Consent if needed.
1206 + if (this.httprequest.consent && (this.httprequest.consent & 16))
1207 {
1186 - try
1187 - {
1188 - var cols = 80, rows = 25;
1189 - if (this.httprequest.xoptions)
1208 + this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
1209 + this.httprequest.tpromise._consent = require('message-box').create('MeshCentral', this.httprequest.username + " requesting Terminal Access. Grant access?", 30);
1210 + this.httprequest.tpromise._consent.retPromise = this.httprequest.tpromise;
1211 + this.httprequest.tpromise._consent.then(
1212 + function ()
1213 {
1191 - if (this.httprequest.xoptions.rows) { rows = this.httprequest.xoptions.rows; }
1192 - if (this.httprequest.xoptions.cols) { cols = this.httprequest.xoptions.cols; }
1193 - }
1194 -
1195 - if (!require('win-terminal').PowerShellCapable() && (this.httprequest.protocol == 6 || this.httprequest.protocol == 9)) { throw ('PowerShell is not supported on this version of windows'); }
1196 - if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6))
1214 + // Success
1215 + MeshServerLog("Local user accepted remote terminal request (" + this.retPromise.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
1216 + this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
1217 + this.retPromise._consent = null;
1218 + this.retPromise._res();
1219 + },
1220 + function (e)
1221 {
1198 - // Admin Terminal
1199 - if (require('win-virtual-terminal').supported)
1200 - {
1201 - // ConPTY PseudoTerminal
1202 - // this.httprequest._term = require('win-virtual-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](80, 25);
1222 + // Denied
1223 + MeshServerLog("Local user rejected remote terminal request (" + this.retPromise.that.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
1224 + this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1225 + this.retPromise._rej(e.toString());
1226 + });
1227 + }
1228 + else
1229 + {
1230 + // User-Consent is not required, so just resolve this promise
1231 + this.httprequest.tpromise._res();
1232 + }
1233
1204 - // The above line is commented out, because there is a bug with ClosePseudoConsole() API, so this is the workaround
1205 - this.httprequest._dispatcher = require('win-dispatcher').dispatch({ modules: [{ name: 'win-virtual-terminal', script: getJSModule('win-virtual-terminal') }], launch: { module: 'win-virtual-terminal', method: (this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } });
1206 - this.httprequest._dispatcher.ws = this;
1207 - this.httprequest._dispatcher.on('connection', function (c)
1208 - {
1209 - this.ws._term = c;
1210 - c.pipe(this.ws, { dataTypeSkip: 1 });
1211 - this.ws.pipe(c, { dataTypeSkip: 1 });
1212 - this.ws.httprequest.tpromise._res();
1213 - });
1214 - }
1215 - else
1216 - {
1217 - // Legacy Terminal
1218 - this.httprequest._term = require('win-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](cols, rows);
1219 - this.httprequest.tpromise._res(this.httprequest._term);
1220 - }
1221 - }
1222 - else
1234 +
1235 + this.httprequest.tpromise.then(
1236 + function ()
1237 + {
1238 + this.httprequest.connectionPromise = new prom(function (res, rej) { this._res = res; this._rej = rej; });
1239 + this.httprequest.connectionPromise.ws = this.that;
1240 +
1241 + // Start Terminal
1242 + if(process.platform == 'win32')
1243 {
1224 - // Logged in user
1225 - var userPromise = require('user-sessions').enumerateUsers();
1226 - userPromise.that = this;
1227 - userPromise.then(function (u)
1244 + try
1245 {
1229 - var that = this.that;
1230 - if (u.Active.length > 0)
1246 + var cols = 80, rows = 25;
1247 + if (this.httprequest.xoptions)
1248 + {
1249 + if (this.httprequest.xoptions.rows) { rows = this.httprequest.xoptions.rows; }
1250 + if (this.httprequest.xoptions.cols) { cols = this.httprequest.xoptions.cols; }
1251 + }
1252 +
1253 + if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6))
1254 {
1232 - var username = u.Active[0].Username;
1255 + // Admin Terminal
1256 if (require('win-virtual-terminal').supported)
1257 {
1258 // ConPTY PseudoTerminal
1236 - that.httprequest._dispatcher = require('win-dispatcher').dispatch({ user: username, modules: [{ name: 'win-virtual-terminal', script: getJSModule('win-virtual-terminal') }], launch: { module: 'win-virtual-terminal', method: (that.httprequest.protocol == 9 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } });
1259 + // this.httprequest._term = require('win-virtual-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](80, 25);
1260 +
1261 + // The above line is commented out, because there is a bug with ClosePseudoConsole() API, so this is the workaround
1262 + this.httprequest._dispatcher = require('win-dispatcher').dispatch({ modules: [{ name: 'win-virtual-terminal', script: getJSModule('win-virtual-terminal') }], launch: { module: 'win-virtual-terminal', method: (this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } });
1263 + this.httprequest._dispatcher.httprequest = this.httprequest;
1264 + this.httprequest._dispatcher.on('connection', function (c)
1265 + {
1266 + this.httprequest.connectionPromise._res(c);
1267 + });
1268 }
1269 else
1270 {
1271 // Legacy Terminal
1241 - that.httprequest._dispatcher = require('win-dispatcher').dispatch({ user: username, modules: [{ name: 'win-terminal', script: getJSModule('win-terminal') }], launch: { module: 'win-terminal', method: (that.httprequest.protocol == 9 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } });
1272 + this.httprequest.connectionPromise._res(require('win-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](cols, rows));
1273 }
1243 - that.httprequest._dispatcher.ws = that;
1244 - that.httprequest._dispatcher.on('connection', function (c)
1274 + }
1275 + else
1276 + {
1277 + // Logged in user
1278 + var userPromise = require('user-sessions').enumerateUsers();
1279 + userPromise.that = this;
1280 + userPromise.then(function (u)
1281 {
1246 - this.ws._term = c;
1247 - c.pipe(this.ws, { dataTypeSkip: 1 });
1248 - this.ws.pipe(c, { dataTypeSkip: 1 });
1249 - this.ws.httprequest.tpromise._res();
1282 + var that = this.that;
1283 + if (u.Active.length > 0)
1284 + {
1285 + var username = u.Active[0].Username;
1286 + if (require('win-virtual-terminal').supported)
1287 + {
1288 + // ConPTY PseudoTerminal
1289 + that.httprequest._dispatcher = require('win-dispatcher').dispatch({ user: username, modules: [{ name: 'win-virtual-terminal', script: getJSModule('win-virtual-terminal') }], launch: { module: 'win-virtual-terminal', method: (that.httprequest.protocol == 9 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } });
1290 + }
1291 + else
1292 + {
1293 + // Legacy Terminal
1294 + that.httprequest._dispatcher = require('win-dispatcher').dispatch({ user: username, modules: [{ name: 'win-terminal', script: getJSModule('win-terminal') }], launch: { module: 'win-terminal', method: (that.httprequest.protocol == 9 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } });
1295 + }
1296 + that.httprequest._dispatcher.ws = that;
1297 + that.httprequest._dispatcher.on('connection', function (c)
1298 + {
1299 + this.ws.httprequest.connectionPromise._res(c);
1300 + });
1301 + }
1302 });
1303 }
1252 - });
1253 - }
1254 - } catch (e)
1255 - {
1256 - MeshServerLog('Failed to start remote terminal session, ' + e.toString() + ' (' + this.httprequest.remoteaddr + ')', this.httprequest);
1257 - this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2, msgargs: [e.toString(), this.httprequest.remoteaddr] }));
1258 - this.end();
1259 - return;
1260 - }
1261 - if (!this.httprequest._dispatcher)
1262 - {
1263 - this.httprequest._term.pipe(this, { dataTypeSkip: 1 });
1264 - this.pipe(this.httprequest._term, { dataTypeSkip: 1, end: false });
1265 - this.prependListener('end', function () { this.httprequest._term.end(function () { console.log("Terminal was closed"); }); });
1266 - this.httprequest.tpromise._res();
1267 - }
1268 - }
1269 - else
1270 - {
1271 - try
1272 - {
1273 - var bash = fs.existsSync('/bin/bash') ? '/bin/bash' : false;
1274 - var sh = fs.existsSync('/bin/sh') ? '/bin/sh' : false;
1275 - var login = process.platform == 'linux' ? '/bin/login' : '/usr/bin/login';
1276 -
1277 - var env = { HISTCONTROL: 'ignoreboth' };
1278 - if (this.httprequest.xoptions)
1279 - {
1280 - if (this.httprequest.xoptions.rows) { env.LINES = ('' + this.httprequest.xoptions.rows); }
1281 - if (this.httprequest.xoptions.cols) { env.COLUMNS = ('' + this.httprequest.xoptions.cols); }
1282 - }
1283 - var options = { type: childProcess.SpawnTypes.TERM, uid: (this.httprequest.protocol == 8) ? require('user-sessions').consoleUid() : null, env: env };
1284 - if (this.httprequest.xoptions && this.httprequest.xoptions.requireLogin)
1285 - {
1286 - if (!require('fs').existsSync(login)) { throw ('Unable to spawn login process'); }
1287 - this.httprequest.process = childProcess.execFile(login, ['login'], options); // Start login shell
1288 - }
1289 - else if (bash)
1290 - {
1291 - this.httprequest.process = childProcess.execFile(bash, ['bash'], options); // Start bash
1292 - // Spaces at the beginning of lines are needed to hide commands from the command history
1293 - if (process.platform == 'linux') { this.httprequest.process.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
1294 - }
1295 - else if (sh)
1296 - {
1297 - this.httprequest.process = childProcess.execFile(sh, ['sh'], options); // Start sh
1298 - // Spaces at the beginning of lines are needed to hide commands from the command history
1299 - if (process.platform == 'linux') { this.httprequest.process.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
1304 + }
1305 + catch (e)
1306 + {
1307 + this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString());
1308 + }
1309 }
1310 else
1311 {
1303 - MeshServerLog("Failed to start remote terminal session, no shell found");
1304 - this.httprequest.tpromise._rej()
1305 - return;
1312 + try
1313 + {
1314 + var bash = fs.existsSync('/bin/bash') ? '/bin/bash' : false;
1315 + var sh = fs.existsSync('/bin/sh') ? '/bin/sh' : false;
1316 + var login = process.platform == 'linux' ? '/bin/login' : '/usr/bin/login';
1317 +
1318 + var env = { HISTCONTROL: 'ignoreboth' };
1319 + if (this.httprequest.xoptions)
1320 + {
1321 + if (this.httprequest.xoptions.rows) { env.LINES = ('' + this.httprequest.xoptions.rows); }
1322 + if (this.httprequest.xoptions.cols) { env.COLUMNS = ('' + this.httprequest.xoptions.cols); }
1323 + }
1324 + var options = { type: childProcess.SpawnTypes.TERM, uid: (this.httprequest.protocol == 8) ? require('user-sessions').consoleUid() : null, env: env };
1325 + if (this.httprequest.xoptions && this.httprequest.xoptions.requireLogin)
1326 + {
1327 + if (!require('fs').existsSync(login)) { throw ('Unable to spawn login process'); }
1328 + this.httprequest.connectionPromise._res(childProcess.execFile(login, ['login'], options)); // Start login shell
1329 + }
1330 + else if (bash)
1331 + {
1332 + var p = childProcess.execFile(bash, ['bash'], options); // Start bash
1333 + // Spaces at the beginning of lines are needed to hide commands from the command history
1334 + if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
1335 + this.httprequest.connectionPromise._res(p);
1336 + }
1337 + else if (sh)
1338 + {
1339 + var p = childProcess.execFile(sh, ['sh'], options); // Start sh
1340 + // Spaces at the beginning of lines are needed to hide commands from the command history
1341 + if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
1342 + this.httprequest.connectionPromise._res(p);
1343 + }
1344 + else
1345 + {
1346 + this.httprequest.connectionPromise._rej('Failed to start remote terminal session, no shell found');
1347 + }
1348 + }
1349 + catch (e)
1350 + {
1351 + this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString());
1352 + }
1353 }
1307 - } catch (e)
1308 - {
1309 - MeshServerLog("Failed to start remote terminal session, " + e.toString() + ' (' + this.httprequest.remoteaddr + ')', this.httprequest);
1310 - this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString() }));
1311 - this.end();
1312 - this.httprequest.tpromise._rej();
1313 - return;
1314 - }
1354
1316 - this.httprequest.process.tunnel = this;
1317 - this.httprequest.process.on('exit', function (ecode, sig) { this.tunnel.end(); });
1318 - this.httprequest.process.stderr.on('data', function (chunk) { this.parent.tunnel.write(chunk); });
1319 - this.httprequest.process.stdout.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
1320 - this.pipe(this.httprequest.process.stdin, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
1321 - this.prependListener('end', function () { this.httprequest.process.kill(); });
1322 - this.httprequest.tpromise._res();
1323 - }
1355 + this.httprequest.connectionPromise.then(
1356 + function (term)
1357 + {
1358 + // SUCCESS
1359 + var stdoutstream;
1360 + var stdinstream;
1361 + if (process.platform == 'win32')
1362 + {
1363 + this.ws.httprequest._term = term;
1364 + this.ws.httprequest._term.tunnel = this.ws;
1365 + stdoutstream = stdinstream = term;
1366 + }
1367 + else
1368 + {
1369 + this.ws.httprequest.process = term;
1370 + this.ws.httprequest.process.tunnel = this.ws;
1371 + term.stderr.stdout = term.stdout;
1372 + term.stderr.on('data', function (c) { this.stdout.write(c); });
1373 + stdoutstream = term.stdout;
1374 + stdinstream = term.stdin;
1375 + this.ws.prependListener('end', function () { this.httprequest.process.kill(); });
1376 + term.prependListener('exit', function () { this.tunnel.end(); });
1377 + }
1378
1325 - // Add the terminal session to the count to update the server
1326 - if (this.httprequest.userid != null) {
1327 - if (tunnelUserCount.terminal[this.httprequest.userid] == null) { tunnelUserCount.terminal[this.httprequest.userid] = 1; } else { tunnelUserCount.terminal[this.httprequest.userid]++; }
1328 - try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (ex) { }
1329 - }
1379 + this.ws.removeAllListeners('data');
1380 + this.ws.on('data', onTunnelControlData);
1381
1331 - this.httprequest.tpromise.that = this;
1332 - this.httprequest.tpromise.then(function ()
1333 - {
1334 - var that = this.that;
1382 + stdoutstream.pipe(this.ws, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
1383 + this.ws.pipe(stdinstream, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
1384
1336 - // Perform notification if needed. Toast messages may not be supported on all platforms.
1337 - if (that.httprequest.consent && (that.httprequest.consent & 16))
1338 - {
1339 - // User Consent Prompt is required
1340 - // Send a console message back using the console channel, "\n" is supported.
1341 - that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
1342 - var pr = require('message-box').create('MeshCentral', that.httprequest.username + " requesting Terminal Access. Grant access?", 30);
1343 - pr.ws = that;
1344 - that.pause();
1345 - that._consentpromise = pr;
1346 - that.prependOnceListener('end', function () { if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); } });
1347 -
1348 - pr.then(
1349 - function ()
1350 - {
1351 - // Success
1352 - this.ws._consentpromise = null;
1353 - MeshServerLog("Starting remote terminal after local user accepted (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
1354 - this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
1385 + // Add the terminal session to the count to update the server
1386 + if (this.ws.httprequest.userid != null)
1387 + {
1388 + if (tunnelUserCount.terminal[this.ws.httprequest.userid] == null) { tunnelUserCount.terminal[this.ws.httprequest.userid] = 1; } else { tunnelUserCount.terminal[this.ws.httprequest.userid]++; }
1389 + try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (ex) { }
1390 + }
1391 +
1392 + // Toast Notification, if required
1393 if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 2))
1394 {
1395 // User Notifications is required
1396 try { require('toaster').Toast('MeshCentral', this.ws.httprequest.username + " started a remote terminal session."); } catch (ex) { }
1397 }
1360 - this.ws.resume();
1398 },
1399 function (e)
1400 {
1364 - // User Consent Denied/Failed
1365 - this.ws._consentpromise = null;
1366 - MeshServerLog("Failed to start remote terminal after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
1401 + // FAILED to connect terminal
1402 this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1403 this.ws.end();
1404 });
1370 - }
1371 - else
1405 + },
1406 + function (e)
1407 {
1373 - // User Consent Prompt is not required
1374 - if (that.httprequest.consent && (that.httprequest.consent & 2))
1375 - {
1376 - // User Notifications is required
1377 - MeshServerLog('Started remote terminal with toast notification (' + that.httprequest.remoteaddr + ')', that.httprequest);
1378 - try { require('toaster').Toast('MeshCentral', that.httprequest.username + ' started a remote terminal session.'); } catch (ex) { }
1379 - } else
1380 - {
1381 - MeshServerLog('Started remote terminal without notification (' + that.httprequest.remoteaddr + ')', that.httprequest);
1382 - }
1383 - that.resume();
1384 - }
1385 - }, function () { });
1408 + // DO NOT start terminal
1409 + this.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1410 + this.that.end();
1411 + });
1412 + }
1413 + else if (this.httprequest.protocol == 2)
1414 + {
1415 + //
1416 + // Remote KVM
1417 + //
1418
1387 - this.removeAllListeners('data');
1388 - this.on('data', onTunnelControlData);
1389 - //this.write('MeshCore Terminal Hello');
1390 - } else if (this.httprequest.protocol == 2) {
1419 // Check user access rights for desktop
1420 if ((((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NODESKTOP) != 0))) {
1421 // Disengage this tunnel, user does not have the rights to do this!!