Merge branch 'dev' of github.com:amnezia-vpn/desktop-client into feature/check-user-in-sudo
This commit is contained in:
commit
f620f4a92e
77 changed files with 1254 additions and 585 deletions
|
@ -36,6 +36,7 @@ enum ErrorCode
|
|||
|
||||
// Ssh connection errors
|
||||
SshRequsetDeniedError, SshInterruptedError, SshInternalError,
|
||||
SshPrivateKeyError, SshPrivateKeyFormatError,
|
||||
|
||||
// Ssh sftp errors
|
||||
SshSftpEofError, SshSftpNoSuchFileError, SshSftpPermissionDeniedError,
|
||||
|
|
|
@ -22,6 +22,8 @@ QString errorString(ErrorCode code){
|
|||
case(SshRequsetDeniedError): return QObject::tr("Ssh request was denied");
|
||||
case(SshInterruptedError): return QObject::tr("Ssh request was interrupted");
|
||||
case(SshInternalError): return QObject::tr("Ssh internal error");
|
||||
case(SshPrivateKeyError): return QObject::tr("Invalid private key or invalid passphrase entered");
|
||||
case(SshPrivateKeyFormatError): return QObject::tr("The selected private key format is not supported, use openssh ED25519 key types or PEM key types");
|
||||
|
||||
// Libssh sftp errors
|
||||
case(SshSftpEofError): return QObject::tr("Sftp error: End-of-file encountered");
|
||||
|
|
|
@ -39,6 +39,7 @@ ServerController::ServerController(std::shared_ptr<Settings> settings, QObject *
|
|||
|
||||
ServerController::~ServerController()
|
||||
{
|
||||
m_sshClient.disconnectFromHost();
|
||||
}
|
||||
|
||||
|
||||
|
@ -92,7 +93,6 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
|
|||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode ServerController::runContainerScript(const ServerCredentials &credentials,
|
||||
DockerContainer container, QString script,
|
||||
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut,
|
||||
|
@ -203,21 +203,6 @@ QByteArray ServerController::getTextFileFromContainer(DockerContainer container,
|
|||
return QByteArray::fromHex(stdOut.toUtf8());
|
||||
}
|
||||
|
||||
ErrorCode ServerController::checkOpenVpnServer(DockerContainer container, const ServerCredentials &credentials)
|
||||
{
|
||||
QString caCert = ServerController::getTextFileFromContainer(container,
|
||||
credentials, protocols::openvpn::caCertPath);
|
||||
QString taKey = ServerController::getTextFileFromContainer(container,
|
||||
credentials, protocols::openvpn::taKeyPath);
|
||||
|
||||
if (!caCert.isEmpty() && !taKey.isEmpty()) {
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
else {
|
||||
return ErrorCode::ServerCheckFailed;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath,
|
||||
libssh::SftpOverwriteMode overwriteMode)
|
||||
{
|
||||
|
@ -260,8 +245,6 @@ ErrorCode ServerController::setupContainer(const ServerCredentials &credentials,
|
|||
//qDebug().noquote() << QJsonDocument(config).toJson();
|
||||
ErrorCode e = ErrorCode::NoError;
|
||||
|
||||
disconnectFromHost(credentials);
|
||||
|
||||
e = isUserInSudo(credentials, container);
|
||||
if (e) return e;
|
||||
|
||||
|
@ -622,11 +605,6 @@ void ServerController::setCancelInstallation(const bool cancel)
|
|||
m_cancelInstallation = cancel;
|
||||
}
|
||||
|
||||
void ServerController::disconnectFromHost(const ServerCredentials &credentials)
|
||||
{
|
||||
m_sshClient.disconnectFromHost();
|
||||
}
|
||||
|
||||
ErrorCode ServerController::setupServerFirewall(const ServerCredentials &credentials)
|
||||
{
|
||||
return runScript(credentials,
|
||||
|
@ -647,6 +625,10 @@ QString ServerController::replaceVars(const QString &script, const Vars &vars)
|
|||
|
||||
ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
|
||||
{
|
||||
if (container == DockerContainer::Dns) {
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
QString stdOut;
|
||||
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||
stdOut += data + "\n";
|
||||
|
@ -657,21 +639,27 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential
|
|||
return ErrorCode::NoError;
|
||||
};
|
||||
|
||||
const QString containerString = ProtocolProps::protoToString(ContainerProps::defaultProtocol(container));
|
||||
const Proto protocol = ContainerProps::defaultProtocol(container);
|
||||
const QString containerString = ProtocolProps::protoToString(protocol);
|
||||
const QJsonObject containerConfig = config.value(containerString).toObject();
|
||||
|
||||
QStringList fixedPorts = ContainerProps::fixedPortsForContainer(container);
|
||||
|
||||
QString port = containerConfig.value(config_key::port).toString();
|
||||
QString transportProto = containerConfig.value(config_key::transport_proto).toString();
|
||||
QString defaultPort("%1");
|
||||
QString port = containerConfig.value(config_key::port).toString(defaultPort.arg(ProtocolProps::defaultPort(protocol)));
|
||||
QString defaultTransportProto = ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(protocol), protocol);
|
||||
QString transportProto = containerConfig.value(config_key::transport_proto).toString(defaultTransportProto);
|
||||
|
||||
QString script = QString("sudo lsof -i -P -n | grep -E ':%1").arg(port);
|
||||
QString script = QString("sudo lsof -i -P -n | grep -E ':%1 ").arg(port);
|
||||
for (auto &port : fixedPorts) {
|
||||
script = script.append("|:%1").arg(port);
|
||||
}
|
||||
script = script.append("' | grep -i %1").arg(transportProto);
|
||||
runScript(credentials,
|
||||
ErrorCode errorCode = runScript(credentials,
|
||||
replaceVars(script, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
if (!stdOut.isEmpty()) {
|
||||
return ErrorCode::ServerPortAlreadyAllocatedError;
|
||||
|
@ -786,3 +774,9 @@ ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredential
|
|||
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
ErrorCode ServerController::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &callback)
|
||||
{
|
||||
auto error = m_sshClient.getDecryptedPrivateKey(credentials, decryptedPrivateKey, callback);
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -22,41 +22,26 @@ public:
|
|||
|
||||
typedef QList<QPair<QString, QString>> Vars;
|
||||
|
||||
// ErrorCode fromSshConnectionErrorCode(QSsh::SshError error);
|
||||
|
||||
// QSsh exitCode and exitStatus are different things
|
||||
// ErrorCode fromSshProcessExitStatus(int exitStatus);
|
||||
|
||||
// QSsh::SshConnectionParameters sshParams(const ServerCredentials &credentials);
|
||||
void disconnectFromHost(const ServerCredentials &credentials);
|
||||
|
||||
ErrorCode removeAllContainers(const ServerCredentials &credentials);
|
||||
ErrorCode removeContainer(const ServerCredentials &credentials, DockerContainer container);
|
||||
ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container,
|
||||
QJsonObject &config, bool isUpdate = false);
|
||||
ErrorCode updateContainer(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &oldConfig, QJsonObject &newConfig);
|
||||
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap<DockerContainer, QJsonObject> &installedContainers);
|
||||
|
||||
// create initial config - generate passwords, etc
|
||||
QJsonObject createContainerInitialConfig(DockerContainer container, int port, TransportProto tp);
|
||||
|
||||
bool isReinstallContainerRequred(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig);
|
||||
ErrorCode uploadTextFileToContainer(DockerContainer container, const ServerCredentials &credentials,
|
||||
const QString &file, const QString &path,
|
||||
libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting);
|
||||
|
||||
ErrorCode checkOpenVpnServer(DockerContainer container, const ServerCredentials &credentials);
|
||||
|
||||
ErrorCode uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data,
|
||||
const QString &remotePath, libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting);
|
||||
|
||||
ErrorCode uploadTextFileToContainer(DockerContainer container,
|
||||
const ServerCredentials &credentials, const QString &file, const QString &path,
|
||||
libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting);
|
||||
|
||||
QByteArray getTextFileFromContainer(DockerContainer container,
|
||||
const ServerCredentials &credentials, const QString &path, ErrorCode *errorCode = nullptr);
|
||||
|
||||
ErrorCode setupServerFirewall(const ServerCredentials &credentials);
|
||||
QByteArray getTextFileFromContainer(DockerContainer container, const ServerCredentials &credentials,
|
||||
const QString &path, ErrorCode *errorCode = nullptr);
|
||||
|
||||
QString replaceVars(const QString &script, const Vars &vars);
|
||||
Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None, const QJsonObject &config = QJsonObject());
|
||||
|
||||
ErrorCode runScript(const ServerCredentials &credentials, QString script,
|
||||
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
|
||||
|
@ -66,12 +51,11 @@ public:
|
|||
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
|
||||
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
|
||||
|
||||
Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None, const QJsonObject &config = QJsonObject());
|
||||
|
||||
QString checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr);
|
||||
|
||||
void setCancelInstallation(const bool cancel);
|
||||
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap<DockerContainer, QJsonObject> &installedContainers);
|
||||
|
||||
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &callback);
|
||||
private:
|
||||
ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container);
|
||||
ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
|
||||
|
@ -81,8 +65,14 @@ private:
|
|||
ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
|
||||
|
||||
ErrorCode isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config);
|
||||
bool isReinstallContainerRequred(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig);
|
||||
ErrorCode isUserInSudo(const ServerCredentials &credentials, DockerContainer container);
|
||||
ErrorCode isServerDpkgBusy(const ServerCredentials &credentials, DockerContainer container);
|
||||
|
||||
ErrorCode uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data,
|
||||
const QString &remotePath, libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting);
|
||||
|
||||
ErrorCode setupServerFirewall(const ServerCredentials &credentials);
|
||||
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
std::shared_ptr<VpnConfigurator> m_configurator;
|
||||
|
|
|
@ -10,18 +10,23 @@
|
|||
#endif
|
||||
|
||||
namespace libssh {
|
||||
std::function<QString()> Client::m_passphraseCallback;
|
||||
|
||||
Client::Client(QObject *parent) : QObject(parent)
|
||||
{ }
|
||||
|
||||
Client::~Client()
|
||||
{ }
|
||||
|
||||
int Client::callback(const char *prompt, char *buf, size_t len, int echo, int verify, void *userdata)
|
||||
{
|
||||
auto passphrase = m_passphraseCallback();
|
||||
passphrase.toStdString().copy(buf, passphrase.size() + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ErrorCode Client::connectToHost(const ServerCredentials &credentials)
|
||||
{
|
||||
// if (is_ssh_initialized()) {
|
||||
// qDebug() << "Failed to initialize ssh";
|
||||
// return ErrorCode::InternalError;
|
||||
// }
|
||||
if (m_session == nullptr) {
|
||||
m_session = ssh_new();
|
||||
|
||||
|
@ -51,20 +56,42 @@ namespace libssh {
|
|||
|
||||
int authResult = SSH_ERROR;
|
||||
if (credentials.password.contains("BEGIN") && credentials.password.contains("PRIVATE KEY")) {
|
||||
ssh_key privateKey;
|
||||
ssh_pki_import_privkey_base64(credentials.password.toStdString().c_str(), nullptr, nullptr, nullptr, &privateKey);
|
||||
authResult = ssh_userauth_publickey(m_session, authUsername.c_str(), privateKey);
|
||||
}
|
||||
else {
|
||||
ssh_key privateKey = nullptr;
|
||||
ssh_key publicKey = nullptr;
|
||||
authResult = ssh_pki_import_privkey_base64(credentials.password.toStdString().c_str(), nullptr, callback, nullptr, &privateKey);
|
||||
if (authResult == SSH_OK) {
|
||||
authResult = ssh_pki_export_privkey_to_pubkey(privateKey, &publicKey);
|
||||
}
|
||||
|
||||
if (authResult == SSH_OK) {
|
||||
authResult = ssh_userauth_try_publickey(m_session, authUsername.c_str(), publicKey);
|
||||
}
|
||||
|
||||
if (authResult == SSH_OK) {
|
||||
authResult = ssh_userauth_publickey(m_session, authUsername.c_str(), privateKey);
|
||||
}
|
||||
|
||||
if (publicKey) {
|
||||
ssh_key_free(publicKey);
|
||||
}
|
||||
if (privateKey) {
|
||||
ssh_key_free(privateKey);
|
||||
}
|
||||
if (authResult != SSH_OK) {
|
||||
qDebug() << ssh_get_error(m_session);
|
||||
ErrorCode errorCode = fromLibsshErrorCode(ssh_get_error_code(m_session));
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
errorCode = ErrorCode::SshPrivateKeyFormatError;
|
||||
}
|
||||
return errorCode;
|
||||
}
|
||||
} else {
|
||||
authResult = ssh_userauth_password(m_session, authUsername.c_str(), credentials.password.toStdString().c_str());
|
||||
if (authResult != SSH_OK) {
|
||||
qDebug() << ssh_get_error(m_session);
|
||||
return fromLibsshErrorCode(ssh_get_error_code(m_session));
|
||||
}
|
||||
}
|
||||
|
||||
if (authResult != SSH_OK) {
|
||||
qDebug() << ssh_get_error(m_session);
|
||||
return fromLibsshErrorCode(ssh_get_error_code(m_session));
|
||||
}
|
||||
|
||||
return fromLibsshErrorCode(ssh_get_error_code(m_session));
|
||||
}
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
@ -319,4 +346,33 @@ namespace libssh {
|
|||
default: return ErrorCode::SshSftpFailureError;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode Client::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &passphraseCallback)
|
||||
{
|
||||
int authResult = SSH_ERROR;
|
||||
ErrorCode errorCode = ErrorCode::NoError;
|
||||
|
||||
ssh_key privateKey = nullptr;
|
||||
m_passphraseCallback = passphraseCallback;
|
||||
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;
|
||||
}
|
||||
|
||||
if (privateKey) {
|
||||
ssh_key_free(privateKey);
|
||||
}
|
||||
return errorCode;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,15 +36,19 @@ namespace libssh {
|
|||
const std::string& localPath,
|
||||
const std::string& remotePath,
|
||||
const std::string& fileDesc);
|
||||
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &passphraseCallback);
|
||||
private:
|
||||
ErrorCode closeChannel();
|
||||
ErrorCode closeSftpSession();
|
||||
ErrorCode fromLibsshErrorCode(int errorCode);
|
||||
ErrorCode fromLibsshSftpErrorCode(int errorCode);
|
||||
static int callback(const char *prompt, char *buf, size_t len, int echo, int verify, void *userdata);
|
||||
|
||||
ssh_session m_session = nullptr;
|
||||
ssh_channel m_channel = nullptr;
|
||||
sftp_session m_sftpSession = nullptr;
|
||||
|
||||
static std::function<QString()> m_passphraseCallback;
|
||||
signals:
|
||||
void writeToChannelFinished();
|
||||
void sftpFileCopyFinished();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue