Merge pull request #2 from amnezia-vpn/ss/refactoring

Refactoring
This commit is contained in:
pokamest 2021-01-06 17:14:02 +03:00 committed by GitHub
commit ff557589ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 566 additions and 220 deletions

View file

@ -11,6 +11,8 @@ include("3rd/QtSsh/src/botan/botan.pri")
HEADERS += \ HEADERS += \
communicator.h \ communicator.h \
core/defs.h \
core/errorstrings.h \
core/openvpnconfigurator.h \ core/openvpnconfigurator.h \
core/router.h \ core/router.h \
core/servercontroller.h \ core/servercontroller.h \
@ -19,14 +21,14 @@ HEADERS += \
localclient.h \ localclient.h \
managementserver.h \ managementserver.h \
message.h \ message.h \
openvpnprotocol.h \
runguard.h \ runguard.h \
settings.h \ settings.h \
ui/Controls/SlidingStackedWidget.h \ ui/Controls/SlidingStackedWidget.h \
ui/mainwindow.h \ ui/mainwindow.h \
utils.h \ utils.h \
vpnconnection.h \ vpnconnection.h \
vpnprotocol.h \ protocols/vpnprotocol.h \
protocols/openvpnprotocol.h \
SOURCES += \ SOURCES += \
communicator.cpp \ communicator.cpp \
@ -38,14 +40,14 @@ SOURCES += \
main.cpp \ main.cpp \
managementserver.cpp \ managementserver.cpp \
message.cpp \ message.cpp \
openvpnprotocol.cpp \
runguard.cpp \ runguard.cpp \
settings.cpp \ settings.cpp \
ui/Controls/SlidingStackedWidget.cpp \ ui/Controls/SlidingStackedWidget.cpp \
ui/mainwindow.cpp \ ui/mainwindow.cpp \
utils.cpp \ utils.cpp \
vpnconnection.cpp \ vpnconnection.cpp \
vpnprotocol.cpp \ protocols/vpnprotocol.cpp \
protocols/openvpnprotocol.cpp \
FORMS += ui/mainwindow.ui FORMS += ui/mainwindow.ui

56
client/core/defs.h Normal file
View file

@ -0,0 +1,56 @@
#ifndef DEFS_H
#define DEFS_H
#include <QObject>
namespace amnezia {
enum class Protocol {
Any,
OpenVpn,
ShadowSocks,
WireGuard
};
struct ServerCredentials
{
QString hostName;
QString userName;
QString password;
int port = 22;
};
enum ErrorCode
{
// General error codes
NoError = 0,
UnknownError,
InternalError,
NotImplementedError,
// Server errorz
ServerCheckFailed,
// Ssh connection errors
SshSocketError, SshTimeoutError, SshProtocolError,
SshHostKeyError, SshKeyFileError, SshAuthenticationError,
SshClosedByServerError, SshInternalError,
// Ssh remote process errors
SshRemoteProcessCreationError,
FailedToStartRemoteProcessError, RemoteProcessCrashError,
// Local errors
FailedToSaveConfigData,
OpenVpnConfigMissing,
OpenVpnManagementServerError,
// Distro errors
AmneziaServiceConnectionFailed,
OpenVpnExecutableMissing,
EasyRsaExecutableMissing
};
} // namespace amnezia
#endif // DEFS_H

View file

@ -0,0 +1,47 @@
#ifndef ERRORSTRINGS_H
#define ERRORSTRINGS_H
#include "defs.h"
using namespace amnezia;
QString errorString(ErrorCode code){
switch (code) {
// General error codes
case(NoError): return QObject::tr("No error");
case(UnknownError): return QObject::tr("Unknown Error");
case(NotImplementedError): return QObject::tr("Function not implemented");
case(ServerCheckFailed): return QObject::tr("Server check failed");
// Ssh connection errors
case(SshSocketError): return QObject::tr("Ssh connection error");
case(SshTimeoutError): return QObject::tr("Ssh connection timeout");
case(SshProtocolError): return QObject::tr("Ssh protocol error");
case(SshHostKeyError): return QObject::tr("Ssh server ket check failed");
case(SshKeyFileError): return QObject::tr("Ssh key file error");
case(SshAuthenticationError): return QObject::tr("Ssh authentication error");
case(SshClosedByServerError): return QObject::tr("Ssh session closed");
case(SshInternalError): return QObject::tr("Ssh internal error");
// Ssh remote process errors
case(SshRemoteProcessCreationError): return QObject::tr("Failed to create remote process on server");
case(FailedToStartRemoteProcessError): return QObject::tr("Failed to start remote process on server");
case(RemoteProcessCrashError): return QObject::tr("Remote process on server crashed");
// Local errors
case (FailedToSaveConfigData): return QObject::tr("Failed to save config to disk");
case (OpenVpnConfigMissing): return QObject::tr("OpenVPN config missing");
case (OpenVpnManagementServerError): return QObject::tr("OpenVpn management server error");
case (OpenVpnExecutableMissing): return QObject::tr("OpenVPN executable missing");
case (EasyRsaExecutableMissing): return QObject::tr("EasyRsa executable missing");
case (AmneziaServiceConnectionFailed): return QObject::tr("Amnezia helper service error");
case(InternalError):
default:
return QObject::tr("Internal error");
}
}
#endif // ERRORSTRINGS_H

View file

