From 9c52cc4d8c0eaef25796e1da86cac6fae43fc64c Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Thu, 19 May 2022 14:41:32 -0700 Subject: [PATCH] Web-SSH fixes and improvements. --- apprelays.js | 23 ++++++++++++----------- webserver.js | 22 +++++++++++++++------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/apprelays.js b/apprelays.js index 5c90564d..fb8e59c2 100644 --- a/apprelays.js +++ b/apprelays.js @@ -604,24 +604,24 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) { parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) { if ((err != null) || (nodes == null) || (nodes.length != 1)) return; const node = nodes[0]; - 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'))) { + if ((domain.allowsavingdevicecredentials === false) || (node.ssh == null) || (typeof node.ssh != 'object') || (node.ssh[obj.userid] == null) || (typeof node.ssh[obj.userid].u != 'string') || ((typeof node.ssh[obj.userid].p != 'string') && (typeof node.ssh[obj.userid].k != 'string'))) { // Send a request for SSH authentication try { ws.send(JSON.stringify({ action: 'sshauth' })) } catch (ex) { } - } else if ((domain.allowsavingdevicecredentials !== false) && (node.ssh != null) && (typeof node.ssh[user._id].k == 'string') && (node.ssh[user._id].kp == null)) { + } else if ((domain.allowsavingdevicecredentials !== false) && (node.ssh != null) && (typeof node.ssh[obj.userid].k == 'string') && (node.ssh[obj.userid].kp == null)) { // Send a request for SSH authentication with option for only the private key password - obj.username = node.ssh[user._id].u; - obj.privateKey = node.ssh[user._id].k; + obj.username = node.ssh[obj.userid].u; + obj.privateKey = node.ssh[obj.userid].k; try { ws.send(JSON.stringify({ action: 'sshauth', askkeypass: true })) } catch (ex) { } } else { // Use our existing credentials obj.termSize = msg; delete obj.keep; - obj.username = node.ssh[user._id].u; - if (typeof node.ssh[user._id].p == 'string') { - obj.password = node.ssh[user._id].p; - } else if (typeof node.ssh[user._id].k == 'string') { - obj.privateKey = node.ssh[user._id].k; - obj.privateKeyPass = node.ssh[user._id].kp; + obj.username = node.ssh[obj.userid].u; + if (typeof node.ssh[obj.userid].p == 'string') { + obj.password = node.ssh[obj.userid].p; + } else if (typeof node.ssh[obj.userid].k == 'string') { + obj.privateKey = node.ssh[obj.userid].k; + obj.privateKeyPass = node.ssh[obj.userid].kp; } startRelayConnection(); } @@ -686,7 +686,8 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) { // Decode the authentication cookie obj.cookie = parent.parent.decodeCookie(req.query.auth, parent.parent.loginCookieEncryptionKey); - if (obj.cookie == null) { obj.ws.send(JSON.stringify({ action: 'sessionerror' })); obj.close(); return; } + if ((obj.cookie == null) || (obj.cookie.userid == null) || (parent.users[obj.cookie.userid] == null)) { obj.ws.send(JSON.stringify({ action: 'sessionerror' })); obj.close(); return; } + obj.userid = obj.cookie.userid; // Get the meshid for this device parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) { diff --git a/webserver.js b/webserver.js index 6f606135..f54d7f31 100644 --- a/webserver.js +++ b/webserver.js @@ -6842,7 +6842,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } }); return; - } else if ((req.query.auth != null) && (req.query.auth != '')) { + } + + if ((req.query.auth != null) && (req.query.auth != '')) { // This is a encrypted cookie authentication var cookie = obj.parent.decodeCookie(req.query.auth, obj.parent.loginCookieEncryptionKey, 60); // Cookie with 1 hour timeout if ((cookie == null) && (obj.parent.multiServer != null)) { cookie = obj.parent.decodeCookie(req.query.auth, obj.parent.serverKey, 60); } // Try the server key @@ -6853,20 +6855,26 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if ((cookie != null) && (cookie.userid != null) && (obj.users[cookie.userid]) && (cookie.domainid == domain.id) && (cookie.userid.split('/')[1] == domain.id)) { // Valid cookie, we are authenticated. Cookie of format { userid: 'user//name', domain: '' } func(ws, req, domain, obj.users[cookie.userid], cookie); + return; } else if ((cookie != null) && (cookie.a === 3) && (typeof cookie.u == 'string') && (obj.users[cookie.u]) && (cookie.u.split('/')[1] == domain.id)) { // Valid cookie, we are authenticated. Cookie of format { u: 'user//name', a: 3 } func(ws, req, domain, obj.users[cookie.u], cookie); + return; } else if ((cookie != null) && (cookie.nouser === 1)) { // This is a valid cookie, but no user. This is used for agent self-sharing. func(ws, req, domain, null, cookie); - } else { + return; + } /*else { // This is a bad cookie, keep going anyway, maybe we have a active session that will save us. if ((cookie != null) && (cookie.domainid != domain.id)) { parent.debug('web', 'ERR: Invalid domain, got \"' + cookie.domainid + '\", expected \"' + domain.id + '\".'); } parent.debug('web', 'ERR: Websocket bad cookie auth (Cookie:' + (cookie != null) + '): ' + req.query.auth); try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'noauth-2b' })); ws.close(); } catch (e) { } + return; } - return; - } else if (req.headers['x-meshauth'] != null) { + */ + } + + if (req.headers['x-meshauth'] != null) { // This is authentication using a custom HTTP header var s = req.headers['x-meshauth'].split(','); for (var i in s) { s[i] = Buffer.from(s[i], 'base64').toString(); } @@ -6954,13 +6962,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF return; } - //console.log(req.headers['x-meshauth']); - if (obj.args.user && obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()]) { // A default user is active func(ws, req, domain, obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()]); return; - } else if (req.session && (req.session.userid != null) && (req.session.userid.split('/')[1] == domain.id) && (obj.users[req.session.userid])) { + } + + if (req.session && (req.session.userid != null) && (req.session.userid.split('/')[1] == domain.id) && (obj.users[req.session.userid])) { // This user is logged in using the ExpressJS session func(ws, req, domain, obj.users[req.session.userid]); return;