added private key export without password to client config

This commit is contained in:
vladimir.kuznetsov 2023-04-03 17:27:55 +03:00
parent f3aef67be6
commit 5e099f522e
10 changed files with 76 additions and 56 deletions

View file

@ -13,7 +13,6 @@ struct ServerCredentials
QString hostName; QString hostName;
QString userName; QString userName;
QString password; QString password;
QString decryptedPrivateKey;
int port = 22; int port = 22;
bool isValid() const { return !hostName.isEmpty() && !userName.isEmpty() && !password.isEmpty() && port > 0; } bool isValid() const { return !hostName.isEmpty() && !userName.isEmpty() && !password.isEmpty() && port > 0; }
@ -36,6 +35,7 @@ enum ErrorCode
// Ssh connection errors // Ssh connection errors
SshRequsetDeniedError, SshInterruptedError, SshInternalError, SshRequsetDeniedError, SshInterruptedError, SshInternalError,
SshPrivateKeyError,
// Ssh sftp errors // Ssh sftp errors
SshSftpEofError, SshSftpNoSuchFileError, SshSftpPermissionDeniedError, SshSftpEofError, SshSftpNoSuchFileError, SshSftpPermissionDeniedError,

View file

@ -21,6 +21,7 @@ QString errorString(ErrorCode code){
case(SshRequsetDeniedError): return QObject::tr("Ssh request was denied"); case(SshRequsetDeniedError): return QObject::tr("Ssh request was denied");
case(SshInterruptedError): return QObject::tr("Ssh request was interrupted"); case(SshInterruptedError): return QObject::tr("Ssh request was interrupted");
case(SshInternalError): return QObject::tr("Ssh internal error"); case(SshInternalError): return QObject::tr("Ssh internal error");
case(SshPrivateKeyError): return QObject::tr("Invalid private key or invalid passphrase entered");
// Libssh sftp errors // Libssh sftp errors
case(SshSftpEofError): return QObject::tr("Sftp error: End-of-file encountered"); case(SshSftpEofError): return QObject::tr("Sftp error: End-of-file encountered");

View file

@ -46,7 +46,7 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut, const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut,
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr) { const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr) {
auto error = m_sshClient.connectToHost(credentials, m_passphraseCallback); auto error = m_sshClient.connectToHost(credentials);
if (error != ErrorCode::NoError) { if (error != ErrorCode::NoError) {
return error; return error;
} }
@ -221,7 +221,7 @@ ErrorCode ServerController::checkOpenVpnServer(DockerContainer container, const
ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath, ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath,
libssh::SftpOverwriteMode overwriteMode) libssh::SftpOverwriteMode overwriteMode)
{ {
auto error = m_sshClient.connectToHost(credentials, m_passphraseCallback); auto error = m_sshClient.connectToHost(credentials);
if (error != ErrorCode::NoError) { if (error != ErrorCode::NoError) {
return error; return error;
} }
@ -757,5 +757,11 @@ ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredential
void ServerController::setPassphraseCallback(const std::function<QString()> &callback) void ServerController::setPassphraseCallback(const std::function<QString()> &callback)
{ {
m_passphraseCallback = callback; m_sshClient.setPassphraseCallback(callback);
}
ErrorCode ServerController::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey)
{
auto error = m_sshClient.getDecryptedPrivateKey(credentials, decryptedPrivateKey);
return error;
} }

View file

@ -74,6 +74,7 @@ public:
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap<DockerContainer, QJsonObject> &installedContainers); ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap<DockerContainer, QJsonObject> &installedContainers);
void setPassphraseCallback(const std::function<QString()> &callback); void setPassphraseCallback(const std::function<QString()> &callback);
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey);
private: private:
ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container); ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container);
ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject()); ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
@ -88,7 +89,6 @@ private:
bool m_cancelInstallation = false; bool m_cancelInstallation = false;
libssh::Client m_sshClient; libssh::Client m_sshClient;
std::function<QString()> m_passphraseCallback;
signals: signals:
void serverIsBusy(const bool isBusy); void serverIsBusy(const bool isBusy);
}; };

View file