@ -121,31 +121,39 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
return connData; return connData;
} }
OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(const QSsh::SshConnectionParameters &sshParams) OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(const ServerCredentials &credentials, ErrorCode *errorCode)
{ {
OpenVpnConfigurator::ConnectionData connData = OpenVpnConfigurator::createCertRequest(); OpenVpnConfigurator::ConnectionData connData = OpenVpnConfigurator::createCertRequest();
connData.host = sshParams.host; connData.host = credentials.hostName;
QString reqFileName = QString("/opt/amneziavpn_data/clients/%1.req").arg(connData.clientId); QString reqFileName = QString("/opt/amneziavpn_data/clients/%1.req").arg(connData.clientId);
ServerController::uploadTextFileToContainer(sshParams, connData.request, reqFileName); ErrorCode e = ServerController::uploadTextFileToContainer(credentials, connData.request, reqFileName);
if (e) {
*errorCode = e;
return connData;
}
ServerController::signCert(sshParams, connData.clientId); ServerController::signCert(credentials, connData.clientId);
connData.caCert = ServerController::getTextFileFromContainer(sshParams, QString("/opt/amneziavpn_data/pki/ca.crt")); connData.caCert = ServerController::getTextFileFromContainer(credentials, ServerController::caCertPath(), &e);
connData.clientCert = ServerController::getTextFileFromContainer(sshParams, QString("/opt/amneziavpn_data/pki/issued/%1.crt").arg(connData.clientId)); connData.clientCert = ServerController::getTextFileFromContainer(credentials, ServerController::clientCertPath() + QString("%1.crt").arg(connData.clientId), &e);
connData.taKey = ServerController::getTextFileFromContainer(sshParams, QString("/opt/amneziavpn_data/ta.key")); if (e) {
*errorCode = e;
return connData;
}
connData.taKey = ServerController::getTextFileFromContainer(credentials, ServerController::taKeyPath(), &e);
return connData; return connData;
} }
QString OpenVpnConfigurator::genOpenVpnConfig(const QSsh::SshConnectionParameters &sshParams) QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials, ErrorCode *errorCode)
{ {
QFile configTemplFile(":/server_scripts/template.ovpn"); QFile configTemplFile(":/server_scripts/template.ovpn");
configTemplFile.open(QIODevice::ReadOnly); configTemplFile.open(QIODevice::ReadOnly);
QString config = configTemplFile.readAll(); QString config = configTemplFile.readAll();
ConnectionData connData = prepareOpenVpnConfig(sshParams); ConnectionData connData = prepareOpenVpnConfig(credentials, errorCode);
config.replace("$PROTO", "udp"); config.replace("$PROTO", "udp");
config.replace("$REMOTE_HOST", connData.host); config.replace("$REMOTE_HOST", connData.host);

View file

@ -3,6 +3,8 @@
#include <QObject> #include <QObject>
#include <QProcessEnvironment> #include <QProcessEnvironment>
#include "defs.h"
#include "servercontroller.h" #include "servercontroller.h"
@ -20,7 +22,7 @@ public:
QString host; // host ip QString host; // host ip
}; };
static QString genOpenVpnConfig(const QSsh::SshConnectionParameters &sshParams); static QString genOpenVpnConfig(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr);
private: private:
static QString getRandomString(int len); static QString getRandomString(int len);
@ -32,7 +34,7 @@ private:
static ConnectionData createCertRequest(); static ConnectionData createCertRequest();
static ConnectionData prepareOpenVpnConfig(const QSsh::SshConnectionParameters &sshParams); static ConnectionData prepareOpenVpnConfig(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr);
}; };

View file

