Added option to save SSH username and key without saving key password.
Ylian Saint-Hilaire committed
May 10, 2022 at 17:44 UTC
0d297088c896436af59feceefbc393292e9e1c4b
7 files changed
+328
-93
apprelays.js
+102
-23
@@ -447,9 +447,9 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
447
};
448
449
// Save SSH credentials into device
450
- function saveSshCredentials() {
451
- if (domain.allowsavingdevicecredentials == false) return;
452
- parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) {
450
+ function saveSshCredentials(keep) {
451
+ if (((keep != 1) && (keep != 2)) || (domain.allowsavingdevicecredentials == false)) return;
452
+ parent.parent.db.Get(obj.nodeid, function (err, nodes) {
453
if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
454
const node = nodes[0];
455
const changed = (node.ssh == null);
@@ -461,16 +461,17 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
461
if (obj.password != null) {
462
node.ssh = { u: obj.username, p: obj.password };
463
} else if (obj.privateKey != null) {
464
- node.ssh = { u: obj.username, k: obj.privateKey, kp: obj.privateKeyPass };
464
+ node.ssh = { u: obj.username, k: obj.privateKey };
465
+ if (keep == 2) { node.ssh.kp = obj.privateKeyPass; }
466
} else return;
467
parent.parent.db.Set(node);
468
469
// Event node change if needed
470
if (changed) {
471
// Event the node change
471
- const event = { etype: 'node', action: 'changenode', nodeid: obj.cookie.nodeid, domain: domain.id, userid: obj.cookie.userid, node: parent.CloneSafeNode(node), msg: "Changed SSH credentials" };
472
+ const event = { etype: 'node', action: 'changenode', nodeid: obj.nodeid, domain: domain.id, userid: obj.userid, node: parent.CloneSafeNode(node), msg: "Changed SSH credentials" };
473
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.
473
- parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(node.meshid, [obj.cookie.nodeid]), obj, event);
474
+ parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(node.meshid, [obj.nodeid]), obj, event);
475
}
476
});
477
}
@@ -498,7 +499,7 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
499
obj.sshClient = new Client();
500
obj.sshClient.on('ready', function () { // Authentication was successful.
501
// If requested, save the credentials
501
- if (obj.keep === true) saveSshCredentials();
502
+ saveSshCredentials(obj.keep);
503
obj.sessionid = Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64');
504
obj.startTime = Date.now();
505
@@ -590,10 +591,15 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
591
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'))) {
592
// Send a request for SSH authentication
593
try { ws.send(JSON.stringify({ action: 'sshauth' })) } catch (ex) { }
594
+ } else if ((domain.allowsavingdevicecredentials !== false) && (node.ssh != null) && (typeof node.ssh.k == 'string') && (node.ssh.kp == null)) {
595
+ // Send a request for SSH authentication with option for only the private key password
596
+ obj.username = node.ssh.u;
597
+ obj.privateKey = node.ssh.k;
598
+ try { ws.send(JSON.stringify({ action: 'sshauth', askkeypass: true })) } catch (ex) { }
599
} else {
600
// Use our existing credentials
601
obj.termSize = msg;
596
- obj.keep = false;
602
+ delete obj.keep;
603
obj.username = node.ssh.u;
604
if (typeof node.ssh.p == 'string') {
605
obj.password = node.ssh.p;
@@ -610,7 +616,8 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
616
if ((typeof msg.rows != 'number') || (typeof msg.cols != 'number') || (typeof msg.height != 'number') || (typeof msg.width != 'number')) break;
617
618
obj.termSize = msg;
613
- obj.keep = msg.keep; // If true, keep store credentials on the server if the SSH tunnel connected succesfully.
619
+ if (msg.keep === true) { msg.keep = 1; } // If true, change to 1. For user/pass, 1 to store user/pass in db. For user/key/pass, 1 to store user/key in db, 2 to store everything in db.
620
+ obj.keep = msg.keep; // If set, keep store credentials on the server if the SSH tunnel connected succesfully.
621
obj.username = msg.username;
622
obj.password = msg.password;
623
obj.privateKey = msg.key;
@@ -619,6 +626,24 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
626
}
627
break;
628
}
629
+ case 'connectKeyPass': {
630
+ // Verify inputs
631
+ if (typeof msg.keypass != 'string') break;
632
+
633
+ // Check if we have SSH credentials for this device
634
+ obj.privateKeyPass = msg.keypass;
635
+ obj.termSize = msg;
636
+ parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) {
637
+ if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
638
+ const node = nodes[0];
639
+ if (node.ssh != null) {
640
+ obj.username = node.ssh.u;
641
+ obj.privateKey = node.ssh.k;
642
+ startRelayConnection();
643
+ }
644
+ });
645
+ break;
646
+ }
647
case 'resize': {
648
// Verify inputs
649
if ((typeof msg.rows != 'number') || (typeof msg.cols != 'number') || (typeof msg.height != 'number') || (typeof msg.width != 'number')) break;
@@ -752,8 +777,8 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
777
};
778
779
// Save SSH credentials into device
755
- function saveSshCredentials() {
756
- if (domain.allowsavingdevicecredentials == false) return;
780
+ function saveSshCredentials(keep) {
781
+ if (((keep != 1) && (keep != 2)) || (domain.allowsavingdevicecredentials == false)) return;
782
parent.parent.db.Get(obj.nodeid, function (err, nodes) {
783
if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
784
const node = nodes[0];
@@ -766,8 +791,9 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
791
if (obj.password != null) {
792
node.ssh = { u: obj.username, p: obj.password };
793
} else if (obj.privateKey != null) {
769
- node.ssh = { u: obj.username, k: obj.privateKey, kp: obj.privateKeyPass };
770
- }
794
+ node.ssh = { u: obj.username, k: obj.privateKey };
795
+ if (keep == 2) { node.ssh.kp = obj.privateKeyPass; }
796
+ } else return;
797
parent.parent.db.Set(node);
798
799
// Event node change if needed
@@ -803,7 +829,7 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
829
obj.sshClient = new Client();
830
obj.sshClient.on('ready', function () { // Authentication was successful.
831
// If requested, save the credentials
806
- if (obj.keep === true) saveSshCredentials();
832
+ saveSshCredentials(obj.keep);
833
obj.sessionid = Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64');
834
obj.startTime = Date.now();
835
@@ -848,7 +874,7 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
874
obj.relayActive = false;
875
delete obj.sshClient;
876
delete obj.ser.forwardwrite;
851
- try { ws.send(JSON.stringify({ action: 'sshauth' })) } catch (ex) { }
877
+ try { ws.send(JSON.stringify({ action: 'sshauth', askkeypass: ((obj.username != null) && (obj.privateKey != null)) })) } catch (ex) { }
878
}
879
880
// We are all set, start receiving data
@@ -894,7 +920,8 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
920
if ((typeof msg.username != 'string') || ((typeof msg.password != 'string') && (typeof msg.key != 'string'))) break;
921
if ((typeof msg.rows != 'number') || (typeof msg.cols != 'number') || (typeof msg.height != 'number') || (typeof msg.width != 'number')) break;
922
897
- obj.keep = msg.keep; // If true, keep store credentials on the server if the SSH tunnel connected succesfully.
923
+ if (msg.keep === true) { msg.keep = 1; } // If true, change to 1. For user/pass, 1 to store user/pass in db. For user/key/pass, 1 to store user/key in db, 2 to store everything in db.
924
+ obj.keep = msg.keep; // If set, keep store credentials on the server if the SSH tunnel connected succesfully.
925
obj.termSize = msg;
926
obj.username = msg.username;
927
obj.password = msg.password;
@@ -912,6 +939,26 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
939
startRelayConnection(parent.parent.encodeCookie(cookieContent, parent.parent.loginCookieEncryptionKey));
940
break;
941
}
942
+ case 'sshkeyauth': {
943
+ // Verify inputs
944
+ if (typeof msg.keypass != 'string') break;
945
+ if ((typeof msg.rows != 'number') || (typeof msg.cols != 'number') || (typeof msg.height != 'number') || (typeof msg.width != 'number')) break;
946
+
947
+ delete obj.keep;
948
+ obj.termSize = msg;
949
+ obj.privateKeyPass = msg.keypass;
950
+
951
+ // Create a mesh relay authentication cookie
952
+ const cookieContent = { userid: user._id, domainid: user.domain, nodeid: obj.nodeid, tcpport: obj.tcpport };
953
+ if (obj.relaynodeid) {
954
+ cookieContent.nodeid = obj.relaynodeid;
955
+ cookieContent.tcpaddr = obj.tcpaddr;
956
+ } else {
957
+ if (obj.mtype == 3) { cookieContent.lc = 1; } // This is a local device
958
+ }
959
+ startRelayConnection(parent.parent.encodeCookie(cookieContent, parent.parent.loginCookieEncryptionKey));
960
+ break;
961
+ }
962
case 'sshautoauth': {
963
// Verify inputs
964
if ((typeof msg.rows != 'number') || (typeof msg.cols != 'number') || (typeof msg.height != 'number') || (typeof msg.width != 'number')) break;
@@ -984,6 +1031,11 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
1031
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'))) {
1032
// Send a request for SSH authentication
1033
try { ws.send(JSON.stringify({ action: 'sshauth' })) } catch (ex) { }
1034
+ } else if ((typeof node.ssh.k == 'string') && (typeof node.ssh.kp != 'string')) {
1035
+ // Send a request for SSH authentication with option for only the private key password
1036
+ obj.username = node.ssh.u;
1037
+ obj.privateKey = node.ssh.k;
1038
+ try { ws.send(JSON.stringify({ action: 'sshauth', askkeypass: true })) } catch (ex) { }
1039
} else {
1040
// Use our existing credentials
1041
obj.username = node.ssh.u;
@@ -1071,8 +1123,8 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
1123
};
1124
1125
// Save SSH credentials into device
1074
- function saveSshCredentials() {
1075
- if (domain.allowsavingdevicecredentials == false) return;
1126
+ function saveSshCredentials(keep) {
1127
+ if (((keep != 1) && (keep != 2)) || (domain.allowsavingdevicecredentials == false)) return;
1128
parent.parent.db.Get(obj.nodeid, function (err, nodes) {
1129
if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
1130
const node = nodes[0];
@@ -1085,8 +1137,9 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
1137
if (obj.password != null) {
1138
node.ssh = { u: obj.username, p: obj.password };
1139
} else if (obj.privateKey != null) {
1088
- node.ssh = { u: obj.username, k: obj.privateKey, kp: obj.privateKeyPass };
1089
- }
1140
+ node.ssh = { u: obj.username, k: obj.privateKey };
1141
+ if (keep == 2) { node.ssh.kp = obj.privateKeyPass; }
1142
+ } else return;
1143
parent.parent.db.Set(node);
1144
1145
// Event node change if needed
@@ -1122,7 +1175,7 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
1175
obj.sshClient = new Client();
1176
obj.sshClient.on('ready', function () { // Authentication was successful.
1177
// If requested, save the credentials
1125
- if (obj.keep === true) saveSshCredentials();
1178
+ saveSshCredentials(obj.keep);
1179
obj.sessionid = Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64');
1180
obj.startTime = Date.now();
1181
@@ -1161,7 +1214,7 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
1214
obj.relayActive = false;
1215
delete obj.sshClient;
1216
delete obj.ser.forwardwrite;
1164
- try { ws.send(JSON.stringify({ action: 'sshauth' })) } catch (ex) { }
1217
+ try { ws.send(JSON.stringify({ action: 'sshauth', askkeypass: ((obj.username != null) && (obj.privateKey != null)) })) } catch (ex) { }
1218
}
1219
1220
// We are all set, start receiving data
@@ -1390,12 +1443,33 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
1443
// Verify inputs
1444
if ((typeof msg.username != 'string') || ((typeof msg.password != 'string') && (typeof msg.key != 'string'))) break;
1445
1393
- obj.keep = (msg.keep === true); // If true, keep store credentials on the server if the SSH tunnel connected succesfully.
1446
+ if (msg.keep === true) { msg.keep = 1; } // If true, change to 1. For user/pass, 1 to store user/pass in db. For user/key/pass, 1 to store user/key in db, 2 to store everything in db.
1447
+ obj.keep = msg.keep; // If set, keep store credentials on the server if the SSH tunnel connected succesfully.
1448
obj.username = msg.username;
1449
obj.password = msg.password;
1450
obj.privateKey = msg.key;
1451
obj.privateKeyPass = msg.keypass;
1452
1453
+ // Create a mesh relay authentication cookie
1454
+ const cookieContent = { userid: user._id, domainid: user.domain, nodeid: obj.nodeid, tcpport: obj.tcpport };
1455
+ if (obj.relaynodeid) {
1456
+ cookieContent.nodeid = obj.relaynodeid;
1457
+ cookieContent.tcpaddr = obj.tcpaddr;
1458
+ } else {
1459
+ if (obj.mtype == 3) { cookieContent.lc = 1; } // This is a local device
1460
+ }
1461
+ startRelayConnection(parent.parent.encodeCookie(cookieContent, parent.parent.loginCookieEncryptionKey));
1462
+ break;
1463
+ }
1464
+ case 'sshkeyauth': {
1465
+ if (obj.sshClient != null) return;
1466
+
1467
+ // Verify inputs
1468
+ if (typeof msg.keypass != 'string') break;
1469
+
1470
+ delete obj.keep;
1471
+ obj.privateKeyPass = msg.keypass;
1472
+
1473
// Create a mesh relay authentication cookie
1474
const cookieContent = { userid: user._id, domainid: user.domain, nodeid: obj.nodeid, tcpport: obj.tcpport };
1475
if (obj.relaynodeid) {
@@ -1479,6 +1553,11 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
1553
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'))) {
1554
// Send a request for SSH authentication
1555
try { ws.send(JSON.stringify({ action: 'sshauth' })) } catch (ex) { }
1556
+ } else if ((typeof node.ssh.k == 'string') && (typeof node.ssh.kp != 'string')) {
1557
+ // Send a request for SSH authentication with option for only the private key password
1558
+ obj.username = node.ssh.u;
1559
+ obj.privateKey = node.ssh.k;
1560
+ try { ws.send(JSON.stringify({ action: 'sshauth', askkeypass: true })) } catch (ex) { }
1561
} else {
1562
// Use our existing credentials
1563
obj.username = node.ssh.u;
meshuser.js
+10
-1
@@ -729,7 +729,16 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
729
if (docs[i].pmt != null) { docs[i].pmt = 1; }
730
731
// Remove SSH credentials if present
732
- if (docs[i].ssh != null) { docs[i].ssh = (docs[i].ssh.k) ? 2 : 1; }
732
+ 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
737
+ else { delete docs[i].ssh; }
738
+ } else {
739
+ delete docs[i].ssh;
740
+ }
741
+ }
742
743
// Remove RDP credentials if present
744
if (docs[i].rdp != null) { docs[i].rdp = 1; }
views/default-mobile.handlebars
+99
-4
@@ -3528,10 +3528,10 @@
3528
if ((node.ssh != null) || (node.rdp != null)) {
3529
var y = [];
3530
if ((meshrights & 4) != 0) {
3531
- if (node.ssh != null) { y.push('<span onclick=showClearSshDialog(3) style=cursor:pointer>' + ((node.ssh == 2) ? "SSH-Key" : "SSH") + ' <img class=hoverButton src="images/link5.png" width=10 height=10 /></span>'); }
3531
+ if (node.ssh != null) { y.push('<span onclick=showClearSshDialog(3) style=cursor:pointer>' + ((node.ssh == 1) ? "SSH-User+Pass" : ((node.ssh == 2) ? "SSH-User+Key+Pass" : "SSH-User+Key")) + ' <img class=hoverButton src="images/link5.png" width=10 height=10 /></span>'); }
3532
if (node.rdp != null) { y.push('<span onclick=showClearRdpDialog(3) style=cursor:pointer>' + "RDP" + ' <img class=hoverButton src="images/link5.png" width=10 height=10 /></span>'); }
3533
} else {
3534
- if (node.ssh != null) { y.push(((node.ssh == 2) ? "SSH-Key" : "SSH")); }
3534
+ if (node.ssh != null) { y.push(((node.ssh == 1) ? "SSH-User+Pass" : ((node.ssh == 2) ? "SSH-User+Key+Pass" : "SSH-User+Key"))); }
3535
if (node.rdp != null) { y.push("RDP"); }
3536
}
3537
x += addDeviceAttribute("Credentials", y.join(', '));
@@ -4750,12 +4750,46 @@
4750
4751
function tunnelUpdate(data) { if (typeof data == 'string') { xterm.writeUtf8(data); } else { xterm.writeUtf8(new Uint8Array(data)); } }
4752
4753
+ function sshTunnelAuthDialog(j, func) {
4754
+ var x = '';
4755
+ if (j.askkeypass) {
4756
+ x += addHtmlValue("Authentication", '<select id=dp2authmethod style=width:150px onchange=sshAuthUpdate(event)><option value=3 selected>' + "Stored Key" + '</option><option value=1>' + "Username & Password" + '</option><option value=2>' + "Username and Key" + '</option></select>');
4757
+ } else {
4758
+ x += addHtmlValue("Authentication", '<select id=dp2authmethod style=width:150px onchange=sshAuthUpdate(event)><option value=1 selected>' + "Username & Password" + '</option><option value=2>' + "Username and Key" + '</option></select>');
4759
+ }
4760
+ x += '<div id=d2userauth style=display:none>';
4761
+ x += addHtmlValue("Username", '<input id=dp2user style=width:150px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
4762
+ x += '</div>';
4763
+ x += '<div id=d2passauth style=display:none>';
4764
+ x += addHtmlValue("Password", '<input type=password id=dp2pass style=width:150px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
4765
+ if ((features2 & 0x00400000) == 0) { x += '<label><input id=dp2keep type=checkbox>' + "Remember credentials" + '</label>'; }
4766
+ x += '</div><div id=d2keyauth style=display:none>';
4767
+ x += addHtmlValue("Key File", '<input type=file id=dp2key style=width:150px maxlength=64 autocomplete=off onchange=sshAuthUpdate(event) />' + '<div id=d2badkey style=font-size:x-small>' + "Key file must be in OpenSSH format." + '</div>');
4768
+ x += addHtmlValue("Key Password", '<input type=password id=dp2keypass style=width:150px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
4769
+ if ((features2 & 0x00400000) == 0) {
4770
+ x += '<label><input id=dp2keep1 type=checkbox onchange=sshAuthUpdate(event)>' + "Remember user & key" + '</label><br/>';
4771
+ x += '<label><input id=dp2keep2 type=checkbox>' + "Remember password" + '</label>';
4772
+ }
4773
+ x += '</div>';
4774
+ if (j.askkeypass) {
4775
+ x += '<div id=d2keyauth2 style=display:none>';
4776
+ x += addHtmlValue("Password", '<input type=password id=dp2keypass2 style=width:150px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
4777
+ x += '</div>';
4778
+ }
4779
+ setDialogMode(2, "Authentication", 11, func, x, 'ssh');
4780
+ Q('dp2user').focus();
4781
+ sshAuthUpdate();
4782
+ setTimeout(sshAuthUpdate, 50);
4783
+ }
4784
+
4785
function sshTunnelUpdate(data) {
4786
if (typeof data == 'string') {
4787
if (data[0] == '{') {
4788
var j = JSON.parse(data);
4789
switch (j.action) {
4790
case 'sshauth': {
4791
+ sshTunnelAuthDialog(j, sshConnectEx);
4792
+ /*
4793
var x = '';
4794
x += addHtmlValue("Authentication", '<select id=dp2authmethod style=width:150px onchange=sshAuthUpdate(event)><option value=1 selected>' + "Username & Password" + '</option><option value=2>' + "Username and Key" + '</option></select>')
4795
x += addHtmlValue("Username", '<input id=dp2user style=width:150px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
@@ -4769,6 +4803,7 @@
4803
x += '<div id=d2keyauth2 style=font-size:x-small><br />' + "Key file must be in OpenSSH format." + '</div>';
4804
setDialogMode(2, "Authentication", 11, sshConnectEx, x, 'ssh');
4805
setTimeout(sshAuthUpdate, 50);
4806
+ */
4807
break;
4808
}
4809
case 'sshautoauth': {
@@ -4783,6 +4818,7 @@
4818
}
4819
}
4820
4821
+ /*
4822
function sshAuthUpdate(e) {
4823
QV('d2passauth', Q('dp2authmethod').value == 1);
4824
QV('d2keyauth', Q('dp2authmethod').value == 2);
@@ -4815,6 +4851,57 @@
4851
}
4852
}
4853
}
4854
+ */
4855
+
4856
+ function sshAuthUpdate(e) {
4857
+ QV('d2userauth', Q('dp2authmethod').value != 3);
4858
+ QV('d2passauth', Q('dp2authmethod').value == 1);
4859
+ QV('d2keyauth', Q('dp2authmethod').value == 2);
4860
+ QV('d2keyauth2', Q('dp2authmethod').value == 3);
4861
+ if (Q('dp2authmethod').value == 1) {
4862
+ QE('idx_dlgOkButton', (Q('dp2user').value.length > 0) && (Q('dp2pass').value.length > 0));
4863
+ } else if (Q('dp2authmethod').value == 3) {
4864
+ QE('idx_dlgOkButton', Q('dp2keypass2').value.length > 0);
4865
+ } else {
4866
+ QE('idx_dlgOkButton', false);
4867
+ if ((features2 & 0x00400000) == 0) { QE('dp2keep2', Q('dp2keep1').checked); }
4868
+ var ok = (Q('dp2user').value.length > 0) && (Q('dp2key').files != null) && (Q('dp2key').files.length == 1) && (Q('dp2key').files[0].size < 8000);
4869
+ if (ok == true) {
4870
+ var reader = new FileReader();
4871
+ reader.onload = function (e) {
4872
+ var validkey = ((e.target.result.indexOf('-----BEGIN OPENSSH PRIVATE KEY-----') >= 0) && (e.target.result.indexOf('-----END OPENSSH PRIVATE KEY-----') >= 0));
4873
+ QE('idx_dlgOkButton', validkey);
4874
+ QS('d2badkey')['color'] = validkey ? '#000' : '#F00';
4875
+ }
4876
+ reader.readAsText(Q('dp2key').files[0]);
4877
+ }
4878
+ }
4879
+
4880
+ // When the enter key is pressed, move to the next field
4881
+ if (e && (e.keyCode == 13) && (e.target) && (Q('dp2authmethod').value == 1)) {
4882
+ if (e.target.id == 'dp2user') { Q('dp2pass').focus(); }
4883
+ if (e.target.id == 'dp2pass') { dialogclose(1); }
4884
+ }
4885
+ }
4886
+
4887
+ function sshConnectEx(b) {
4888
+ if (b == 0) {
4889
+ if (terminal != null) { connectTerminal(); } // Disconnect
4890
+ } else {
4891
+ var keep = 0;
4892
+ if (Q('dp2authmethod').value == 1) {
4893
+ if ((features2 & 0x00400000) == 0) { keep = (Q('dp2keep').checked ? 1 : 0); }
4894
+ 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 }));
4895
+ } else if (Q('dp2authmethod').value == 3) {
4896
+ terminal.socket.send(JSON.stringify({ action: 'sshkeyauth', keypass: Q('dp2keypass2').value, cols: xterm.cols, rows: xterm.rows, width: Q('termarea3xdiv').offsetWidth, height: Q('termarea3xdiv').offsetHeight }));
4897
+ } else {
4898
+ if ((features2 & 0x00400000) == 0) { keep = (Q('dp2keep1').checked ? 1 : 0); if (keep == 1) { keep += (Q('dp2keep2').checked ? 1 : 0); } } // Keep: 1 = user & key, 2 = User, key and password
4899
+ var reader = new FileReader(), username = Q('dp2user').value, keypass = Q('dp2keypass').value;
4900
+ 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 })); }
4901
+ reader.readAsText(Q('dp2key').files[0]);
4902
+ }
4903
+ }
4904
+ }
4905
4906
// Send the new terminal size to the agent
4907
function xTermSendResize() {
@@ -5035,6 +5122,8 @@
5122
// Process any SSH actions
5123
switch (data.action) {
5124
case 'sshauth': {
5125
+ sshTunnelAuthDialog(data, p13sshConnectEx);
5126
+ /*
5127
var x = '';
5128
x += addHtmlValue("Authentication", '<select id=dp2authmethod style=width:150px onchange=sshAuthUpdate(event)><option value=1 selected>' + "Username & Password" + '</option><option value=2>' + "Username and Key" + '</option></select>')
5129
x += addHtmlValue("Username", '<input id=dp2user style=width:150px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
@@ -5048,6 +5137,7 @@
5137
x += '<div id=d2keyauth2 style=font-size:x-small><br />' + "Key file must be in OpenSSH format." + '</div>';
5138
setDialogMode(2, "Authentication", 11, p13sshConnectEx, x, 'ssh');
5139
setTimeout(sshAuthUpdate, 50);
5140
+ */
5141
break;
5142
}
5143
case 'autherror': { p13setConsoleMsg("Authentication Error", 5000); return; }
@@ -5088,10 +5178,15 @@
5178
if (b == 0) {
5179
if (files != null) { connectFiles(); } // Disconnect
5180
} else {
5181
+ var keep = 0;
5182
if (Q('dp2authmethod').value == 1) {
5092
- files.socket.send(JSON.stringify({ action: 'sshauth', username: Q('dp2user').value, password: Q('dp2pass').value, keep: Q('dp2keep').checked }));
5183
+ if ((features2 & 0x00400000) == 0) { keep = (Q('dp2keep').checked ? 1 : 0); }
5184
+ files.socket.send(JSON.stringify({ action: 'sshauth', username: Q('dp2user').value, password: Q('dp2pass').value, keep: keep }));
5185
+ } else if (Q('dp2authmethod').value == 3) {
5186
+ files.socket.send(JSON.stringify({ action: 'sshkeyauth', keypass: Q('dp2keypass2').value }));
5187
} else {
5094
- var reader = new FileReader(), username = Q('dp2user').value, keypass = Q('dp2keypass').value, keep = Q('dp2keep').checked;
5188
+ if ((features2 & 0x00400000) == 0) { keep = (Q('dp2keep1').checked ? 1 : 0); if (keep == 1) { keep += (Q('dp2keep2').checked ? 1 : 0); } } // Keep: 1 = user & key, 2 = User, key and password
5189
+ var reader = new FileReader(), username = Q('dp2user').value, keypass = Q('dp2keypass').value;
5190
reader.onload = function (e) { files.socket.send(JSON.stringify({ action: 'sshauth', username: username, keypass: keypass, key: e.target.result, keep: keep })); }
5191
reader.readAsText(Q('dp2key').files[0]);
5192
}
views/default.handlebars
+51
-36
@@ -7007,10 +7007,10 @@
7007
if ((node.ssh != null) || (node.rdp != null)) {
7008
var y = [];
7009
if ((meshrights & 4) != 0) {
7010
- if (node.ssh != null) { y.push('<span onclick=showClearSshDialog(3) style=cursor:pointer>' + ((node.ssh == 2)?"SSH-Key":"SSH") + ' <img class=hoverButton src="images/link5.png" width=10 height=10 /></span>'); }
7010
+ if (node.ssh != null) { y.push('<span onclick=showClearSshDialog(3) style=cursor:pointer>' + ((node.ssh == 1)?"SSH-User+Pass":((node.ssh == 2)?"SSH-User+Key+Pass":"SSH-User+Key")) + ' <img class=hoverButton src="images/link5.png" width=10 height=10 /></span>'); }
7011
if (node.rdp != null) { y.push('<span onclick=showClearRdpDialog(3) style=cursor:pointer>' + "RDP" + ' <img class=hoverButton src="images/link5.png" width=10 height=10 /></span>'); }
7012
} else {
7013
- if (node.ssh != null) { y.push(((node.ssh == 2)?"SSH-Key":"SSH")); }
7013
+ if (node.ssh != null) { y.push(((node.ssh == 1)?"SSH-User+Pass":((node.ssh == 2)?"SSH-User+Key+Pass":"SSH-User+Key"))); }
7014
if (node.rdp != null) { y.push("RDP"); }
7015
}
7016
x += addDeviceAttribute("Credentials", y.join(', '));
@@ -9660,25 +9660,45 @@
9660
9661
function tunnelUpdate(data) { if (typeof data == 'string') { xterm.writeUtf8(data); } else { xterm.writeUtf8(new Uint8Array(data)); } }
9662
9663
+ function sshTunnelAuthDialog(j, func) {
9664
+ var x = '';
9665
+ if (j.askkeypass) {
9666
+ x += addHtmlValue("Authentication", '<select id=dp2authmethod style=width:230px onchange=sshAuthUpdate(event)><option value=3 selected>' + "Stored Key" + '</option><option value=1>' + "Username & Password" + '</option><option value=2>' + "Username and Key" + '</option></select>');
9667
+ } else {
9668
+ x += addHtmlValue("Authentication", '<select id=dp2authmethod style=width:230px onchange=sshAuthUpdate(event)><option value=1 selected>' + "Username & Password" + '</option><option value=2>' + "Username and Key" + '</option></select>');
9669
+ }
9670
+ x += '<div id=d2userauth style=display:none>';
9671
+ x += addHtmlValue("Username", '<input id=dp2user style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
9672
+ x += '</div>';
9673
+ x += '<div id=d2passauth style=display:none>';
9674
+ x += addHtmlValue("Password", '<input type=password id=dp2pass style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
9675
+ if ((features2 & 0x00400000) == 0) { x += addHtmlValue('', '<label><input id=dp2keep type=checkbox>' + "Remember credentials" + '</label>'); }
9676
+ x += '</div><div id=d2keyauth style=display:none>';
9677
+ 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>');
9678
+ x += addHtmlValue("Key Password", '<input type=password id=dp2keypass style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
9679
+ if ((features2 & 0x00400000) == 0) {
9680
+ x += addHtmlValue('', '<label><input id=dp2keep1 type=checkbox onchange=sshAuthUpdate(event)>' + "Remember user & key" + '</label>');
9681
+ x += addHtmlValue('', '<label><input id=dp2keep2 type=checkbox>' + "Remember password" + '</label>');
9682
+ }
9683
+ x += '</div>';
9684
+ if (j.askkeypass) {
9685
+ x += '<div id=d2keyauth2 style=display:none>';
9686
+ x += addHtmlValue("Password", '<input type=password id=dp2keypass2 style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
9687
+ x += '</div>';
9688
+ }
9689
+ setDialogMode(2, "Authentication", 11, func, x, 'ssh');
9690
+ Q('dp2user').focus();
9691
+ sshAuthUpdate();
9692
+ setTimeout(sshAuthUpdate, 50);
9693
+ }
9694
+
9695
function sshTunnelUpdate(data) {
9696
if (typeof data == 'string') {
9697
if (data[0] == '{') {
9698
var j = JSON.parse(data);
9699
switch (j.action) {
9700
case 'sshauth': {
9669
- var x = '';
9670
- x += addHtmlValue("Authentication", '<select id=dp2authmethod style=width:230px onchange=sshAuthUpdate(event)><option value=1 selected>' + "Username & Password" + '</option><option value=2>' + "Username and Key" + '</option></select>')
9671
- x += addHtmlValue("Username", '<input id=dp2user style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
9672
- x += '<div id=d2passauth>';
9673
- x += addHtmlValue("Password", '<input type=password id=dp2pass style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
9674
- x += '</div><div id=d2keyauth style=display:none>';
9675
- 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>');
9676
- x += addHtmlValue("Key Password", '<input type=password id=dp2keypass style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
9677
- x += '</div>';
9678
- if ((features2 & 0x00400000) == 0) { x += addHtmlValue('', '<label><input id=dp2keep type=checkbox>' + "Remember credentials" + '</label>'); }
9679
- setDialogMode(2, "Authentication", 11, sshConnectEx, x, 'ssh');
9680
- Q('dp2user').focus();
9681
- setTimeout(sshAuthUpdate, 50);
9701
+ sshTunnelAuthDialog(j, sshConnectEx);
9702
break;
9703
}
9704
case 'sshautoauth': {
@@ -9695,12 +9715,17 @@
9715
}
9716
9717
function sshAuthUpdate(e) {
9718
+ QV('d2userauth', Q('dp2authmethod').value != 3);
9719
QV('d2passauth', Q('dp2authmethod').value == 1);
9720
QV('d2keyauth', Q('dp2authmethod').value == 2);
9721
+ QV('d2keyauth2', Q('dp2authmethod').value == 3);
9722
if (Q('dp2authmethod').value == 1) {
9723
QE('idx_dlgOkButton', (Q('dp2user').value.length > 0) && (Q('dp2pass').value.length > 0));
9724
+ } else if (Q('dp2authmethod').value == 3) {
9725
+ QE('idx_dlgOkButton', Q('dp2keypass2').value.length > 0);
9726
} else {
9727
QE('idx_dlgOkButton', false);
9728
+ if ((features2 & 0x00400000) == 0) { QE('dp2keep2', Q('dp2keep1').checked); }
9729
var ok = (Q('dp2user').value.length > 0) && (Q('dp2key').files != null) && (Q('dp2key').files.length == 1) && (Q('dp2key').files[0].size < 8000);
9730
if (ok == true) {
9731
var reader = new FileReader();
@@ -9724,12 +9749,14 @@
9749
if (b == 0) {
9750
if (terminal != null) { connectTerminal(); } // Disconnect
9751
} else {
9727
- var keep = false;
9728
- if ((features2 & 0x00400000) == 0) { keep = Q('dp2keep').checked; }
9729
-
9752
+ var keep = 0;
9753
if (Q('dp2authmethod').value == 1) {
9754
+ if ((features2 & 0x00400000) == 0) { keep = (Q('dp2keep').checked ? 1 : 0); }
9755
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 }));
9756
+ } else if (Q('dp2authmethod').value == 3) {
9757
+ terminal.socket.send(JSON.stringify({ action: 'sshkeyauth', keypass: Q('dp2keypass2').value, cols: xterm.cols, rows: xterm.rows, width: Q('termarea3xdiv').offsetWidth, height: Q('termarea3xdiv').offsetHeight }));
9758
} else {
9759
+ if ((features2 & 0x00400000) == 0) { keep = (Q('dp2keep1').checked ? 1 : 0); if (keep == 1) { keep += (Q('dp2keep2').checked ? 1 : 0); } } // Keep: 1 = user & key, 2 = User, key and password
9760
var reader = new FileReader(), username = Q('dp2user').value, keypass = Q('dp2keypass').value;
9761
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 })); }
9762
reader.readAsText(Q('dp2key').files[0]);
@@ -10068,22 +10095,7 @@
10095
10096
// Process any SSH actions
10097
switch (data.action) {
10071
- case 'sshauth': {
10072
- var x = '';
10073
- x += addHtmlValue("Authentication", '<select id=dp2authmethod style=width:230px onchange=sshAuthUpdate(event)><option value=1 selected>' + "Username & Password" + '</option><option value=2>' + "Username and Key" + '</option></select>')
10074
- x += addHtmlValue("Username", '<input id=dp2user style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
10075
- x += '<div id=d2passauth>';
10076
- x += addHtmlValue("Password", '<input type=password id=dp2pass style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
10077
- x += '</div><div id=d2keyauth style=display:none>';
10078
- x += addHtmlValue("Key File", '<input type=file id=dp2key style=width:230px maxlength=64 autocomplete=off onchange=sshAuthUpdate(event) />');
10079
- x += addHtmlValue("Key Password", '<input type=password id=dp2keypass style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
10080
- x += '</div>';
10081
- if ((features2 & 0x00400000) == 0) { x += addHtmlValue('', '<label><input id=dp2keep type=checkbox>' + "Remember credentials" + '</label>'); }
10082
- setDialogMode(2, "Authentication", 11, p13sshConnectEx, x, 'ssh');
10083
- Q('dp2user').focus();
10084
- setTimeout(sshAuthUpdate, 50);
10085
- return;
10086
- }
10098
+ case 'sshauth': { sshTunnelAuthDialog(data, p13sshConnectEx); return; }
10099
case 'autherror': { p13setConsoleMsg("Authentication Error", 5000); return; }
10100
case 'connectionerror': { p13setConsoleMsg("Connection Error", 5000); return; }
10101
case 'sessionerror': { p13setConsoleMsg("Session expired", 5000); return; }
@@ -10136,11 +10148,14 @@
10148
if (b == 0) {
10149
if (files != null) { connectFiles(); } // Disconnect
10150
} else {
10139
- var keep = false;
10140
- if ((features2 & 0x00400000) == 0) { keep = Q('dp2keep').checked; }
10151
+ var keep = 0;
10152
if (Q('dp2authmethod').value == 1) {
10153
+ if ((features2 & 0x00400000) == 0) { keep = (Q('dp2keep').checked ? 1 : 0); }
10154
files.socket.send(JSON.stringify({ action: 'sshauth', username: Q('dp2user').value, password: Q('dp2pass').value, keep: keep }));
10155
+ } else if (Q('dp2authmethod').value == 3) {
10156
+ files.socket.send(JSON.stringify({ action: 'sshkeyauth', keypass: Q('dp2keypass2').value }));
10157
} else {
10158
+ if ((features2 & 0x00400000) == 0) { keep = (Q('dp2keep1').checked ? 1 : 0); if (keep == 1) { keep += (Q('dp2keep2').checked ? 1 : 0); } } // Keep: 1 = user & key, 2 = User, key and password
10159
var reader = new FileReader(), username = Q('dp2user').value, keypass = Q('dp2keypass').value;
10160
reader.onload = function (e) { files.socket.send(JSON.stringify({ action: 'sshauth', username: username, keypass: keypass, key: e.target.result, keep: keep })); }
10161
reader.readAsText(Q('dp2key').files[0]);
views/mstsc.handlebars
+2
-2
@@ -80,7 +80,7 @@
80
var urlargs = parseUriArgs();
81
if (urlargs.key && (isAlphaNumeric(urlargs.key) == false)) { delete urlargs.key; }
82
var cookie = '{{{cookie}}}';
83
- var serverCredentials = (decodeURIComponent('{{{serverCredentials}}}') == 'true');
83
+ var serverCredentials = parseInt('{{{serverCredentials}}}');
84
var name = decodeURIComponent('{{{name}}}');
85
if (name != '') { document.title = name + ' - ' + document.title; }
86
var features = parseInt('{{{features}}}');
@@ -97,7 +97,7 @@
97
QE('connectButton', false);
98
}
99
100
- if (serverCredentials == true) {
100
+ if (serverCredentials == 1) {
101
QV('dropdowndomain', true);
102
Q('d3coreMode').value = 1;
103
} else {
views/ssh.handlebars
+45
-20
@@ -130,12 +130,17 @@
130
}
131
132
function sshAuthUpdate(e) {
133
+ QV('d2userauth', Q('dp2authmethod').value != 3);
134
QV('d2passauth', Q('dp2authmethod').value == 1);
135
QV('d2keyauth', Q('dp2authmethod').value == 2);
136
+ QV('d2keyauth2', Q('dp2authmethod').value == 3);
137
if (Q('dp2authmethod').value == 1) {
138
QE('idx_dlgOkButton', (Q('dp2user').value.length > 0) && (Q('dp2pass').value.length > 0));
139
+ } else if (Q('dp2authmethod').value == 3) {
140
+ QE('idx_dlgOkButton', Q('dp2keypass2').value.length > 0);
141
} else {
142
QE('idx_dlgOkButton', false);
143
+ if ((features & 1) == 0) { QE('dp2keep2', Q('dp2keep1').checked); }
144
var ok = (Q('dp2user').value.length > 0) && (Q('dp2key').files != null) && (Q('dp2key').files.length == 1) && (Q('dp2key').files[0].size < 8000);
145
if (ok == true) {
146
var reader = new FileReader();
@@ -156,13 +161,18 @@
161
}
162
163
function connectEx() {
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; }
164
+ var cmd = { action: 'connect', cols: term.cols, rows: term.rows, width: Q('terminal').offsetWidth, height: Q('terminal').offsetHeight, username: Q('dp2user').value, keep: 0 };
165
166
if (Q('dp2authmethod').value == 1) {
167
cmd.password = Q('dp2pass').value;
168
+ if ((features & 1) == 0) { cmd.keep = Q('dp2keep').checked ? 1 : 0; }
169
+ connectEx2(cmd);
170
+ } else if (Q('dp2authmethod').value == 3) {
171
+ cmd.action = 'connectKeyPass';
172
+ cmd.keypass = Q('dp2keypass2').value;
173
connectEx2(cmd);
174
} else {
175
+ if ((features & 1) == 0) { cmd.keep = (Q('dp2keep1').checked ? 1 : 0); if (cmd.keep == 1) { cmd.keep += (Q('dp2keep2').checked ? 1 : 0); } } // Keep: 1 = user & key, 2 = User, key and password
176
cmd.keypass = Q('dp2keypass').value;
177
var reader = new FileReader();
178
reader.onload = function (e) { cmd.key = e.target.result; connectEx2(cmd); }
@@ -170,6 +180,38 @@
180
}
181
}
182
183
+ function sshTunnelAuthDialog(j, func) {
184
+ var x = '';
185
+ if (j.askkeypass) {
186
+ x += addHtmlValue("Authentication", '<select id=dp2authmethod style=width:230px onchange=sshAuthUpdate(event)><option value=3 selected>' + "Stored Key" + '</option><option value=1>' + "Username & Password" + '</option><option value=2>' + "Username and Key" + '</option></select>');
187
+ } else {
188
+ x += addHtmlValue("Authentication", '<select id=dp2authmethod style=width:230px onchange=sshAuthUpdate(event)><option value=1 selected>' + "Username & Password" + '</option><option value=2>' + "Username and Key" + '</option></select>');
189
+ }
190
+ x += '<div id=d2userauth style=display:none>';
191
+ x += addHtmlValue("Username", '<input id=dp2user style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
192
+ x += '</div>';
193
+ x += '<div id=d2passauth style=display:none>';
194
+ x += addHtmlValue("Password", '<input type=password id=dp2pass style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
195
+ if ((features & 1) == 0) { x += addHtmlValue('', '<label><input id=dp2keep type=checkbox>' + "Remember credentials" + '</label>'); }
196
+ x += '</div><div id=d2keyauth style=display:none>';
197
+ 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>');
198
+ x += addHtmlValue("Key Password", '<input type=password id=dp2keypass style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
199
+ if ((features & 1) == 0) {
200
+ x += addHtmlValue('', '<label><input id=dp2keep1 type=checkbox onchange=sshAuthUpdate(event)>' + "Remember user & key" + '</label>');
201
+ x += addHtmlValue('', '<label><input id=dp2keep2 type=checkbox>' + "Remember password" + '</label>');
202
+ }
203
+ x += '</div>';
204
+ if (j.askkeypass) {
205
+ x += '<div id=d2keyauth2 style=display:none>';
206
+ x += addHtmlValue("Password", '<input type=password id=dp2keypass2 style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
207
+ x += '</div>';
208
+ }
209
+ setDialogMode(2, "Authentication", 11, func, x, 'ssh');
210
+ Q('dp2user').focus();
211
+ sshAuthUpdate();
212
+ setTimeout(sshAuthUpdate, 50);
213
+ }
214
+
215
function connectEx2(cmd) {
216
state = 1;
217
var url = window.location.protocol.replace('http', 'ws') + '//' + window.location.host + domainurl + 'sshrelay.ashx?auth=' + cookie + (urlargs.key ? ('&key=' + urlargs.key) : '');
@@ -192,24 +234,7 @@
234
if ((json.ctrlChannel == 102938) && (json.type == 'ping')) { socket.send('{"ctrlChannel":"102938","type":"pong"}'); return; }
235
switch (json.action) {
236
case 'connected': { state = 3; updateState(); term.focus(); break; }
195
- case 'sshauth': {
196
- var x = '';
197
- x += addHtmlValue("Authentication", '<select id=dp2authmethod style=width:230px onchange=sshAuthUpdate(event)><option value=1 selected>' + "Username & Password" + '</option><option value=2>' + "Username and Key" + '</option></select>')
198
- x += addHtmlValue("Username", '<input id=dp2user style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
199
- x += '<div id=d2passauth>';
200
- x += addHtmlValue("Password", '<input type=password id=dp2pass style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
201
- x += '</div><div id=d2keyauth style=display:none>';
202
- 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>');
203
- x += addHtmlValue("Key Password", '<input type=password id=dp2keypass style=width:230px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
204
- x += '</div>';
205
- if ((features & 1) == 0) { x += addHtmlValue('', '<label><input id=dp2keep type=checkbox>' + "Remember credentials" + '</label>'); }
206
- setDialogMode(2, "Authentication", 3, connectEx, x);
207
- Q('dp2user').value = user;
208
- Q('dp2pass').value = pass;
209
- if (user == '') { Q('dp2user').focus(); } else { Q('dp2pass').focus(); }
210
- setTimeout(sshAuthUpdate, 50);
211
- break;
212
- }
237
+ case 'sshauth': { sshTunnelAuthDialog(json, connectEx); break; }
238
case 'autherror': { setDialogMode(2, "Authentication", 1, null, "Unable to authenticate."); break; }
239
case 'sessionerror': { setDialogMode(2, "Session", 1, null, "Session expired."); break; }
240
case 'sessiontimeout': { setDialogMode(2, "Session", 1, null, "Session timeout."); break; }
webserver.js
+19
-7
@@ -1962,13 +1962,15 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
1962
if ((err != null) || (nodes.length != 1)) { res.sendStatus(404); return; }
1963
const node = nodes[0];
1964
1965
- // Check if we have RDP credentials for this device
1966
- var serverCredentials = false;
1965
+ // Check if we have SSH/RDP credentials for this device
1966
+ var serverCredentials = 0;
1967
if (domain.allowsavingdevicecredentials !== false) {
1968
if (page == 'ssh') {
1969
- serverCredentials = ((typeof node.ssh == 'object') && (typeof node.ssh.u == 'string'))
1969
+ if ((typeof node.ssh == 'object') && (typeof node.ssh.u == 'string') && (typeof node.ssh.p == 'string')) { serverCredentials = 1; } // Username and password
1970
+ else if ((typeof node.ssh == 'object') && (typeof node.ssh.k == 'string') && (typeof node.ssh.kp == 'string')) { serverCredentials = 2; } // Username, key and password
1971
+ else if ((typeof node.ssh == 'object') && (typeof node.ssh.k == 'string')) { serverCredentials = 3; } // Username and key. No password.
1972
} else {
1971
- serverCredentials = ((typeof node.rdp == 'object') && (typeof node.rdp.d == 'string') && (typeof node.rdp.u == 'string') && (typeof node.rdp.p == 'string'))
1973
+ if ((typeof node.rdp == 'object') && (typeof node.rdp.d == 'string') && (typeof node.rdp.u == 'string') && (typeof node.rdp.p == 'string')) { serverCredentials = 1; } // Username and password
1974
}
1975
}
1976
@@ -2028,14 +2030,20 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
2030
if (typeof node.sshport == 'number') { port = node.sshport; }
2031
2032
// Check if we have SSH credentials for this device
2031
- if (domain.allowsavingdevicecredentials !== false) { serverCredentials = ((typeof node.ssh == 'object') && (typeof node.ssh.u == 'string')); }
2033
+ if (domain.allowsavingdevicecredentials !== false) {
2034
+ if ((typeof node.ssh == 'object') && (typeof node.ssh.u == 'string') && (typeof node.ssh.p == 'string')) { serverCredentials = 1; } // Username and password
2035
+ else if ((typeof node.ssh == 'object') && (typeof node.ssh.k == 'string') && (typeof node.ssh.kp == 'string')) { serverCredentials = 2; } // Username, key and password
2036
+ else if ((typeof node.ssh == 'object') && (typeof node.ssh.k == 'string')) { serverCredentials = 3; } // Username and key. No password.
2037
+ }
2038
} else {
2039
// RDP port
2040
port = 3389;
2041
if (typeof node.rdpport == 'number') { port = node.rdpport; }
2042
2043
// Check if we have RDP credentials for this device
2038
- if (domain.allowsavingdevicecredentials !== false) { serverCredentials = ((typeof node.rdp == 'object') && (typeof node.rdp.d == 'string') && (typeof node.rdp.u == 'string') && (typeof node.rdp.p == 'string')); }
2044
+ if (domain.allowsavingdevicecredentials !== false) {
2045
+ if ((typeof node.rdp == 'object') && (typeof node.rdp.d == 'string') && (typeof node.rdp.u == 'string') && (typeof node.rdp.p == 'string')) { serverCredentials = 1; } // Username and password
2046
+ }
2047
}
2048
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; } }
2049
@@ -7513,7 +7521,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
7521
if ((r.pmt != null) || (r.ssh != null) || (r.rdp != null) || ((r.intelamt != null) && ((r.intelamt.pass != null) || (r.intelamt.mpspass != null)))) {
7522
r = Object.assign({}, r); // Shallow clone
7523
if (r.pmt != null) { r.pmt = 1; }
7516
- if (r.ssh != null) { r.ssh = (r.ssh.k != null) ? 2 : 1; }
7524
+ if (r.ssh && r.ssh.u) {
7525
+ if (r.ssh.p) { r.ssh = 1; } // Username and password
7526
+ else if (r.ssh.k && r.ssh.kp) { r.ssh = 2; } // Username, key and password
7527
+ else if (r.ssh.k) { r.ssh = 3; } // Username and key. No password.
7528
+ }
7529
if (r.rdp != null) { r.rdp = 1; }
7530
if ((r.intelamt != null) && ((r.intelamt.pass != null) || (r.intelamt.mpspass != null))) {
7531
r.intelamt = Object.assign({}, r.intelamt); // Shallow clone