From eb1e175839f6ae0f1942fac8aa98cfa46ae4f95a Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Sun, 17 Dec 2023 16:52:58 +0200 Subject: [PATCH] luci-app-sshtunnel: extract a public key from a key if no .pub For the Dropbear keys without a .pub we need to fall back and execute the -y command to extract a pubkey from a private. Signed-off-by: Sergey Ponomarev (cherry picked from commit 8755aa3a71bf47ba65706a39c72cd294923d9285) --- .../resources/view/sshtunnel/ssh_keys.js | 57 +++++++++++++------ .../resources/view/sshtunnel/ssh_servers.js | 28 ++++----- 2 files changed, 52 insertions(+), 33 deletions(-) diff --git a/applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js b/applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js index 2c3ee7a53f..adaa103597 100644 --- a/applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js +++ b/applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_keys.js @@ -20,7 +20,7 @@ return view.extend({ for (var sshKeyName of sshKeyNames) { var sshPubKeyName = sshKeyName + '.pub'; tasks.push(Promise.resolve(sshKeyName)); - tasks.push(fs.lines('/root/.ssh/' + sshPubKeyName)); + tasks.push(_loadPublicKey(sshPubKeyName)); } return Promise.all(tasks); }); @@ -45,29 +45,25 @@ return view.extend({ }); function _findAllPossibleIdKeys(entries) { - var sshKeyNames = []; - for (var item of entries) { - if (item.type !== 'file') { - continue - } + var sshKeyNames = new Set(); + var fileNames = entries.filter(item => item.type === 'file').map(item => item.name); + for (var fileName of fileNames) { // a key file should have a corresponding .pub file - if (item.name.endsWith('.pub')) { - var sshPubKeyName = item.name; - var sshKeyName = sshPubKeyName.substring(0, sshPubKeyName.length - 4); - if (!sshKeyNames.includes(sshKeyName)) { - sshKeyNames.push(sshKeyName) + if (fileName.endsWith('.pub')) { + var sshKeyName = fileName.slice(0, -4); + // if such a key exists then add it + if (fileNames.includes(sshKeyName)) { + sshKeyNames.add(sshKeyName); } } else { // or at least it should start with id_ e.g. id_dropbear - if (item.name.startsWith('id_')) { - var sshKeyName = item.name; - if (!sshKeyNames.includes(sshKeyName)) { - sshKeyNames.push(sshKeyName) - } + if (fileName.startsWith('id_')) { + var sshKeyName = fileName; + sshKeyNames.add(sshKeyName); } } } - return sshKeyNames; + return Array.from(sshKeyNames); } function _splitSshKeys(sshFiles) { @@ -158,3 +154,30 @@ function _handleKeyGenSubmit(event) { }); return false; } + +function _extractPubKeyFromOutput(res) { + var lines = res.stdout.split('\n'); + for (var line of lines) { + if (line.startsWith('ssh-')) { + return line; + } + } + return ''; +} + +function _loadPublicKey(sshPubKeyName) { + return fs.read('/root/.ssh/' + sshPubKeyName) + .catch(() => { + // If there is no the .pub file then this is probably a Dropbear key e.g. id_dropbear. + // We can extract it's public key by executing: dropbearkey -y -f /root/.ssh/id_dropbear + var sshKeyName = sshPubKeyName.substring(0, sshPubKeyName.length - 4); + return fs.exec('/usr/bin/dropbearkey', ['-y', '-f', '/root/.ssh/' + sshKeyName]).then((res) => { + if (res.code === 0) { + return _extractPubKeyFromOutput(res); + } else { + console.log('dropbearkey: ' + res.stdout + ' ' + res.stderr); + return ''; + } + }).catch(()=> ''); + }); +} diff --git a/applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js b/applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js index e932806631..30b1b4fb30 100644 --- a/applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js +++ b/applications/luci-app-sshtunnel/htdocs/luci-static/resources/view/sshtunnel/ssh_servers.js @@ -129,27 +129,23 @@ return view.extend({ }); function _findAllPossibleIdKeys(entries) { - var sshKeyNames = []; - for (var item of entries) { - if (item.type !== 'file') { - continue - } + var sshKeyNames = new Set(); + var fileNames = entries.filter(item => item.type === 'file').map(item => item.name); + for (var fileName of fileNames) { // a key file should have a corresponding .pub file - if (item.name.endsWith('.pub')) { - var sshPubKeyName = item.name; - var sshKeyName = sshPubKeyName.substring(0, sshPubKeyName.length - 4); - if (!sshKeyNames.includes(sshKeyName)) { - sshKeyNames.push(sshKeyName) + if (fileName.endsWith('.pub')) { + var sshKeyName = fileName.slice(0, -4); + // if such a key exists then add it + if (fileNames.includes(sshKeyName)) { + sshKeyNames.add(sshKeyName); } } else { // or at least it should start with id_ e.g. id_dropbear - if (item.name.startsWith('id_')) { - var sshKeyName = item.name; - if (!sshKeyNames.includes(sshKeyName)) { - sshKeyNames.push(sshKeyName) - } + if (fileName.startsWith('id_')) { + var sshKeyName = fileName; + sshKeyNames.add(sshKeyName); } } } - return sshKeyNames; + return Array.from(sshKeyNames); } -- 2.30.2