@ -6,19 +6,19 @@
#include <QPointer> #include <QPointer>
#include <QTimer> #include <QTimer>
//#include "sshclient.h"
//#include "sshprocess.h"
#include "sshconnectionmanager.h" #include "sshconnectionmanager.h"
#include "sshremoteprocess.h"
using namespace QSsh; using namespace QSsh;
bool ServerController::runScript(const SshConnectionParameters &sshParams, QString script) ErrorCode ServerController::runScript(const SshConnectionParameters &sshParams, QString script)
{ {
QLoggingCategory::setFilterRules(QStringLiteral("qtc.ssh=false")); QLoggingCategory::setFilterRules(QStringLiteral("qtc.ssh=false"));
SshConnection *client = connectToHost(sshParams); SshConnection *client = connectToHost(sshParams);
if (client->state() != SshConnection::State::Connected) {
return fromSshConnectionErrorCode(client->errorState());
}
script.replace("\r", ""); script.replace("\r", "");
@ -36,49 +36,52 @@ bool ServerController::runScript(const SshConnectionParameters &sshParams, QStri
if (!proc) { if (!proc) {
qCritical() << "Failed to create SshRemoteProcess, breaking."; qCritical() << "Failed to create SshRemoteProcess, breaking.";
return false; return ErrorCode::SshRemoteProcessCreationError;
} }
QEventLoop wait; QEventLoop wait;
int exitStatus;
QObject::connect(proc.data(), &SshRemoteProcess::started, &wait, [](){ // QObject::connect(proc.data(), &SshRemoteProcess::started, &wait, [](){
qDebug() << "Command started"; // qDebug() << "Command started";
}); // });
QObject::connect(proc.data(), &SshRemoteProcess::closed, &wait, [&](int status){ QObject::connect(proc.data(), &SshRemoteProcess::closed, &wait, [&](int status){
qDebug() << "Remote process exited with status" << status; exitStatus = status;
//qDebug() << "Remote process exited with status" << status;
wait.quit(); wait.quit();
}); });
QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardOutput, [proc](){ // QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardOutput, [proc](){
QString s = proc->readAllStandardOutput(); // QString s = proc->readAllStandardOutput();
if (s != "." && !s.isEmpty()) { // if (s != "." && !s.isEmpty()) {
qDebug().noquote() << s; // qDebug().noquote() << s << s.size();
} // }
}); // });
QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardError, [proc](){ // QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardError, [proc](){
QString s = proc->readAllStandardError(); // QString s = proc->readAllStandardError();
if (s != "." && !s.isEmpty()) { // if (s != "." && !s.isEmpty()) {
qDebug().noquote() << s; // qDebug().noquote() << s;
} // }
}); // });
proc->start(); proc->start();
if (i < lines.count() - 1) { if (i < lines.count() - 1) {
wait.exec(); wait.exec();
} }
if (SshRemoteProcess::ExitStatus(exitStatus) != QSsh::SshRemoteProcess::ExitStatus::NormalExit) {
return fromSshProcessExitStatus(exitStatus);
}
} }
qDebug() << "ServerController::runScript finished\n"; qDebug() << "ServerController::runScript finished\n";
return ErrorCode::NoError;
// client->disconnectFromHost();
// client->deleteLater();
return true;
} }
void ServerController::uploadTextFileToContainer(const SshConnectionParameters &sshParams, ErrorCode ServerController::uploadTextFileToContainer(const ServerCredentials &credentials,
QString &file, const QString &path) QString &file, const QString &path)
{ {
QLoggingCategory::setFilterRules(QStringLiteral("qtc.ssh=false")); QLoggingCategory::setFilterRules(QStringLiteral("qtc.ssh=false"));
@ -88,60 +91,85 @@ void ServerController::uploadTextFileToContainer(const SshConnectionParameters &
qDebug().noquote() << script; qDebug().noquote() << script;
SshConnection *client = connectToHost(sshParams); SshConnection *client = connectToHost(sshParams(credentials));
if (client->state() != SshConnection::State::Connected) {
return fromSshConnectionErrorCode(client->errorState());
}
QSharedPointer<SshRemoteProcess> proc = client->createRemoteProcess(script.toUtf8()); QSharedPointer<SshRemoteProcess> proc = client->createRemoteProcess(script.toUtf8());
if (!proc) { if (!proc) {
qCritical() << "Failed to create SshRemoteProcess, breaking."; qCritical() << "Failed to create SshRemoteProcess, breaking.";
return; return ErrorCode::SshRemoteProcessCreationError;
} }
QEventLoop wait; QEventLoop wait;
int exitStatus = 0;
QObject::connect(proc.data(), &SshRemoteProcess::started, &wait, [](){ // QObject::connect(proc.data(), &SshRemoteProcess::started, &wait, [](){
qDebug() << "Command started"; // qDebug() << "Command started";
}); // });
QObject::connect(proc.data(), &SshRemoteProcess::closed, &wait, [&](int status){ QObject::connect(proc.data(), &SshRemoteProcess::closed, &wait, [&](int status){
qDebug() << "Remote process exited with status" << status; //qDebug() << "Remote process exited with status" << status;
exitStatus = status;
wait.quit(); wait.quit();
}); });
QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardOutput, [proc](){ // QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardOutput, [proc](){
qDebug().noquote() << proc->readAllStandardOutput(); // qDebug().noquote() << proc->readAllStandardOutput();
}); // });
QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardError, [proc](){ // QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardError, [proc](){
qDebug().noquote() << proc->readAllStandardError(); // qDebug().noquote() << proc->readAllStandardError();
}); // });
proc->start(); proc->start();
wait.exec(); wait.exec();
return fromSshProcessExitStatus(exitStatus);
} }
QString ServerController::getTextFileFromContainer(const SshConnectionParameters &sshParams, const QString &path) QString ServerController::getTextFileFromContainer(const ServerCredentials &credentials, const QString &path,
ErrorCode *errorCode)
{ {
QString script = QString("docker exec -i amneziavpn sh -c \"cat \'%1\'\""). QString script = QString("docker exec -i amneziavpn sh -c \"cat \'%1\'\"").
arg(path); arg(path);
qDebug().noquote() << "Copy file from container\n" << script; qDebug().noquote() << "Copy file from container\n" << script;
SshConnection *client = connectToHost(sshParams); SshConnection *client = connectToHost(sshParams(credentials));
if (client->state() != SshConnection::State::Connected) {
if (errorCode) *errorCode = fromSshConnectionErrorCode(client->errorState());
return QString();
}
QSharedPointer<SshRemoteProcess> proc = client->createRemoteProcess(script.toUtf8()); QSharedPointer<SshRemoteProcess> proc = client->createRemoteProcess(script.toUtf8());
if (!proc) {
qCritical() << "Failed to create SshRemoteProcess, breaking.";
if (errorCode) *errorCode = ErrorCode::SshRemoteProcessCreationError;
return QString();
}
QEventLoop wait; QEventLoop wait;
int exitStatus = 0;
QObject::connect(proc.data(), &SshRemoteProcess::closed, &wait, [&](int ){ QObject::connect(proc.data(), &SshRemoteProcess::closed, &wait, [&](int status){
exitStatus = status;
wait.quit(); wait.quit();
}); });
proc->start(); proc->start();
wait.exec(); wait.exec();
if (SshRemoteProcess::ExitStatus(exitStatus) != QSsh::SshRemoteProcess::ExitStatus::NormalExit) {
if (errorCode) *errorCode = fromSshProcessExitStatus(exitStatus);
}
return proc->readAllStandardOutput(); return proc->readAllStandardOutput();
} }
bool ServerController::signCert(const SshConnectionParameters &sshParams, QString clientId) ErrorCode ServerController::signCert(const ServerCredentials &credentials, QString clientId)
{ {
QString script_import = QString("docker exec -i amneziavpn bash -c \"cd /opt/amneziavpn_data && " QString script_import = QString("docker exec -i amneziavpn bash -c \"cd /opt/amneziavpn_data && "
"easyrsa import-req /opt/amneziavpn_data/clients/%1.req %1 &>/dev/null\"") "easyrsa import-req /opt/amneziavpn_data/clients/%1.req %1 &>/dev/null\"")
@ -153,55 +181,121 @@ bool ServerController::signCert(const SshConnectionParameters &sshParams, QStrin
QStringList script {script_import, script_sign}; QStringList script {script_import, script_sign};
return runScript(sshParams, script.join("\n")); return runScript(sshParams(credentials), script.join("\n"));
} }
bool ServerController::removeServer(const SshConnectionParameters &sshParams, ServerController::ServerType sType) ErrorCode ServerController::checkOpenVpnServer(const ServerCredentials &credentials)
{
QString caCert = ServerController::getTextFileFromContainer(credentials, ServerController::caCertPath());
QString taKey = ServerController::getTextFileFromContainer(credentials, ServerController::taKeyPath());
if (!caCert.isEmpty() && !taKey.isEmpty()) {
return ErrorCode::NoError;
}
else {
return ErrorCode::ServerCheckFailed;
}
}
ErrorCode ServerController::fromSshConnectionErrorCode(SshError error)
{
switch (error) {
case(SshNoError): return ErrorCode::NoError;
case(QSsh::SshSocketError): return ErrorCode::SshSocketError;
case(QSsh::SshTimeoutError): return ErrorCode::SshTimeoutError;
case(QSsh::SshProtocolError): return ErrorCode::SshProtocolError;
case(QSsh::SshHostKeyError): return ErrorCode::SshHostKeyError;
case(QSsh::SshKeyFileError): return ErrorCode::SshKeyFileError;
case(QSsh::SshAuthenticationError): return ErrorCode::SshAuthenticationError;
case(QSsh::SshClosedByServerError): return ErrorCode::SshClosedByServerError;
case(QSsh::SshInternalError): return ErrorCode::SshInternalError;
}
}
ErrorCode ServerController::fromSshProcessExitStatus(int exitStatus)
{
switch (SshRemoteProcess::ExitStatus(exitStatus)) {
case(SshRemoteProcess::ExitStatus::NormalExit): return ErrorCode::NoError;
case(SshRemoteProcess::ExitStatus::FailedToStart): return ErrorCode::FailedToStartRemoteProcessError;
case(SshRemoteProcess::ExitStatus::CrashExit): return ErrorCode::RemoteProcessCrashError;
}
}
SshConnectionParameters ServerController::sshParams(const ServerCredentials &credentials)
{
QSsh::SshConnectionParameters sshParams;
sshParams.authenticationType = QSsh::SshConnectionParameters::AuthenticationTypePassword;
sshParams.host = credentials.hostName;
sshParams.userName = credentials.userName;
sshParams.password = credentials.password;
sshParams.timeout = 10;
sshParams.port = credentials.port;
sshParams.hostKeyCheckingMode = QSsh::SshHostKeyCheckingMode::SshHostKeyCheckingNone;
return sshParams;
}
ErrorCode ServerController::removeServer(const ServerCredentials &credentials, Protocol proto)
{ {
QString scriptFileName; QString scriptFileName;
if (sType == OpenVPN) { if (proto == Protocol::OpenVpn) {
scriptFileName = ":/server_scripts/remove_openvpn_server.sh"; scriptFileName = ":/server_scripts/remove_openvpn_server.sh";
} }
QString scriptData; QString scriptData;
QFile file(scriptFileName); QFile file(scriptFileName);
if (! file.open(QIODevice::ReadOnly)) { if (! file.open(QIODevice::ReadOnly)) return ErrorCode::InternalError;
return false;
}
scriptData = file.readAll(); scriptData = file.readAll();
if (scriptData.isEmpty()) return false; if (scriptData.isEmpty()) return ErrorCode::InternalError;
return runScript(sshParams, scriptData); return runScript(sshParams(credentials), scriptData);
} }
bool ServerController::setupServer(const SshConnectionParameters &sshParams, ServerController::ServerType sType) ErrorCode ServerController::setupServer(const ServerCredentials &credentials, Protocol proto)
{ {
QString scriptFileName; if (proto == Protocol::OpenVpn) {
return setupOpenVpnServer(credentials);
if (sType == OpenVPN) { }
scriptFileName = ":/server_scripts/setup_openvpn_server.sh"; else if (proto == Protocol::ShadowSocks) {
return setupShadowSocksServer(credentials);
}
else if (proto == Protocol::Any) {
// TODO: run concurently
return setupOpenVpnServer(credentials);
//setupShadowSocksServer(credentials);
} }
return ErrorCode::NotImplementedError;
}
ErrorCode ServerController::setupOpenVpnServer(const ServerCredentials &credentials)
{
QString scriptData; QString scriptData;
QString scriptFileName = ":/server_scripts/setup_openvpn_server.sh";
QFile file(scriptFileName); QFile file(scriptFileName);
if (! file.open(QIODevice::ReadOnly)) { if (! file.open(QIODevice::ReadOnly)) return ErrorCode::InternalError;
return false;
}
scriptData = file.readAll(); scriptData = file.readAll();
if (scriptData.isEmpty()) return false; if (scriptData.isEmpty()) return ErrorCode::InternalError;
return runScript(sshParams, scriptData); ErrorCode e = runScript(sshParams(credentials), scriptData);
if (e) return e;
//return ok;
return checkOpenVpnServer(credentials);
}
ErrorCode ServerController::setupShadowSocksServer(const ServerCredentials &credentials)
{
return ErrorCode::NotImplementedError;
} }
SshConnection *ServerController::connectToHost(const SshConnectionParameters &sshParams) SshConnection *ServerController::connectToHost(const SshConnectionParameters &sshParams)
{ {
SshConnection *client = acquireConnection(sshParams); SshConnection *client = acquireConnection(sshParams);
//QPointer<SshConnection> client = new SshConnection(serverInfo);
QEventLoop waitssh; QEventLoop waitssh;
QObject::connect(client, &SshConnection::connected, &waitssh, [&]() { QObject::connect(client, &SshConnection::connected, &waitssh, [&]() {

View file

@ -3,29 +3,43 @@
#include <QObject> #include <QObject>
#include "sshconnection.h" #include "sshconnection.h"
#include "sshremoteprocess.h"
#include "defs.h"
using namespace amnezia;
class ServerController : public QObject class ServerController : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
enum ServerType {
OpenVPN,
ShadowSocks,
WireGuard
};
static bool removeServer(const QSsh::SshConnectionParameters &sshParams, ServerType sType); static ErrorCode fromSshConnectionErrorCode(QSsh::SshError error);
static bool setupServer(const QSsh::SshConnectionParameters &sshParams, ServerType sType);
// QSsh exitCode and exitStatus are different things
static ErrorCode fromSshProcessExitStatus(int exitStatus);
static QString caCertPath() { return "/opt/amneziavpn_data/pki/ca.crt"; }
static QString clientCertPath() { return "/opt/amneziavpn_data/pki/issued/"; }
static QString taKeyPath() { return "/opt/amneziavpn_data/ta.key"; }
static QSsh::SshConnectionParameters sshParams(const ServerCredentials &credentials);
static ErrorCode removeServer(const ServerCredentials &credentials, Protocol proto);
static ErrorCode setupServer(const ServerCredentials &credentials, Protocol proto);
static ErrorCode checkOpenVpnServer(const ServerCredentials &credentials);
static ErrorCode uploadTextFileToContainer(const ServerCredentials &credentials, QString &file, const QString &path);
static QString getTextFileFromContainer(const ServerCredentials &credentials, const QString &path, ErrorCode *errorCode = nullptr);
static ErrorCode signCert(const ServerCredentials &credentials, QString clientId);
private:
static QSsh::SshConnection *connectToHost(const QSsh::SshConnectionParameters &sshParams); static QSsh::SshConnection *connectToHost(const QSsh::SshConnectionParameters &sshParams);
static bool runScript(const QSsh::SshConnectionParameters &sshParams, QString script); static ErrorCode runScript(const QSsh::SshConnectionParameters &sshParams, QString script);
static void uploadTextFileToContainer(const QSsh::SshConnectionParameters &sshParams, QString &file, const QString &path); static ErrorCode setupOpenVpnServer(const ServerCredentials &credentials);
static QString getTextFileFromContainer(const QSsh::SshConnectionParameters &sshParams, const QString &path); static ErrorCode setupShadowSocksServer(const ServerCredentials &credentials);
static bool signCert(const QSsh::SshConnectionParameters &sshParams, QString clientId);
signals:
}; };

View file

@ -107,7 +107,7 @@ QString OpenVpnProtocol::openVpnExecPath() const
#endif #endif
} }
bool OpenVpnProtocol::start() ErrorCode OpenVpnProtocol::start()
{ {
qDebug() << "Start OpenVPN connection"; qDebug() << "Start OpenVPN connection";
@ -116,18 +116,18 @@ bool OpenVpnProtocol::start()
stop(); stop();
if (communicator() && !communicator()->connected()) { if (communicator() && !communicator()->connected()) {
setLastError("Communicator is not connected!"); setLastError(ErrorCode::AmneziaServiceConnectionFailed);
return false; return lastError();
} }
if (!QFileInfo::exists(openVpnExecPath())) { if (!QFileInfo::exists(openVpnExecPath())) {
setLastError("OpenVPN executable does not exist!\n" + openVpnExecPath()); setLastError(ErrorCode::OpenVpnExecutableMissing);
return false; return lastError();
} }
if (!QFileInfo::exists(configPath())) { if (!QFileInfo::exists(configPath())) {
setLastError("OpenVPN config file does not exist!\n" + configPath()); setLastError(ErrorCode::OpenVpnConfigMissing);
return false; return lastError();
} }
QString vpnLogFileNamePath = Utils::systemLogPath() + "/openvpn.log"; QString vpnLogFileNamePath = Utils::systemLogPath() + "/openvpn.log";
@ -141,14 +141,15 @@ bool OpenVpnProtocol::start()
}); });
if (!m_managementServer.start(m_managementHost, m_managementPort)) { if (!m_managementServer.start(m_managementHost, m_managementPort)) {
return false; setLastError(ErrorCode::OpenVpnManagementServerError);
return lastError();
} }
setConnectionState(ConnectionState::Connecting); setConnectionState(ConnectionState::Connecting);
m_communicator->sendMessage(Message(Message::State::StartRequest, args)); m_communicator->sendMessage(Message(Message::State::StartRequest, args));
startTimeoutTimer(); startTimeoutTimer();
return true; return ErrorCode::NoError;
} }
void OpenVpnProtocol::openVpnStateSigTermHandlerTimerEvent() void OpenVpnProtocol::openVpnStateSigTermHandlerTimerEvent()

