Added new allowSavingDeviceCredentials option, #3751
Ylian Saint-Hilaire committed
Mar 15, 2022 at 17:00 UTC
545290a9af92b924b722464b88249f2d11aae8db
6 files changed
+82
-39
apprelays.js
+8
-4
@@ -168,6 +168,7 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
168
169
// Save SSH credentials into device
170
function saveRdpCredentials() {
171
+ if (domain.allowsavingdevicecredentials == false) return;
172
parent.parent.db.Get(obj.nodeid, function (err, nodes) {
173
if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
174
const node = nodes[0];
@@ -214,7 +215,7 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
215
// Check if we need to load server stored credentials
216
if ((typeof obj.infos.options == 'object') && (obj.infos.options.useServerCreds == true)) {
217
// Check if RDP credentials exist
217
- if ((typeof node.rdp == 'object') && (typeof node.rdp.d == 'string') && (typeof node.rdp.u == 'string') && (typeof node.rdp.p == 'string')) {
218
+ if ((domain.allowsavingdevicecredentials === false) && (typeof node.rdp == 'object') && (typeof node.rdp.d == 'string') && (typeof node.rdp.u == 'string') && (typeof node.rdp.p == 'string')) {
219
obj.infos.domain = node.rdp.d;
220
obj.infos.username = node.rdp.u;
221
obj.infos.password = node.rdp.p;
@@ -340,6 +341,7 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
341
342
// Save SSH credentials into device
343
function saveSshCredentials() {
344
+ if (domain.allowsavingdevicecredentials == false) return;
345
parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) {
346
if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
347
const node = nodes[0];
@@ -471,7 +473,7 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
473
parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) {
474
if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
475
const node = nodes[0];
474
- if ((node.ssh == null) || (typeof node.ssh != 'object') || (typeof node.ssh.u != 'string') || ((typeof node.ssh.p != 'string') && (typeof node.ssh.k != 'string'))) {
476
+ if ((domain.allowsavingdevicecredentials === false) || (node.ssh == null) || (typeof node.ssh != 'object') || (typeof node.ssh.u != 'string') || ((typeof node.ssh.p != 'string') && (typeof node.ssh.k != 'string'))) {
477
// Send a request for SSH authentication
478
try { ws.send(JSON.stringify({ action: 'sshauth' })) } catch (ex) { }
479
} else {
@@ -611,6 +613,7 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
613
614
// Save SSH credentials into device
615
function saveSshCredentials() {
616
+ if (domain.allowsavingdevicecredentials == false) return;
617
parent.parent.db.Get(obj.nodeid, function (err, nodes) {
618
if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
619
const node = nodes[0];
@@ -811,7 +814,7 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
814
if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
815
const node = nodes[0];
816
814
- if ((node.ssh == null) || (typeof node.ssh != 'object') || (typeof node.ssh.u != 'string') || ((typeof node.ssh.p != 'string') && (typeof node.ssh.k != 'string'))) {
817
+ if ((domain.allowsavingdevicecredentials === false) || (node.ssh == null) || (typeof node.ssh != 'object') || (typeof node.ssh.u != 'string') || ((typeof node.ssh.p != 'string') && (typeof node.ssh.k != 'string'))) {
818
// Send a request for SSH authentication
819
try { ws.send(JSON.stringify({ action: 'sshauth' })) } catch (ex) { }
820
} else {
@@ -903,6 +906,7 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
906
907
// Save SSH credentials into device
908
function saveSshCredentials() {
909
+ if (domain.allowsavingdevicecredentials == false) return;
910
parent.parent.db.Get(obj.nodeid, function (err, nodes) {
911
if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
912
const node = nodes[0];
@@ -1283,7 +1287,7 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
1287
if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
1288
const node = nodes[0];
1289
1286
- if ((node.ssh == null) || (typeof node.ssh != 'object') || (typeof node.ssh.u != 'string') || ((typeof node.ssh.p != 'string') && (typeof node.ssh.k != 'string'))) {
1290
+ if ((domain.allowsavingdevicecredentials === false) || (node.ssh == null) || (typeof node.ssh != 'object') || (typeof node.ssh.u != 'string') || ((typeof node.ssh.p != 'string') && (typeof node.ssh.k != 'string'))) {
1291
// Send a request for SSH authentication
1292
try { ws.send(JSON.stringify({ action: 'sshauth' })) } catch (ex) { }
1293
} else {
meshcentral-config-schema.json
+1
@@ -321,6 +321,7 @@
321
"hide": { "type": "integer", "default": 0, "description": "Sum of: 1 = Hide header, 2 = Hide tab, 4 = Hide footer, 8 = Hide title, 16 = Hide left bar, 32 = Hide back buttons" },
322
"footer": { "type": "string", "default": null, "description": "This is a HTML string displayed at the bottom of the web page when a user is logged in." },
323
"loginfooter": { "type": "string", "default": null, "description": "This is a HTML string displayed at the bottom of the web page when a user is not logged in." },
324
+ "allowSavingDeviceCredentials": { "type": "boolean", "default": true, "description": "Allow users to save SSH, RDP, VNC device credentials on the server that can be used by any other user." },
325
"guestDeviceSharing": {
326
"type": [ "boolean", "object" ],
327
"default": true,
views/default.handlebars
+38
-24
@@ -2434,14 +2434,14 @@
2434
if (nodes != null) { for (var i in nodes) { if (nodes[i]._id == message.nodeid) { index = i; break; } } }
2435
if (index != -1) {
2436
// Node was found, dispatch the message
2437
- if ((message.type == 'cpuinfo') && (currentNode != null) && (currentNode._id == message.nodeid)) {
2437
+ if ((message.type === 'cpuinfo') && (currentNode != null) && (currentNode._id == message.nodeid)) {
2438
var now = (Date.now() / 1000), cpu = 0, memory = 0;
2439
if (typeof message.cpu.total == 'number') { cpu = message.cpu.total; }
2440
if (typeof message.memory.percentConsumed == 'number') { memory = message.memory.percentConsumed; }
2441
deviceDetailsStatsData.push([now, cpu, memory]);
2442
deviceDetailsStatsDraw(message);
2443
- } else if (message.type == 'console') { p15consoleReceive(nodes[index], message.value, message.source); } // This is a console message.
2444
- else if (message.type == 'notify') { // This is a notification message.
2443
+ } else if (message.type === 'console') { p15consoleReceive(nodes[index], message.value, message.source); } // This is a console message.
2444
+ else if (message.type === 'notify') { // This is a notification message.
2445
var n = getstore('notifications', 0);
2446
if (((n & 8) == 0) && (message.amtMessage != null)) { break; } // Intel AMT desktop & terminal messages should be ignored.
2447
var n = { text: message.value, title: message.title, icon: message.icon, titleid: message.titleid, msgid: message.msgid, args: message.args };
@@ -2450,40 +2450,40 @@
2450
if (message.tag != null) { n.tag = message.tag; }
2451
if (message.url != null) { n.url = message.url; }
2452
if (message.username != null) { n.username = message.username; }
2453
- if (typeof message.maxtime == 'number') { n.maxtime = message.maxtime; }
2453
+ if (typeof message.maxtime === 'number') { n.maxtime = message.maxtime; }
2454
addNotification(n);
2455
- } else if (message.type == 'ps') {
2455
+ } else if (message.type === 'ps') {
2456
showDeskToolsProcesses(message);
2457
- } else if (message.type == 'services') {
2457
+ } else if (message.type === 'services') {
2458
showDeskToolsServices(message);
2459
- } else if ((message.type == 'getclip') && (currentNode != null) && (currentNode._id == message.nodeid)) {
2460
- if ((message.tag == 1) && (xxdialogTag == 'clipboard')) {
2459
+ } else if ((message.type === 'getclip') && (currentNode != null) && (currentNode._id == message.nodeid)) {
2460
+ if ((message.tag == 1) && (xxdialogTag === 'clipboard')) {
2461
Q('d2clipText').value = message.data; // Put remote clipboard data into dialog box
2462
- } else if (message.tag == 2) {
2462
+ } else if (message.tag === 2) {
2463
if (navigator.clipboard != null) { navigator.clipboard.writeText(message.data).then(function() { }).catch(function(err) { console.log(err); }) } // Put remote clipboard data into our clipboard
2464
}
2465
- } else if ((message.type == 'setclip') && (xxdialogTag == 'clipboard') && (currentNode != null) && (currentNode._id == message.nodeid)) {
2465
+ } else if ((message.type === 'setclip') && (xxdialogTag === 'clipboard') && (currentNode != null) && (currentNode._id == message.nodeid)) {
2466
// Display success/fail on the clipboard dialog box.
2467
QH('dlgClipStatus', message.success ? '<span style=color:green>' + "Success" + '</span>' : '<span style=color:red>' + "Failed" + '</span>')
2468
setTimeout(function () { try { QH('dlgClipStatus', ''); } catch (ex) { } }, 2000);
2469
- } else if ((message.type == 'userSessions') && (currentNode != null) && (currentNode._id == message.nodeid) && (desktop == null)) {
2469
+ } else if ((message.type === 'userSessions') && (currentNode != null) && (currentNode._id === message.nodeid) && (desktop == null)) {
2470
// Got list of user sessions
2471
var userSessions = [];
2472
- if (message.data != null) { for (var i in message.data) { if ((message.data[i].State == 'Active') || (message.data[i].StationName == 'Console') || (debugmode == 3)) { userSessions.push(message.data[i]); } } }
2473
- if (userSessions.length == 0) { connectDesktop(null, 1, null, message.tag); } // No active sessions, do a normal connection.
2474
- else if (userSessions.length == 1) { connectDesktop(null, 1, userSessions[0].SessionId, message.tag); } // One active session, connect to it
2472
+ if (message.data != null) { for (var i in message.data) { if ((message.data[i].State == 'Active') || (message.data[i].State == 'Connected') || (message.data[i].StationName == 'Console') || (debugmode == 3)) { userSessions.push(message.data[i]); } } }
2473
+ if (userSessions.length === 0) { connectDesktop(null, 1, null, message.tag); } // No active sessions, do a normal connection.
2474
+ else if (userSessions.length === 1) { connectDesktop(null, 1, userSessions[0].SessionId, message.tag); } // One active session, connect to it
2475
else {
2476
var x = '';
2477
for (var i in userSessions) {
2478
- x += '<div style="text-align:left;cursor:pointer;background-color:gray;margin:5px;padding:5px;border-radius:5px" onclick=connectDesktop(event,1,' + userSessions[i].SessionId + ',' + message.tag + ')>' + userSessions[i].State + ', ' + userSessions[i].StationName;
2478
+ x += '<div style="text-align:left;cursor:pointer;background-color:gray;margin:5px;padding:5px;border-radius:5px" onclick=connectDesktop(event,1,' + userSessions[i].SessionId + ',' + message.tag + ')>' + userSessions[i].State + (userSessions[i].StationName ? (', ' + userSessions[i].StationName) : '');
2479
if (userSessions[i].Username) { if (userSessions[i].Domain) { x += ' - ' + userSessions[i].Domain + '/' + userSessions[i].Username; } else { x += ' - ' + userSessions[i].Username; } }
2480
x += '</div>';
2481
}
2482
QH('p11DeskSessionSelector', x);
2483
QV('p11DeskSessionSelector', true);
2484
}
2485
- } else if (message.type == 'psinfo') {
2486
- if (xxdialogTag == ('ps|' + message.nodeid + '|' + message.pid)) {
2485
+ } else if (message.type === 'psinfo') {
2486
+ if (xxdialogTag === ('ps|' + message.nodeid + '|' + message.pid)) {
2487
var x = '<div style=max-height:200px;overflow-y:auto>';
2488
//x += addHtmlValue4("Process ID", message.pid);
2489
if ((typeof message.value == 'object') && (Object.keys(message.value).length > 0)) {
@@ -2518,7 +2518,7 @@
2518
}
2519
}
2520
} else {
2521
- if (message.type == 'notify') { // This is a notification message.
2521
+ if (message.type === 'notify') { // This is a notification message.
2522
var n = { text: message.value, title: message.title, icon: message.icon, titleid: message.titleid, msgid: message.msgid, args: message.args };
2523
if (message.id != null) { n.id = message.id; }
2524
if (message.tag != null) { n.tag = message.tag; }
@@ -9489,8 +9489,9 @@
9489
x += addHtmlValue("Key File", '<input type=file id=dp2key style=width:230px maxlength=64 autocomplete=off onchange=sshAuthUpdate(event) />' + '<div id=d2badkey style=font-size:x-small>' + "Key file must be in OpenSSH format." + '</div>');
9490
x += addHtmlValue("Key Password", '<input type=password id=dp2keypass style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
9491
x += '</div>';
9492
- x += addHtmlValue('', '<label><input id=dp2keep type=checkbox>' + "Remember credentials" + '</label>');
9492
+ if ((features2 & 0x00400000) == 0) { x += addHtmlValue('', '<label><input id=dp2keep type=checkbox>' + "Remember credentials" + '</label>'); }
9493
setDialogMode(2, "Authentication", 11, sshConnectEx, x, 'ssh');
9494
+ Q('dp2user').focus();
9495
setTimeout(sshAuthUpdate, 50);
9496
break;
9497
}
@@ -9525,15 +9526,25 @@
9526
reader.readAsText(Q('dp2key').files[0]);
9527
}
9528
}
9529
+
9530
+ // When the enter key is pressed, move to the next field
9531
+ if (e && (e.keyCode == 13) && (e.target) && (Q('dp2authmethod').value == 1)) {
9532
+ if (e.target.id == 'dp2user') { Q('dp2pass').focus(); }
9533
+ if (e.target.id == 'dp2pass') { dialogclose(1); }
9534
+ }
9535
}
9536
+
9537
function sshConnectEx(b) {
9538
if (b == 0) {
9539
if (terminal != null) { connectTerminal(); } // Disconnect
9540
} else {
9541
+ var keep = false;
9542
+ if ((features2 & 0x00400000) == 0) { keep = Q('dp2keep').checked; }
9543
+
9544
if (Q('dp2authmethod').value == 1) {
9534
- terminal.socket.send(JSON.stringify({ action: 'sshauth', username: Q('dp2user').value, password: Q('dp2pass').value, keep: Q('dp2keep').checked, cols: xterm.cols, rows: xterm.rows, width: Q('termarea3xdiv').offsetWidth, height: Q('termarea3xdiv').offsetHeight }));
9545
+ terminal.socket.send(JSON.stringify({ action: 'sshauth', username: Q('dp2user').value, password: Q('dp2pass').value, keep: keep, cols: xterm.cols, rows: xterm.rows, width: Q('termarea3xdiv').offsetWidth, height: Q('termarea3xdiv').offsetHeight }));
9546
} else {
9536
- var reader = new FileReader(), username = Q('dp2user').value, keypass = Q('dp2keypass').value, keep = Q('dp2keep').checked;
9547
+ var reader = new FileReader(), username = Q('dp2user').value, keypass = Q('dp2keypass').value;
9548
reader.onload = function (e) { terminal.socket.send(JSON.stringify({ action: 'sshauth', username: username, keypass: keypass, key: e.target.result, keep: keep, cols: xterm.cols, rows: xterm.rows, width: Q('termarea3xdiv').offsetWidth, height: Q('termarea3xdiv').offsetHeight })); }
9549
reader.readAsText(Q('dp2key').files[0]);
9550
}
@@ -9881,8 +9892,9 @@
9892
x += addHtmlValue("Key File", '<input type=file id=dp2key style=width:230px maxlength=64 autocomplete=off onchange=sshAuthUpdate(event) />');
9893
x += addHtmlValue("Key Password", '<input type=password id=dp2keypass style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
9894
x += '</div>';
9884
- x += addHtmlValue('', '<label><input id=dp2keep type=checkbox>' + "Remember credentials" + '</label>');
9895
+ if ((features2 & 0x00400000) == 0) { x += addHtmlValue('', '<label><input id=dp2keep type=checkbox>' + "Remember credentials" + '</label>'); }
9896
setDialogMode(2, "Authentication", 11, p13sshConnectEx, x, 'ssh');
9897
+ Q('dp2user').focus();
9898
setTimeout(sshAuthUpdate, 50);
9899
return;
9900
}
@@ -9938,10 +9950,12 @@
9950
if (b == 0) {
9951
if (files != null) { connectFiles(); } // Disconnect
9952
} else {
9953
+ var keep = false;
9954
+ if ((features2 & 0x00400000) == 0) { keep = Q('dp2keep').checked; }
9955
if (Q('dp2authmethod').value == 1) {
9942
- files.socket.send(JSON.stringify({ action: 'sshauth', username: Q('dp2user').value, password: Q('dp2pass').value, keep: Q('dp2keep').checked }));
9956
+ files.socket.send(JSON.stringify({ action: 'sshauth', username: Q('dp2user').value, password: Q('dp2pass').value, keep: keep }));
9957
} else {
9944
- var reader = new FileReader(), username = Q('dp2user').value, keypass = Q('dp2keypass').value, keep = Q('dp2keep').checked;
9958
+ var reader = new FileReader(), username = Q('dp2user').value, keypass = Q('dp2keypass').value;
9959
reader.onload = function (e) { files.socket.send(JSON.stringify({ action: 'sshauth', username: username, keypass: keypass, key: e.target.result, keep: keep })); }
9960
reader.readAsText(Q('dp2key').files[0]);
9961
}
views/mstsc.handlebars
+2
-1
@@ -83,6 +83,7 @@
83
var serverCredentials = (decodeURIComponent('{{{serverCredentials}}}') == 'true');
84
var name = decodeURIComponent('{{{name}}}');
85
if (name != '') { document.title = name + ' - ' + document.title; }
86
+ var features = parseInt('{{{features}}}');
87
88
function load() {
89
if (name != '') { QH('computerName', EscapeHtml(name)); }
@@ -159,7 +160,7 @@
160
QV('rowdomain', newCreds);
161
QV('rowusername', newCreds);
162
QV('rowpassword', newCreds);
162
- QV('rowremember', newCreds);
163
+ QV('rowremember', newCreds && ((features & 1) == 0));
164
if (newCreds) Q('inputUsername').focus();
165
}
166
views/ssh.handlebars
+10
-2
@@ -75,6 +75,7 @@
75
if (urlargs.key && (isAlphaNumeric(urlargs.key) == false)) { delete urlargs.key; }
76
var cookie = '{{{cookie}}}';
77
var domainurl = '{{{domainurl}}}';
78
+ var features = parseInt('{{{features}}}');
79
var name = decodeURIComponent('{{{name}}}');
80
if (name != '') { document.title = name + ' - ' + document.title; }
81
var StatusStrs = ["Disconnected", "Connecting...", "Setup...", "Connected"];
@@ -146,10 +147,17 @@
147
reader.readAsText(Q('dp2key').files[0]);
148
}
149
}
150
+
151
+ // When the enter key is pressed, move to the next field
152
+ if (e && (e.keyCode == 13) && (e.target) && (Q('dp2authmethod').value == 1)) {
153
+ if (e.target.id == 'dp2user') { Q('dp2pass').focus(); }
154
+ if (e.target.id == 'dp2pass') { dialogclose(1); }
155
+ }
156
}
157
158
function connectEx() {
152
- var cmd = { action: 'connect', cols: term.cols, rows: term.rows, width: Q('terminal').offsetWidth, height: Q('terminal').offsetHeight, username: Q('dp2user').value, keep: Q('dp2keep').checked };
159
+ var cmd = { action: 'connect', cols: term.cols, rows: term.rows, width: Q('terminal').offsetWidth, height: Q('terminal').offsetHeight, username: Q('dp2user').value, keep: false };
160
+ if ((features & 1) == 0) { cmd.keep = Q('dp2keep').checked; }
161
162
if (Q('dp2authmethod').value == 1) {
163
cmd.password = Q('dp2pass').value;
@@ -191,7 +199,7 @@
199
x += addHtmlValue("Key File", '<input type=file id=dp2key style=width:230px maxlength=64 autocomplete=off onchange=sshAuthUpdate(event) />' + '<div id=d2badkey style=font-size:x-small>' + "Key file must be in OpenSSH format." + '</div>');
200
x += addHtmlValue("Key Password", '<input type=password id=dp2keypass style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
201
x += '</div>';
194
- x += addHtmlValue('', '<label><input id=dp2keep type=checkbox>' + "Remember credentials" + '</label>');
202
+ if ((features & 1) == 0) { x += addHtmlValue('', '<label><input id=dp2keep type=checkbox>' + "Remember credentials" + '</label>'); }
203
setDialogMode(2, "Authentication", 3, connectEx, x);
204
Q('dp2user').value = user;
205
Q('dp2pass').value = pass;
webserver.js
+23
-8
@@ -1949,6 +1949,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
1949
return;
1950
}
1951
1952
+ // Set features we want to send to this page
1953
+ var features = 0;
1954
+ if (domain.allowsavingdevicecredentials === false) { features |= 1; }
1955
+
1956
if (req.query.ws != null) {
1957
// This is a query with a websocket relay cookie, check that the cookie is valid and use it.
1958
var rcookie = parent.decodeCookie(req.query.ws, parent.loginCookieEncryptionKey, 60); // Cookie with 1 hour timeout
@@ -1960,10 +1964,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
1964
const node = nodes[0];
1965
1966
// Check if we have RDP credentials for this device
1963
- var serverCredentials = ((typeof node.rdp == 'object') && (typeof node.rdp.d == 'string') && (typeof node.rdp.u == 'string') && (typeof node.rdp.p == 'string'));
1967
+ var serverCredentials = false;
1968
+ if (domain.allowsavingdevicecredentials !== false) {
1969
+ if (page == 'ssh') {
1970
+ serverCredentials = ((typeof node.rdp == 'object') && (typeof node.rdp.d == 'string') && (typeof node.rdp.u == 'string') && (typeof node.rdp.p == 'string'))
1971
+ } else {
1972
+ serverCredentials = ((typeof node.ssh == 'object') && (typeof node.ssh.u == 'string'))
1973
+ }
1974
+ }
1975
1976
// Render the page
1966
- render(req, res, getRenderPage(page, req, domain), getRenderArgs({ cookie: req.query.ws, name: encodeURIComponent(req.query.name).replace(/'/g, '%27'), serverCredentials: serverCredentials }, req, domain));
1977
+ render(req, res, getRenderPage(page, req, domain), getRenderArgs({ cookie: req.query.ws, name: encodeURIComponent(req.query.name).replace(/'/g, '%27'), serverCredentials: serverCredentials, features: features }, req, domain));
1978
});
1979
return;
1980
}
@@ -2000,35 +2011,38 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
2011
}
2012
2013
// If there is no nodeid, exit now
2003
- if (req.query.node == null) { render(req, res, getRenderPage(page, req, domain), getRenderArgs({ cookie: '', name: '' }, req, domain)); return; }
2014
+ if (req.query.node == null) { render(req, res, getRenderPage(page, req, domain), getRenderArgs({ cookie: '', name: '', features: features }, req, domain)); return; }
2015
2016
// Fetch the node from the database
2017
obj.db.Get(req.query.node, function (err, nodes) {
2018
if ((err != null) || (nodes.length != 1)) { res.sendStatus(404); return; }
2019
const node = nodes[0];
2020
2010
- // Check if we have RDP credentials for this device
2011
- var serverCredentials = ((typeof node.rdp == 'object') && (typeof node.rdp.d == 'string') && (typeof node.rdp.u == 'string') && (typeof node.rdp.p == 'string'));
2012
-
2021
// Check access rights, must have remote control rights
2022
if ((obj.GetNodeRights(user, node.meshid, node._id) & MESHRIGHT_REMOTECONTROL) == 0) { res.sendStatus(401); return; }
2023
2024
// Figure out the target port
2017
- var port = 0;
2025
+ var port = 0, serverCredentials = false;
2026
if (page == 'ssh') {
2027
// SSH port
2028
port = 22;
2029
if (typeof node.sshport == 'number') { port = node.sshport; }
2030
+
2031
+ // Check if we have SSH credentials for this device
2032
+ if (domain.allowsavingdevicecredentials !== false) { serverCredentials = ((typeof node.ssh == 'object') && (typeof node.ssh.u == 'string')); }
2033
} else {
2034
// RDP port
2035
port = 3389;
2036
if (typeof node.rdpport == 'number') { port = node.rdpport; }
2037
+
2038
+ // Check if we have RDP credentials for this device
2039
+ if (domain.allowsavingdevicecredentials !== false) { serverCredentials = ((typeof node.rdp == 'object') && (typeof node.rdp.d == 'string') && (typeof node.rdp.u == 'string') && (typeof node.rdp.p == 'string')); }
2040
}
2041
if (req.query.port != null) { var qport = 0; try { qport = parseInt(req.query.port); } catch (ex) { } if ((typeof qport == 'number') && (qport > 0) && (qport < 65536)) { port = qport; } }
2042
2043
// Generate a cookie and respond
2044
var cookie = parent.encodeCookie({ userid: user._id, domainid: user.domain, nodeid: node._id, tcpport: port }, parent.loginCookieEncryptionKey);
2031
- render(req, res, getRenderPage(page, req, domain), getRenderArgs({ cookie: cookie, name: encodeURIComponent(node.name).replace(/'/g, '%27'), serverCredentials: serverCredentials }, req, domain));
2045
+ render(req, res, getRenderPage(page, req, domain), getRenderArgs({ cookie: cookie, name: encodeURIComponent(node.name).replace(/'/g, '%27'), serverCredentials: serverCredentials, features: features }, req, domain));
2046
});
2047
}
2048
@@ -2942,6 +2956,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
2956
if ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.single2factorwarning === false)) { features2 += 0x00080000; } // Indicates no warning if a single 2FA is in use
2957
if (domain.nightmode === 1) { features2 += 0x00100000; } // Always night mode
2958
if (domain.nightmode === 2) { features2 += 0x00200000; } // Always day mode
2959
+ if (domain.allowsavingdevicecredentials == false) { features2 += 0x00400000; } // Do not allow device credentials to be saved on the server
2960
return { features: features, features2: features2 };
2961
}
2962