SSH/RDP credentials are now stored per user account, #3995

Ylian Saint-Hilaire committed May 17, 2022 at 16:09 UTC 753b6c240a4050449267e6b10ca7d0692eb6e257
3 files changed +141 -98
apprelays.js
+109 -83
@@ -215,28 +215,33 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
215 }
216 }
217
218 - // Save SSH credentials into device
218 + // Save RDP credentials into database
219 function saveRdpCredentials() {
220 if (domain.allowsavingdevicecredentials == false) return;
221 parent.parent.db.Get(obj.nodeid, function (err, nodes) {
222 if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
223 const node = nodes[0];
224 - const changed = (node.rdp == null);
224 + if (node.rdp == null) { node.rdp = {}; }
225
226 - // Check if credentials are the same
227 - if ((typeof node.rdp == 'object') && (node.rdp.d == obj.infos.domain) && (node.rdp.u == obj.infos.username) && (node.rdp.p == obj.infos.password)) return;
226 + // Check if credentials are already set
227 + if ((typeof node.rdp[obj.userid] == 'object') && (node.rdp[obj.userid].d == obj.infos.domain) && (node.rdp[obj.userid].u == obj.infos.username) && (node.rdp[obj.userid].p == obj.infos.password)) return;
228 +
229 + // Clear up any existing credentials or credentials for users that don't exist anymore
230 + for (var i in node.rdp) { if (!i.startsWith('user/') || (parent.users[i] == null)) { delete node.rdp[i]; } }
231 +
232 + // Clear legacy credentials
233 + delete node.rdp.d;
234 + delete node.rdp.u;
235 + delete node.rdp.p;
236
237 // Save the credentials
230 - node.rdp = { d: obj.infos.domain, u: obj.infos.username, p: obj.infos.password };
238 + node.rdp[obj.userid] = { d: obj.infos.domain, u: obj.infos.username, p: obj.infos.password };
239 parent.parent.db.Set(node);
240
233 - // Event node change if needed
234 - if (changed) {
235 - // Event the node change
236 - const event = { etype: 'node', action: 'changenode', nodeid: obj.nodeid, domain: domain.id, userid: obj.userid, node: parent.CloneSafeNode(node), msg: "Changed RDP credentials" };
237 - if (parent.parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
238 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(node.meshid, [obj.nodeid]), obj, event);
239 - }
241 + // Event the node change
242 + const event = { etype: 'node', action: 'changenode', nodeid: obj.nodeid, domain: domain.id, userid: obj.userid, node: parent.CloneSafeNode(node), msg: "Changed RDP credentials" };
243 + if (parent.parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
244 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(node.meshid, [obj.nodeid]), obj, event);
245 });
246 }
247
@@ -299,10 +304,10 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
304 // Check if we need to load server stored credentials
305 if ((typeof obj.infos.options == 'object') && (obj.infos.options.useServerCreds == true)) {
306 // Check if RDP credentials exist
302 - if ((domain.allowsavingdevicecredentials !== false) && (typeof node.rdp == 'object') && (typeof node.rdp.d == 'string') && (typeof node.rdp.u == 'string') && (typeof node.rdp.p == 'string')) {
303 - obj.infos.domain = node.rdp.d;
304 - obj.infos.username = node.rdp.u;
305 - obj.infos.password = node.rdp.p;
307 + if ((domain.allowsavingdevicecredentials !== false) && (typeof node.rdp == 'object') && (typeof node.rdp[obj.userid] == 'object') && (typeof node.rdp[obj.userid].d == 'string') && (typeof node.rdp[obj.userid].u == 'string') && (typeof node.rdp[obj.userid].p == 'string')) {
308 + obj.infos.domain = node.rdp[obj.userid].d;
309 + obj.infos.username = node.rdp[obj.userid].u;
310 + obj.infos.password = node.rdp[obj.userid].p;
311 startTcpServer();
312 } else {
313 // No server credentials.
@@ -382,7 +387,7 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
387 module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
388 const Net = require('net');
389 const WebSocket = require('ws');
385 -
390 +
391 // SerialTunnel object is used to embed SSH within another connection.
392 function SerialTunnel(options) {
393 const obj = new require('stream').Duplex(options);
@@ -447,36 +452,43 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
452 delete obj.cookie;
453 delete obj.nodeid;
454 delete obj.meshid;
455 + delete obj.userid;
456 delete obj.ws;
457 };
458
453 - // Save SSH credentials into device
459 + // Save SSH credentials into database
460 function saveSshCredentials(keep) {
461 if (((keep != 1) && (keep != 2)) || (domain.allowsavingdevicecredentials == false)) return;
462 parent.parent.db.Get(obj.nodeid, function (err, nodes) {
463 if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
464 const node = nodes[0];
459 - const changed = (node.ssh == null);
465 + if (node.ssh == null) { node.ssh = {}; }
466
467 // Check if credentials are the same
462 - //if ((typeof node.ssh == 'object') && (node.ssh.u == obj.username) && (node.ssh.p == obj.password)) return; // TODO
468 + //if ((typeof node.ssh[obj.userid] == 'object') && (node.ssh[obj.userid].u == obj.username) && (node.ssh[obj.userid].p == obj.password)) return; // TODO
469 +
470 + // Clear up any existing credentials or credentials for users that don't exist anymore
471 + for (var i in node.ssh) { if (!i.startsWith('user/') || (parent.users[i] == null)) { delete node.ssh[i]; } }
472 +
473 + // Clear legacy credentials
474 + delete node.ssh.u;
475 + delete node.ssh.p;
476 + delete node.ssh.k;
477 + delete node.ssh.kp;
478
479 // Save the credentials
480 if (obj.password != null) {
466 - node.ssh = { u: obj.username, p: obj.password };
481 + node.ssh[obj.userid] = { u: obj.username, p: obj.password };
482 } else if (obj.privateKey != null) {
468 - node.ssh = { u: obj.username, k: obj.privateKey };
469 - if (keep == 2) { node.ssh.kp = obj.privateKeyPass; }
483 + node.ssh[obj.userid] = { u: obj.username, k: obj.privateKey };
484 + if (keep == 2) { node.ssh[obj.userid].kp = obj.privateKeyPass; }
485 } else return;
486 parent.parent.db.Set(node);
487
473 - // Event node change if needed
474 - if (changed) {
475 - // Event the node change
476 - const event = { etype: 'node', action: 'changenode', nodeid: obj.nodeid, domain: domain.id, userid: obj.userid, node: parent.CloneSafeNode(node), msg: "Changed SSH credentials" };
477 - if (parent.parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
478 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(node.meshid, [obj.nodeid]), obj, event);
479 - }
488 + // Event the node change
489 + const event = { etype: 'node', action: 'changenode', nodeid: obj.nodeid, domain: domain.id, userid: obj.userid, node: parent.CloneSafeNode(node), msg: "Changed SSH credentials" };
490 + if (parent.parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
491 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(node.meshid, [obj.nodeid]), obj, event);
492 });
493 }
494
@@ -592,24 +604,24 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
604 parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) {
605 if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
606 const node = nodes[0];
595 - 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'))) {
607 + if ((domain.allowsavingdevicecredentials === false) || (node.ssh == null) || (typeof node.ssh != 'object') || (node.ssh[user._id] == null) || (typeof node.ssh[user._id].u != 'string') || ((typeof node.ssh[user._id].p != 'string') && (typeof node.ssh[user._id].k != 'string'))) {
608 // Send a request for SSH authentication
609 try { ws.send(JSON.stringify({ action: 'sshauth' })) } catch (ex) { }
598 - } else if ((domain.allowsavingdevicecredentials !== false) && (node.ssh != null) && (typeof node.ssh.k == 'string') && (node.ssh.kp == null)) {
610 + } else if ((domain.allowsavingdevicecredentials !== false) && (node.ssh != null) && (typeof node.ssh[user._id].k == 'string') && (node.ssh[user._id].kp == null)) {
611 // Send a request for SSH authentication with option for only the private key password
600 - obj.username = node.ssh.u;
601 - obj.privateKey = node.ssh.k;
612 + obj.username = node.ssh[user._id].u;
613 + obj.privateKey = node.ssh[user._id].k;
614 try { ws.send(JSON.stringify({ action: 'sshauth', askkeypass: true })) } catch (ex) { }
615 } else {
616 // Use our existing credentials
617 obj.termSize = msg;
618 delete obj.keep;
607 - obj.username = node.ssh.u;
608 - if (typeof node.ssh.p == 'string') {
609 - obj.password = node.ssh.p;
610 - } else if (typeof node.ssh.k == 'string') {
611 - obj.privateKey = node.ssh.k;
612 - obj.privateKeyPass = node.ssh.kp;
619 + obj.username = node.ssh[user._id].u;
620 + if (typeof node.ssh[user._id].p == 'string') {
621 + obj.password = node.ssh[user._id].p;
622 + } else if (typeof node.ssh[user._id].k == 'string') {
623 + obj.privateKey = node.ssh[user._id].k;
624 + obj.privateKeyPass = node.ssh[user._id].kp;
625 }
626 startRelayConnection();
627 }
@@ -786,30 +798,37 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
798 parent.parent.db.Get(obj.nodeid, function (err, nodes) {
799 if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
800 const node = nodes[0];
789 - const changed = (node.ssh == null);
801 + if (node.ssh == null) { node.ssh = {}; }
802
803 // Check if credentials are the same
804 //if ((typeof node.ssh == 'object') && (node.ssh.u == obj.username) && (node.ssh.p == obj.password)) return; // TODO
805
806 + // Clear up any existing credentials or credentials for users that don't exist anymore
807 + for (var i in node.ssh) { if (!i.startsWith('user/') || (parent.users[i] == null)) { delete node.ssh[i]; } }
808 +
809 + // Clear legacy credentials
810 + delete node.ssh.u;
811 + delete node.ssh.p;
812 + delete node.ssh.k;
813 + delete node.ssh.kp;
814 +
815 // Save the credentials
816 if (obj.password != null) {
796 - node.ssh = { u: obj.username, p: obj.password };
817 + node.ssh[user._id] = { u: obj.username, p: obj.password };
818 } else if (obj.privateKey != null) {
798 - node.ssh = { u: obj.username, k: obj.privateKey };
799 - if (keep == 2) { node.ssh.kp = obj.privateKeyPass; }
819 + node.ssh[user._id] = { u: obj.username, k: obj.privateKey };
820 + if (keep == 2) { node.ssh[user._id].kp = obj.privateKeyPass; }
821 } else return;
822 parent.parent.db.Set(node);
823
803 - // Event node change if needed
804 - if (changed) {
805 - // Event the node change
806 - const event = { etype: 'node', action: 'changenode', nodeid: obj.nodeid, domain: domain.id, userid: user._id, username: user.name, node: parent.CloneSafeNode(node), msg: "Changed SSH credentials" };
807 - if (parent.parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
808 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(node.meshid, [obj.nodeid]), obj, event);
809 - }
824 + // Event the node change
825 + const event = { etype: 'node', action: 'changenode', nodeid: obj.nodeid, domain: domain.id, userid: user._id, username: user.name, node: parent.CloneSafeNode(node), msg: "Changed SSH credentials" };
826 + if (parent.parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
827 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(node.meshid, [obj.nodeid]), obj, event);
828 });
829 }
830
831 +
832 // Start the looppback server
833 function startRelayConnection(authCookie) {
834 try {
@@ -1032,22 +1051,22 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
1051 ws._socket.resume();
1052
1053 // Check if we have SSH credentials for this device
1035 - 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'))) {
1054 + if ((domain.allowsavingdevicecredentials === false) || (node.ssh == null) || (typeof node.ssh != 'object') || (node.ssh[user._id] == null) || (typeof node.ssh[user._id].u != 'string') || ((typeof node.ssh[user._id].p != 'string') && (typeof node.ssh[user._id].k != 'string'))) {
1055 // Send a request for SSH authentication
1056 try { ws.send(JSON.stringify({ action: 'sshauth' })) } catch (ex) { }
1038 - } else if ((typeof node.ssh.k == 'string') && (typeof node.ssh.kp != 'string')) {
1057 + } else if ((typeof node.ssh[user._id].k == 'string') && (typeof node.ssh[user._id].kp != 'string')) {
1058 // Send a request for SSH authentication with option for only the private key password
1040 - obj.username = node.ssh.u;
1041 - obj.privateKey = node.ssh.k;
1059 + obj.username = node.ssh[user._id].u;
1060 + obj.privateKey = node.ssh[user._id].k;
1061 try { ws.send(JSON.stringify({ action: 'sshauth', askkeypass: true })) } catch (ex) { }
1062 } else {
1063 // Use our existing credentials
1045 - obj.username = node.ssh.u;
1046 - if (typeof node.ssh.p == 'string') {
1047 - obj.password = node.ssh.p;
1048 - } else if (typeof node.ssh.k == 'string') {
1049 - obj.privateKey = node.ssh.k;
1050 - obj.privateKeyPass = node.ssh.kp;
1064 + obj.username = node.ssh[user._id].u;
1065 + if (typeof node.ssh[user._id].p == 'string') {
1066 + obj.password = node.ssh[user._id].p;
1067 + } else if (typeof node.ssh[user._id].k == 'string') {
1068 + obj.privateKey = node.ssh[user._id].k;
1069 + obj.privateKeyPass = node.ssh[user._id].kp;
1070 }
1071 try { ws.send(JSON.stringify({ action: 'sshautoauth' })) } catch (ex) { }
1072 }
@@ -1132,30 +1151,37 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
1151 parent.parent.db.Get(obj.nodeid, function (err, nodes) {
1152 if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
1153 const node = nodes[0];
1135 - const changed = (node.ssh == null);
1154 + if (node.rdp == null) { node.rdp = {}; }
1155
1156 // Check if credentials are the same
1138 - //if ((typeof node.ssh == 'object') && (node.ssh.u == obj.username) && (node.ssh.p == obj.password)) return; // TODO
1157 + //if ((typeof node.ssh[obj.userid] == 'object') && (node.ssh[obj.userid].u == obj.username) && (node.ssh[obj.userid].p == obj.password)) return; // TODO
1158 +
1159 + // Clear up any existing credentials or credentials for users that don't exist anymore
1160 + for (var i in node.ssh) { if (!i.startsWith('user/') || (parent.users[i] == null)) { delete node.ssh[i]; } }
1161 +
1162 + // Clear legacy credentials
1163 + delete node.ssh.u;
1164 + delete node.ssh.p;
1165 + delete node.ssh.k;
1166 + delete node.ssh.kp;
1167
1168 // Save the credentials
1169 if (obj.password != null) {
1142 - node.ssh = { u: obj.username, p: obj.password };
1170 + node.ssh[user._id] = { u: obj.username, p: obj.password };
1171 } else if (obj.privateKey != null) {
1144 - node.ssh = { u: obj.username, k: obj.privateKey };
1145 - if (keep == 2) { node.ssh.kp = obj.privateKeyPass; }
1172 + node.ssh[user._id] = { u: obj.username, k: obj.privateKey };
1173 + if (keep == 2) { node.ssh[user._id].kp = obj.privateKeyPass; }
1174 } else return;
1175 parent.parent.db.Set(node);
1176
1149 - // Event node change if needed
1150 - if (changed) {
1151 - // Event the node change
1152 - const event = { etype: 'node', action: 'changenode', nodeid: obj.nodeid, domain: domain.id, userid: user._id, username: user.name, node: parent.CloneSafeNode(node), msg: "Changed SSH credentials" };
1153 - if (parent.parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
1154 - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(node.meshid, [obj.nodeid]), obj, event);
1155 - }
1177 + // Event the node change
1178 + const event = { etype: 'node', action: 'changenode', nodeid: obj.nodeid, domain: domain.id, userid: user._id, username: user.name, node: parent.CloneSafeNode(node), msg: "Changed SSH credentials" };
1179 + if (parent.parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
1180 + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(node.meshid, [obj.nodeid]), obj, event);
1181 });
1182 }
1183
1184 +
1185 // Start the looppback server
1186 function startRelayConnection(authCookie) {
1187 try {
@@ -1554,22 +1580,22 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
1580 ws._socket.resume();
1581
1582 // Check if we have SSH credentials for this device
1557 - 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'))) {
1583 + if ((domain.allowsavingdevicecredentials === false) || (node.ssh == null) || (typeof node.ssh != 'object') || (node.ssh[user._id] == null) || (typeof node.ssh[user._id].u != 'string') || ((typeof node.ssh[user._id].p != 'string') && (typeof node.ssh[user._id].k != 'string'))) {
1584 // Send a request for SSH authentication
1585 try { ws.send(JSON.stringify({ action: 'sshauth' })) } catch (ex) { }
1560 - } else if ((typeof node.ssh.k == 'string') && (typeof node.ssh.kp != 'string')) {
1586 + } else if ((typeof node.ssh[user._id].k == 'string') && (typeof node.ssh[user._id].kp != 'string')) {
1587 // Send a request for SSH authentication with option for only the private key password
1562 - obj.username = node.ssh.u;
1563 - obj.privateKey = node.ssh.k;
1588 + obj.username = node.ssh[user._id].u;
1589 + obj.privateKey = node.ssh[user._id].k;
1590 try { ws.send(JSON.stringify({ action: 'sshauth', askkeypass: true })) } catch (ex) { }
1591 } else {
1592 // Use our existing credentials
1567 - obj.username = node.ssh.u;
1568 - if (typeof node.ssh.p == 'string') {
1569 - obj.password = node.ssh.p;
1570 - } else if (typeof node.ssh.k == 'string') {
1571 - obj.privateKey = node.ssh.k;
1572 - obj.privateKeyPass = node.ssh.kp;
1593 + obj.username = node.ssh[user._id].u;
1594 + if (typeof node.ssh[user._id].p == 'string') {
1595 + obj.password = node.ssh[user._id].p;
1596 + } else if (typeof node.ssh[user._id].k == 'string') {
1597 + obj.privateKey = node.ssh[user._id].k;
1598 + obj.privateKeyPass = node.ssh[user._id].kp;
1599 }
1600
1601 // Create a mesh relay authentication cookie
meshuser.js
+21 -10
@@ -423,9 +423,16 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
423 else if (event == 'updatefiles') { updateUserFiles(user, ws, domain); }
424 else {
425 // If updating guest device shares, if we are updating a user that is not creator of the share, remove the URL.
426 - if ((event.action == 'deviceShareUpdate') && (Array.isArray(event.deviceShares))) {
426 + if (((event.action == 'deviceShareUpdate') && (Array.isArray(event.deviceShares))) || ((event.action == 'changenode') && (event.node != null) && ((event.node.rdp != null) || (event.node.ssh != null)))) {
427 event = common.Clone(event);
428 - for (var i in event.deviceShares) { if (event.deviceShares[i].userid != user._id) { delete event.deviceShares[i].url; } }
428 + if ((event.action == 'deviceShareUpdate') && (Array.isArray(event.deviceShares))) {
429 + for (var i in event.deviceShares) { if (event.deviceShares[i].userid != user._id) { delete event.deviceShares[i].url; } }
430 + }
431 + if ((event.action == 'changenode') && (event.node != null) && ((event.node.rdp != null) || (event.node.ssh != null))) {
432 + // Clean up RDP & SSH credentials
433 + if ((event.node.rdp != null) && (typeof event.node.rdp[user._id] == 'number')) { event.node.rdp = event.node.rdp[user._id]; } else { delete event.node.rdp; }
434 + if ((event.node.ssh != null) && (typeof event.node.ssh[user._id] == 'number')) { event.node.ssh = event.node.ssh[user._id]; } else { delete event.node.ssh; }
435 + }
436 }
437
438 // This is a MeshCentral Satellite message
@@ -730,18 +737,18 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
737
738 // Remove SSH credentials if present
739 if (docs[i].ssh != null) {
733 - if (docs[i].ssh.u) {
734 - if (docs[i].ssh.k && docs[i].ssh.kp) { docs[i].ssh = 2; } // Username, key and password
735 - else if (docs[i].ssh.k) { docs[i].ssh = 3; } // Username and key. No password.
736 - else if (docs[i].ssh.p) { docs[i].ssh = 1; } // Username and password
740 + if ((docs[i].ssh[obj.user._id] != null) && (docs[i].ssh[obj.user._id].u)) {
741 + if (docs[i].ssh.k && docs[i].ssh[obj.user._id].kp) { docs[i].ssh = 2; } // Username, key and password
742 + else if (docs[i].ssh[obj.user._id].k) { docs[i].ssh = 3; } // Username and key. No password.
743 + else if (docs[i].ssh[obj.user._id].p) { docs[i].ssh = 1; } // Username and password
744 else { delete docs[i].ssh; }
745 } else {
746 delete docs[i].ssh;
747 }
748 }
749
743 - // Remove RDP credentials if present
744 - if (docs[i].rdp != null) { docs[i].rdp = 1; }
750 + // Remove RDP credentials if present, only set to 1 if our userid has RDP credentials
751 + if ((docs[i].rdp != null) && (docs[i].rdp[obj.user._id] != null)) { docs[i].rdp = 1; } else { delete docs[i].rdp; }
752
753 // Remove Intel AMT credential if present
754 if (docs[i].intelamt != null) {
@@ -3014,13 +3021,17 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3021 }
3022
3023 if ((typeof command.ssh == 'number') && (command.ssh == 0)) {
3017 - if (node.ssh != null) { delete node.ssh; change = 1; changes.push('ssh'); } // Delete the SSH cendentials
3024 + if ((node.ssh != null) && (node.ssh[user._id] != null)) { delete node.ssh[user._id]; change = 1; changes.push('ssh'); } // Delete the SSH cendentials
3025 }
3026
3027 if ((typeof command.rdp == 'number') && (command.rdp == 0)) {
3021 - if (node.rdp != null) { delete node.rdp; change = 1; changes.push('rdp'); } // Delete the RDP cendentials
3028 + if ((node.rdp != null) && (node.rdp[user._id] != null)) { delete node.rdp[user._id]; change = 1; changes.push('rdp'); } // Delete the RDP cendentials
3029 }
3030
3031 + // Clean up any legacy RDP and SSH credentials
3032 + if (node.rdp != null) { delete node.rdp.d; delete node.rdp.u; delete node.rdp.p; }
3033 + if (node.ssh != null) { delete node.ssh.u; delete node.ssh.p; delete node.ssh.k; delete node.ssh.kp; }
3034 +
3035 if (domain.geolocation && command.userloc && ((node.userloc == null) || (command.userloc[0] != node.userloc[0]) || (command.userloc[1] != node.userloc[1]))) {
3036 change = 1;
3037 if ((command.userloc.length == 0) && (node.userloc)) {
webserver.js
+11 -5
@@ -7533,12 +7533,18 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
7533 if ((r.pmt != null) || (r.ssh != null) || (r.rdp != null) || ((r.intelamt != null) && ((r.intelamt.pass != null) || (r.intelamt.mpspass != null)))) {
7534 r = Object.assign({}, r); // Shallow clone
7535 if (r.pmt != null) { r.pmt = 1; }
7536 - if (r.ssh && r.ssh.u) {
7537 - if (r.ssh.p) { r.ssh = 1; } // Username and password
7538 - else if (r.ssh.k && r.ssh.kp) { r.ssh = 2; } // Username, key and password
7539 - else if (r.ssh.k) { r.ssh = 3; } // Username and key. No password.
7536 + if (r.ssh != null) {
7537 + var n = {};
7538 + for (var i in r.ssh) {
7539 + if (i.startsWith('user/')) {
7540 + if (r.ssh[i].p) { n[i] = 1; } // Username and password
7541 + else if (r.ssh[i].k && r.ssh[i].kp) { n[i] = 2; } // Username, key and password
7542 + else if (r.ssh[i].k) { n[i] = 3; } // Username and key. No password.
7543 + }
7544 + }
7545 + r.ssh = n;
7546 }
7541 - if (r.rdp != null) { r.rdp = 1; }
7547 + if (r.rdp != null) { var n = {}; for (var i in r.rdp) { if (i.startsWith('user/')) { n[i] = 1; } } r.rdp = n; }
7548 if ((r.intelamt != null) && ((r.intelamt.pass != null) || (r.intelamt.mpspass != null))) {
7549 r.intelamt = Object.assign({}, r.intelamt); // Shallow clone
7550 if (r.intelamt.pass != null) { r.intelamt.pass = 1; }; // Remove the Intel AMT administrator password from the node