View file

@ -17,7 +17,7 @@ public:
explicit OpenVpnProtocol(const QString& args = QString(), QObject* parent = nullptr); explicit OpenVpnProtocol(const QString& args = QString(), QObject* parent = nullptr);
~OpenVpnProtocol(); ~OpenVpnProtocol();
bool start() override; ErrorCode start() override;
void stop() override; void stop() override;
protected slots: protected slots:

View file

@ -19,11 +19,6 @@ VpnProtocol::VpnProtocol(const QString& args, QObject* parent)
Q_UNUSED(args) Q_UNUSED(args)
} }
VpnProtocol::~VpnProtocol()
{
}
void VpnProtocol::initializeCommunicator(QObject* parent) void VpnProtocol::initializeCommunicator(QObject* parent)
{ {
if (!m_communicator) { if (!m_communicator) {
@ -36,13 +31,13 @@ Communicator* VpnProtocol::communicator()
return m_communicator; return m_communicator;
} }
void VpnProtocol::setLastError(const QString& error) void VpnProtocol::setLastError(ErrorCode lastError)
{ {
m_lastError = error; m_lastError = lastError;
qCritical().noquote() << m_lastError; qCritical().noquote() << m_lastError;
} }
QString VpnProtocol::lastError() const ErrorCode VpnProtocol::lastError() const
{ {
return m_lastError; return m_lastError;
} }

View file

@ -4,6 +4,9 @@
#include <QObject> #include <QObject>
#include <QString> #include <QString>
#include "core/defs.h"
using namespace amnezia;
class QTimer; class QTimer;
class Communicator; class Communicator;
@ -13,7 +16,7 @@ class VpnProtocol : public QObject
public: public:
explicit VpnProtocol(const QString& args = QString(), QObject* parent = nullptr); explicit VpnProtocol(const QString& args = QString(), QObject* parent = nullptr);
~VpnProtocol(); virtual ~VpnProtocol() override = default;
enum class ConnectionState {Unknown, Disconnected, Preparing, Connecting, Connected, Disconnecting, TunnelReconnecting, Error}; enum class ConnectionState {Unknown, Disconnected, Preparing, Connecting, Connected, Disconnecting, TunnelReconnecting, Error};
@ -24,13 +27,13 @@ public:
virtual bool connected() const; virtual bool connected() const;
virtual bool disconnected() const; virtual bool disconnected() const;
virtual bool start() = 0; virtual ErrorCode start() = 0;
virtual void stop() = 0; virtual void stop() = 0;
ConnectionState connectionState() const; ConnectionState connectionState() const;
QString lastError() const; ErrorCode lastError() const;
QString textConnectionState() const; QString textConnectionState() const;
void setLastError(const QString& error); void setLastError(ErrorCode lastError);
signals: signals:
void bytesChanged(quint64 receivedBytes, quint64 sentBytes); void bytesChanged(quint64 receivedBytes, quint64 sentBytes);
@ -53,7 +56,7 @@ protected:
private: private:
QTimer* m_timeoutTimer; QTimer* m_timeoutTimer;
QString m_lastError; ErrorCode m_lastError;
quint64 m_receivedBytes; quint64 m_receivedBytes;
quint64 m_sentBytes; quint64 m_sentBytes;
}; };