@ -25,15 +25,8 @@ namespace libssh {
return 0; return 0;
} }
ErrorCode Client::connectToHost(const ServerCredentials &credentials, const std::function<QString()> &passphraseCallback) ErrorCode Client::connectToHost(const ServerCredentials &credentials)
{ {
// if (is_ssh_initialized()) {
// qDebug() << "Failed to initialize ssh";
// return ErrorCode::InternalError;
// }
m_passphraseCallback = passphraseCallback;
if (m_session == nullptr) { if (m_session == nullptr) {
m_session = ssh_new(); m_session = ssh_new();
@ -64,39 +57,20 @@ namespace libssh {
int authResult = SSH_ERROR; int authResult = SSH_ERROR;
if (credentials.password.contains("BEGIN") && credentials.password.contains("PRIVATE KEY")) { if (credentials.password.contains("BEGIN") && credentials.password.contains("PRIVATE KEY")) {
ssh_key privateKey; ssh_key privateKey;
authResult = ssh_pki_import_privkey_base64(credentials.password.toStdString().c_str(), nullptr, callback, nullptr, &privateKey);
if (authResult != SSH_OK) {
qDebug() << ssh_get_error(m_session);
return fromLibsshErrorCode(ssh_get_error_code(m_session));
}
ssh_key publicKey; ssh_key publicKey;
authResult = ssh_pki_export_privkey_to_pubkey(privateKey, &publicKey); authResult = ssh_pki_import_privkey_base64(credentials.password.toStdString().c_str(), nullptr, callback, nullptr, &privateKey);
if (authResult != SSH_OK) { if (authResult == SSH_OK) {
qDebug() << ssh_get_error(m_session); authResult = ssh_pki_export_privkey_to_pubkey(privateKey, &publicKey);
return fromLibsshErrorCode(ssh_get_error_code(m_session));
}
authResult = ssh_userauth_try_publickey(m_session, authUsername.c_str(), publicKey);
if (authResult != SSH_OK) {
qDebug() << ssh_get_error(m_session);
return fromLibsshErrorCode(ssh_get_error_code(m_session));
} }
authResult = ssh_userauth_publickey(m_session, authUsername.c_str(), privateKey); if (authResult == SSH_OK) {
if (authResult != SSH_OK) { authResult = ssh_userauth_try_publickey(m_session, authUsername.c_str(), publicKey);
qDebug() << ssh_get_error(m_session);
return fromLibsshErrorCode(ssh_get_error_code(m_session));
} }
char* key = new char[65535]; if (authResult == SSH_OK) {
authResult = ssh_pki_export_privkey_base64(privateKey, nullptr, nullptr, nullptr, &key); authResult = ssh_userauth_publickey(m_session, authUsername.c_str(), privateKey);
if (authResult != SSH_OK) {
qDebug() << ssh_get_error(m_session);
return fromLibsshErrorCode(ssh_get_error_code(m_session));
} }
// credentials.decryptedPrivateKey(key);
ssh_key_free(publicKey); ssh_key_free(publicKey);
ssh_key_free(privateKey); ssh_key_free(privateKey);
} else { } else {
@ -363,4 +337,35 @@ namespace libssh {
default: return ErrorCode::SshSftpFailureError; default: return ErrorCode::SshSftpFailureError;
} }
} }
ErrorCode Client::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey)
{
int authResult = SSH_ERROR;
ErrorCode errorCode = ErrorCode::NoError;
ssh_key privateKey;
authResult = ssh_pki_import_privkey_base64(credentials.password.toStdString().c_str(), nullptr, callback, nullptr, &privateKey);
if (authResult == SSH_OK) {
char* key = new char[65535];
authResult = ssh_pki_export_privkey_base64(privateKey, nullptr, nullptr, nullptr, &key);
decryptedPrivateKey = key;
delete[] key;
if (authResult != SSH_OK) {
qDebug() << "failed to export private key";
errorCode = ErrorCode::InternalError;
}
} else {
errorCode = ErrorCode::SshPrivateKeyError;
}
ssh_key_free(privateKey);
return errorCode;
}
void Client::setPassphraseCallback(const std::function<QString()> &callback)
{
m_passphraseCallback = callback;
}
} }

View file

@ -26,7 +26,7 @@ namespace libssh {
Client(QObject *parent = nullptr); Client(QObject *parent = nullptr);
~Client(); ~Client();
ErrorCode connectToHost(const ServerCredentials &credentials, const std::function<QString()> &passphraseCallback); ErrorCode connectToHost(const ServerCredentials &credentials);
void disconnectFromHost(); void disconnectFromHost();
ErrorCode executeCommand(const QString &data, ErrorCode executeCommand(const QString &data,
const std::function<ErrorCode (const QString &, Client &)> &cbReadStdOut, const std::function<ErrorCode (const QString &, Client &)> &cbReadStdOut,
@ -36,6 +36,8 @@ namespace libssh {
const std::string& localPath, const std::string& localPath,
const std::string& remotePath, const std::string& remotePath,
const std::string& fileDesc); const std::string& fileDesc);
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey);
void setPassphraseCallback(const std::function<QString()> &callback);
private: private:
ErrorCode closeChannel(); ErrorCode closeChannel();
ErrorCode closeSftpSession(); ErrorCode closeSftpSession();

View file

@ -165,6 +165,6 @@
<file>ui/qml/Controls/PopupWithQuestion.qml</file> <file>ui/qml/Controls/PopupWithQuestion.qml</file>
<file>ui/qml/Pages/PageAdvancedServerSettings.qml</file> <file>ui/qml/Pages/PageAdvancedServerSettings.qml</file>
<file>ui/qml/Controls/PopupWarning.qml</file> <file>ui/qml/Controls/PopupWarning.qml</file>
<file>ui/qml/Controls/PopupWithInputField.qml</file> <file>ui/qml/Controls/PopupWithTextField.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View file

@ -6,6 +6,7 @@
#include "configurators/vpn_configurator.h" #include "configurators/vpn_configurator.h"
#include "../uilogic.h" #include "../uilogic.h"
#include "utilities.h" #include "utilities.h"
#include "core/servercontroller.h"
#include <QFileDialog> #include <QFileDialog>
#include <QStandardPaths> #include <QStandardPaths>
@ -94,8 +95,7 @@ void StartPageLogic::onPushButtonConnect()
set_labelWaitInfoText(tr("Please fill in all fields")); set_labelWaitInfoText(tr("Please fill in all fields"));
return; return;
} }
} } else {
else {
if (lineEditIpText().isEmpty() || if (lineEditIpText().isEmpty() ||
lineEditLoginText().isEmpty() || lineEditLoginText().isEmpty() ||
lineEditPasswordText().isEmpty() ) { lineEditPasswordText().isEmpty() ) {
@ -111,7 +111,7 @@ void StartPageLogic::onPushButtonConnect()
serverCredentials.hostName = serverCredentials.hostName.split(":").at(0); serverCredentials.hostName = serverCredentials.hostName.split(":").at(0);
} }
serverCredentials.userName = lineEditLoginText(); serverCredentials.userName = lineEditLoginText();
if (pushButtonConnectKeyChecked()){ if (pushButtonConnectKeyChecked()) {
QString key = textEditSshKeyText(); QString key = textEditSshKeyText();
if (key.startsWith("ssh-rsa")) { if (key.startsWith("ssh-rsa")) {
emit uiLogic()->showPublicKeyWarning(); emit uiLogic()->showPublicKeyWarning();
@ -123,28 +123,34 @@ void StartPageLogic::onPushButtonConnect()
} }
serverCredentials.password = key; serverCredentials.password = key;
} } else {
else {
serverCredentials.password = lineEditPasswordText(); serverCredentials.password = lineEditPasswordText();
} }
set_pushButtonConnectEnabled(false); set_pushButtonConnectEnabled(false);
set_pushButtonConnectText(tr("Connecting...")); set_pushButtonConnectText(tr("Connecting..."));
ErrorCode e = ErrorCode::NoError; ErrorCode errorCode = ErrorCode::NoError;
#ifdef Q_DEBUG #ifdef Q_DEBUG
//QString output = m_serverController->checkSshConnection(serverCredentials, &e); //QString output = m_serverController->checkSshConnection(serverCredentials, &e);
#else #else
QString output; QString output;
#endif #endif
bool ok = true; if (pushButtonConnectKeyChecked()) {
if (e) { QString decryptedPrivateKey;
set_labelWaitInfoVisible(true); errorCode = uiLogic()->m_serverController->getDecryptedPrivateKey(serverCredentials, decryptedPrivateKey);
set_labelWaitInfoText(errorString(e)); if (errorCode == ErrorCode::NoError) {
ok = false; serverCredentials.password = decryptedPrivateKey;
}
} }
else {
bool ok = true;
if (errorCode) {
set_labelWaitInfoVisible(true);
set_labelWaitInfoText(errorString(errorCode));
ok = false;
} else {
if (output.contains("Please login as the user")) { if (output.contains("Please login as the user")) {
output.replace("\n", ""); output.replace("\n", "");
set_labelWaitInfoVisible(true); set_labelWaitInfoVisible(true);

View file

@ -235,7 +235,7 @@ Window {
popupWarning.open() popupWarning.open()
} }
function onShowPassphraseRequestMessage() { function onShowPassphraseRequestMessage() {
popupWithInputField.open() popupWithTextField.open()
} }
} }
@ -358,8 +358,8 @@ Window {
PopupWarning { PopupWarning {
id: popupWarning id: popupWarning
} }
PopupWithInputField { PopupWithTextField {
id: popupWithInputField id: popupWithTextField
placeholderText: "Enter private key passphrase" placeholderText: "Enter private key passphrase"
yesFunc: function() { yesFunc: function() {
editingFinished() editingFinished()