View file

@ -37,5 +37,6 @@
<file>server_scripts/setup_openvpn_server.sh</file> <file>server_scripts/setup_openvpn_server.sh</file>
<file>server_scripts/template.ovpn</file> <file>server_scripts/template.ovpn</file>
<file>images/background_connected.png</file> <file>images/background_connected.png</file>
<file>server_scripts/setup_shadowsocks_server.sh</file>
</qresource> </qresource>
</RCC> </RCC>

View file

@ -0,0 +1,13 @@
#DOCKER_IMAGE="amneziavpn/shadow-vpn:latest"
#CONTAINER_NAME="shadow-vpn"
#sudo apt update
sudo apt install -y docker.io curl
sudo systemctl start docker
sudo docker stop shadow-vpn
sudo docker rm -f shadow-vpn
sudo docker pull amneziavpn/shadow-vpn:latest
sudo docker run -d --restart always --cap-add=NET_ADMIN -p 1194:1194/tcp -p 6789:6789/tcp --name shadow-vpn amneziavpn/shadow-vpn:latest

View file

@ -12,30 +12,31 @@ Settings::Settings(QObject* parent) : QObject(parent)
void Settings::read() void Settings::read()
{ {
m_settings->beginGroup("Server"); m_settings->beginGroup("Server");
m_login = m_settings->value("login", QString()).toString(); m_userName = m_settings->value("userName", QString()).toString();
m_password = m_settings->value("password", QString()).toString(); m_password = m_settings->value("password", QString()).toString();
m_serverName = m_settings->value("serverName", QString()).toString(); m_serverName = m_settings->value("serverName", QString()).toString();
m_serverPort = m_settings->value("serverPort", 22).toInt();
m_settings->endGroup(); m_settings->endGroup();
} }
void Settings::save() void Settings::save()
{ {
m_settings->beginGroup("Server"); m_settings->beginGroup("Server");
m_settings->setValue("login", m_login); m_settings->setValue("userName", m_userName);
m_settings->setValue("password", m_password); m_settings->setValue("password", m_password);
m_settings->setValue("serverName", m_serverName); m_settings->setValue("serverName", m_serverName);
m_settings->setValue("serverPort", m_serverPort);
m_settings->endGroup(); m_settings->endGroup();
} }
bool Settings::haveAuthData() const bool Settings::haveAuthData() const
{ {
return (!serverName().isEmpty() && !login().isEmpty() && !password().isEmpty()); return (!serverName().isEmpty() && !userName().isEmpty() && !password().isEmpty());
} }
void Settings::setLogin(const QString& login) void Settings::setUserName(const QString& login)
{ {
m_login = login; m_userName = login;
} }
void Settings::setPassword(const QString& password) void Settings::setPassword(const QString& password)
@ -48,17 +49,26 @@ void Settings::setServerName(const QString& serverName)
m_serverName = serverName; m_serverName = serverName;
} }
QString Settings::login() const void Settings::setServerPort(int serverPort)
{ {
return m_login; m_serverPort = serverPort;
} }
QString Settings::password() const void Settings::setServerCredentials(const ServerCredentials &credentials)
{ {
return m_password; setServerName(credentials.hostName);
setServerPort(credentials.port);
setUserName(credentials.userName);
setPassword(credentials.password);
} }
QString Settings::serverName() const ServerCredentials Settings::serverCredentials()
{ {
return m_serverName; ServerCredentials credentials;
credentials.hostName = serverName();
credentials.userName = userName();
credentials.password = password();
credentials.port = serverPort();
return credentials;
} }

View file

@ -4,6 +4,10 @@
#include <QObject> #include <QObject>
#include <QString> #include <QString>
#include "core/defs.h"
using namespace amnezia;
class QSettings; class QSettings;
class Settings : public QObject class Settings : public QObject
@ -16,21 +20,27 @@ public:
void read(); void read();
void save(); void save();
void setLogin(const QString& login); void setUserName(const QString& login);
void setPassword(const QString& password); void setPassword(const QString& password);
void setServerName(const QString& serverName); void setServerName(const QString& serverName);
void setServerPort(int serverPort);
void setServerCredentials(const ServerCredentials &credentials);
QString userName() const { return m_userName; }
QString password() const { return m_password; }
QString serverName() const { return m_serverName; }
int serverPort() const { return m_serverPort; }
ServerCredentials serverCredentials();
QString login() const;
QString password() const;
QString serverName() const;
bool haveAuthData() const; bool haveAuthData() const;
protected: protected:
QSettings* m_settings; QSettings* m_settings;
QString m_login; QString m_userName;
QString m_password; QString m_password;
QString m_serverName; QString m_serverName;
int m_serverPort;
}; };
#endif // SETTINGS_H #endif // SETTINGS_H

View file

@ -2,10 +2,14 @@
#include <QMessageBox> #include <QMessageBox>
#include <QSysInfo> #include <QSysInfo>
#include <QThread> #include <QThread>
#include <QTimer>
#include "communicator.h" #include "communicator.h"
#include "core/errorstrings.h"
#include "core/openvpnconfigurator.h" #include "core/openvpnconfigurator.h"
#include "core/servercontroller.h" #include "core/servercontroller.h"
#include "debug.h" #include "debug.h"
#include "defines.h" #include "defines.h"
#include "mainwindow.h" #include "mainwindow.h"
@ -34,6 +38,10 @@ MainWindow::MainWindow(QWidget *parent) :
ui->stackedWidget_main->setSpeed(200); ui->stackedWidget_main->setSpeed(200);
ui->stackedWidget_main->setAnimation(QEasingCurve::Linear); ui->stackedWidget_main->setAnimation(QEasingCurve::Linear);
ui->label_new_server_wait_info->setVisible(false);
ui->progressBar_new_server_connection->setMinimum(0);
ui->progressBar_new_server_connection->setMaximum(300);
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
ui->widget_tittlebar->hide(); ui->widget_tittlebar->hide();
ui->stackedWidget_main->move(0,0); ui->stackedWidget_main->move(0,0);
@ -48,6 +56,8 @@ MainWindow::MainWindow(QWidget *parent) :
goToPage(Page::Initialization); goToPage(Page::Initialization);
} }
//goToPage(Page::Initialization);
connect(ui->pushButton_blocked_list, SIGNAL(clicked(bool)), this, SLOT(onPushButtonBlockedListClicked(bool))); connect(ui->pushButton_blocked_list, SIGNAL(clicked(bool)), this, SLOT(onPushButtonBlockedListClicked(bool)));
connect(ui->pushButton_connect, SIGNAL(toggled(bool)), this, SLOT(onPushButtonConnectToggled(bool))); connect(ui->pushButton_connect, SIGNAL(toggled(bool)), this, SLOT(onPushButtonConnectToggled(bool)));
connect(ui->pushButton_settings, SIGNAL(clicked(bool)), this, SLOT(onPushButtonSettingsClicked(bool))); connect(ui->pushButton_settings, SIGNAL(clicked(bool)), this, SLOT(onPushButtonSettingsClicked(bool)));
@ -148,28 +158,71 @@ void MainWindow::onPushButtonNewServerConnectWithNewData(bool clicked)
ui->lineEdit_new_server_password->text().isEmpty() ) { ui->lineEdit_new_server_password->text().isEmpty() ) {
QMessageBox::warning(this, APPLICATION_NAME, tr("Please fill in all fields")); QMessageBox::warning(this, APPLICATION_NAME, tr("Please fill in all fields"));
return; return;
} else {
qDebug() << "Start connection with new data";
m_settings->setServerName(ui->lineEdit_new_server_ip->text());
m_settings->setLogin(ui->lineEdit_new_server_login->text());
m_settings->setPassword(ui->lineEdit_new_server_password->text());
m_settings->save();
//goToPage(Page::Vpn);
if (requestOvpnConfig(m_settings->serverName(), m_settings->login(), m_settings->password())) {
goToPage(Page::Vpn);
ui->pushButton_connect->setDown(true);
if (!m_vpnConnection->connectToVpn()) {
ui->pushButton_connect->setChecked(false);
QMessageBox::critical(this, APPLICATION_NAME, m_vpnConnection->lastError());
return;
}
}
} }
qDebug() << "Start connection with new data";
ServerCredentials serverCredentials;
serverCredentials.hostName = ui->lineEdit_new_server_ip->text();
if (serverCredentials.hostName.contains(":")) {
serverCredentials.port = serverCredentials.hostName.split(":").at(1).toInt();
serverCredentials.hostName = serverCredentials.hostName.split(":").at(0);
}
serverCredentials.userName = ui->lineEdit_new_server_login->text();
serverCredentials.password = ui->lineEdit_new_server_password->text();
m_settings->setServerCredentials(serverCredentials);
m_settings->save();
ui->page_new_server->setEnabled(false);
ui->pushButton_new_server_connect_with_new_data->setVisible(false);
ui->label_new_server_wait_info->setVisible(true);
QTimer timer;
connect(&timer, &QTimer::timeout, [&](){
ui->progressBar_new_server_connection->setValue(ui->progressBar_new_server_connection->value() + 1);
});
ui->progressBar_new_server_connection->setValue(0);
timer.start(1000);
ErrorCode e = ServerController::setupServer(serverCredentials, Protocol::Any);
if (e) {
ui->page_new_server->setEnabled(true);
ui->pushButton_new_server_connect_with_new_data->setVisible(true);
ui->label_new_server_wait_info->setVisible(false);
QMessageBox::warning(this, APPLICATION_NAME,
tr("Error occurred while configuring server.") + "\n" +
errorString(e) + "\n" +
tr("See logs for details."));
return;
}
// just ui progressbar tweak
timer.stop();
int remaining_val = ui->progressBar_new_server_connection->maximum() - ui->progressBar_new_server_connection->value();
if (remaining_val > 0) {
QTimer timer1;
QEventLoop loop1;
connect(&timer1, &QTimer::timeout, [&](){
ui->progressBar_new_server_connection->setValue(ui->progressBar_new_server_connection->value() + 1);
if (ui->progressBar_new_server_connection->value() >= ui->progressBar_new_server_connection->maximum()) {
loop1.quit();
}
});
timer1.start(5);
loop1.exec();
}
goToPage(Page::Vpn);
ui->pushButton_connect->setChecked(true);
} }
void MainWindow::onBytesChanged(quint64 receivedData, quint64 sentData) void MainWindow::onBytesChanged(quint64 receivedData, quint64 sentData)
@ -249,9 +302,13 @@ void MainWindow::onConnectionStateChanged(VpnProtocol::ConnectionState state)
void MainWindow::onPushButtonConnectToggled(bool checked) void MainWindow::onPushButtonConnectToggled(bool checked)
{ {
if (checked) { if (checked) {
if (!m_vpnConnection->connectToVpn()) { // TODO: Call connectToVpn with restricted server account
ServerCredentials credentials = m_settings->serverCredentials();
ErrorCode errorCode = m_vpnConnection->connectToVpn(credentials);
if (errorCode) {
ui->pushButton_connect->setChecked(false); ui->pushButton_connect->setChecked(false);
QMessageBox::critical(this, APPLICATION_NAME, m_vpnConnection->lastError()); QMessageBox::critical(this, APPLICATION_NAME, errorString(errorCode));
return; return;
} }
ui->pushButton_connect->setEnabled(false); ui->pushButton_connect->setEnabled(false);
@ -260,36 +317,6 @@ void MainWindow::onPushButtonConnectToggled(bool checked)
} }
} }
bool MainWindow::requestOvpnConfig(const QString& hostName, const QString& userName, const QString& password, int port, int timeout)
{
QSsh::SshConnectionParameters sshParams;
sshParams.authenticationType = QSsh::SshConnectionParameters::AuthenticationTypePassword;
sshParams.host = hostName;
sshParams.userName = userName;
sshParams.password = password;
sshParams.timeout = timeout;
sshParams.port = port;
sshParams.hostKeyCheckingMode = QSsh::SshHostKeyCheckingMode::SshHostKeyCheckingNone;
if (!ServerController::setupServer(sshParams, ServerController::OpenVPN)) {
return false;
}
QString configData = OpenVpnConfigurator::genOpenVpnConfig(sshParams);
if (configData.isEmpty()) {
return false;
}
QFile file(Utils::defaultVpnConfigFileName());
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)){
QTextStream stream(&file);
stream << configData << endl;
return true;
}
return false;
}
void MainWindow::on_pushButton_close_clicked() void MainWindow::on_pushButton_close_clicked()
{ {
qApp->exit(); qApp->exit();

View file

@ -4,7 +4,7 @@
#include <QMainWindow> #include <QMainWindow>
#include "framelesswindow.h" #include "framelesswindow.h"
#include "vpnprotocol.h" #include "protocols/vpnprotocol.h"
class Settings; class Settings;
class VpnConnection; class VpnConnection;
@ -45,9 +45,6 @@ private slots:
void on_pushButton_close_clicked(); void on_pushButton_close_clicked();
protected:
bool requestOvpnConfig(const QString& hostName, const QString& userName, const QString& password, int port = 22, int timeout = 30);
private: private:
void goToPage(Page page); void goToPage(Page page);

View file

@ -653,10 +653,7 @@ color: #333333;</string>
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">QPushButton { <string notr="true">QPushButton {
font-size: 13pt; color:rgb(212, 212, 212);
font: &quot;Open Sans Semibold&quot;;
color:rgb(212, 212, 212);
border-radius: 4px; border-radius: 4px;
font-family: Lato; font-family: Lato;
@ -708,8 +705,26 @@ color: #15CDCB;</string>
</rect> </rect>
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">background: #181922; <string notr="true">QProgressBar{
border-radius: 4px;</string> color:rgb(212, 212, 212);
border-radius: 4px;
font-family: Lato;
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 21px;
background: #100A44;
border-radius: 4px;
}
QProgressBar::chunk {
background: rgba(255, 255, 255, 0.15);
border-radius: 4px 0px 0px 4px;
}
</string>
</property> </property>
<property name="value"> <property name="value">
<number>24</number> <number>24</number>
@ -721,7 +736,7 @@ border-radius: 4px;</string>
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="format"> <property name="format">
<string>Connecting...</string> <string>Configuring...</string>
</property> </property>
</widget> </widget>
<widget class="QPushButton" name="pushButton_back_from_new_server"> <widget class="QPushButton" name="pushButton_back_from_new_server">
@ -772,6 +787,25 @@ QPushButton:hover {
<string/> <string/>
</property> </property>
</widget> </widget>
<widget class="QLabel" name="label_new_server_wait_info">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>40</x>
<y>490</y>
<width>301</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string>Please wait, configuring process may take up to 5 minutes</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
<zorder>progressBar_new_server_connection</zorder> <zorder>progressBar_new_server_connection</zorder>
<zorder>label_2</zorder> <zorder>label_2</zorder>
<zorder>label_4</zorder> <zorder>label_4</zorder>
@ -784,6 +818,7 @@ QPushButton:hover {
<zorder>pushButton</zorder> <zorder>pushButton</zorder>
<zorder>pushButton_back_from_new_server</zorder> <zorder>pushButton_back_from_new_server</zorder>
<zorder>label_7</zorder> <zorder>label_7</zorder>
<zorder>label_new_server_wait_info</zorder>
</widget> </widget>
<widget class="QWidget" name="page_amnezia"> <widget class="QWidget" name="page_amnezia">
<property name="styleSheet"> <property name="styleSheet">

View file

@ -81,7 +81,7 @@ bool Utils::processIsRunning(const QString& fileName)
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
QProcess process; QProcess process;
process.setReadChannel(QProcess::StandardOutput); process.setReadChannel(QProcess::StandardOutput);
process.setReadChannelMode(QProcess::MergedChannels); process.setProcessChannelMode(QProcess::MergedChannels);
process.start(QString("wmic.exe /OUTPUT:STDOUT PROCESS get %1").arg("Caption")); process.start(QString("wmic.exe /OUTPUT:STDOUT PROCESS get %1").arg("Caption"));
process.waitForStarted(); process.waitForStarted();
process.waitForFinished(); process.waitForFinished();

View file

@ -1,6 +1,11 @@
#include <QDebug> #include <QDebug>
#include <QFile>
#include "openvpnprotocol.h" #include <core/openvpnconfigurator.h>
#include <core/servercontroller.h>
#include "protocols/openvpnprotocol.h"
#include "utils.h"
#include "vpnconnection.h" #include "vpnconnection.h"
VpnConnection::VpnConnection(QObject* parent) : QObject(parent) VpnConnection::VpnConnection(QObject* parent) : QObject(parent)
@ -8,11 +13,6 @@ VpnConnection::VpnConnection(QObject* parent) : QObject(parent)
VpnProtocol::initializeCommunicator(parent); VpnProtocol::initializeCommunicator(parent);
} }
VpnConnection::~VpnConnection()
{
}
void VpnConnection::onBytesChanged(quint64 receivedBytes, quint64 sentBytes) void VpnConnection::onBytesChanged(quint64 receivedBytes, quint64 sentBytes)
{ {
emit bytesChanged(receivedBytes, sentBytes); emit bytesChanged(receivedBytes, sentBytes);
@ -23,28 +23,56 @@ void VpnConnection::onConnectionStateChanged(VpnProtocol::ConnectionState state)
emit connectionStateChanged(state); emit connectionStateChanged(state);
} }
QString VpnConnection::lastError() const ErrorCode VpnConnection::lastError() const
{ {
if (!m_vpnProtocol.data()) { if (!m_vpnProtocol.data()) {
return "Unnown protocol"; return ErrorCode::InternalError;
} }
return m_vpnProtocol.data()->lastError(); return m_vpnProtocol.data()->lastError();
} }
bool VpnConnection::connectToVpn(Protocol protocol) ErrorCode VpnConnection::requestVpnConfig(const ServerCredentials &credentials, Protocol protocol)
{ {
ErrorCode errorCode = ErrorCode::NoError;
if (protocol == Protocol::OpenVpn) {
QString configData = OpenVpnConfigurator::genOpenVpnConfig(credentials, &errorCode);
if (errorCode) {
return errorCode;
}
QFile file(Utils::defaultVpnConfigFileName());
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)){
QTextStream stream(&file);
stream << configData << endl;
return ErrorCode::NoError;
}
return ErrorCode::FailedToSaveConfigData;
}
else if (protocol == Protocol::ShadowSocks) {
// Request OpenVPN config and ShadowSocks
return ErrorCode::NotImplementedError;
}
return ErrorCode::NotImplementedError;
}
ErrorCode VpnConnection::connectToVpn(const ServerCredentials &credentials, Protocol protocol)
{
// TODO: Try protocols one by one in case of Protocol::Any
// TODO: Implement some behavior in case if connection not stable
qDebug() << "Connect to VPN"; qDebug() << "Connect to VPN";
switch (protocol) { if (protocol == Protocol::Any || protocol == Protocol::OpenVpn) {
case Protocol::OpenVpn: ErrorCode e = requestVpnConfig(credentials, Protocol::OpenVpn);
if (e) {
return e;
}
m_vpnProtocol.reset(new OpenVpnProtocol()); m_vpnProtocol.reset(new OpenVpnProtocol());
break; }
; else if (protocol == Protocol::ShadowSocks) {
default: return ErrorCode::NotImplementedError;
// TODO, add later
return false;
;
} }
connect(m_vpnProtocol.data(), SIGNAL(connectionStateChanged(VpnProtocol::ConnectionState)), this, SLOT(onConnectionStateChanged(VpnProtocol::ConnectionState))); connect(m_vpnProtocol.data(), SIGNAL(connectionStateChanged(VpnProtocol::ConnectionState)), this, SLOT(onConnectionStateChanged(VpnProtocol::ConnectionState)));

View file

@ -5,7 +5,10 @@
#include <QString> #include <QString>
#include <QScopedPointer> #include <QScopedPointer>
#include "vpnprotocol.h" #include "protocols/vpnprotocol.h"
#include "core/defs.h"
using namespace amnezia;
class VpnConnection : public QObject class VpnConnection : public QObject
{ {
@ -13,13 +16,13 @@ class VpnConnection : public QObject
public: public:
explicit VpnConnection(QObject* parent = nullptr); explicit VpnConnection(QObject* parent = nullptr);
~VpnConnection(); ~VpnConnection() override = default;
enum class Protocol{OpenVpn};
static QString bytesToText(quint64 bytes); static QString bytesToText(quint64 bytes);
QString lastError() const; ErrorCode lastError() const;
bool connectToVpn(Protocol protocol = Protocol::OpenVpn); ErrorCode requestVpnConfig(const ServerCredentials &credentials, Protocol protocol);
ErrorCode connectToVpn(const ServerCredentials &credentials, Protocol protocol = Protocol::Any);
bool connected() const; bool connected() const;
bool disconnected() const; bool disconnected() const;
void disconnectFromVpn(); void disconnectFromVpn();