added button 'Reset settings and remove all data from the application'
This commit is contained in:
parent
3aaa7b62ef
commit
75489c00c2
18 changed files with 585 additions and 432 deletions
|
@ -1,23 +1,23 @@
|
|||
#include "servercontroller.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCryptographicHash>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QEventLoop>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QLoggingCategory>
|
||||
#include <QPointer>
|
||||
#include <QTimer>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QApplication>
|
||||
#include <QTemporaryFile>
|
||||
#include <QFileInfo>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QtConcurrent>
|
||||
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <chrono>
|
||||
|
@ -25,15 +25,14 @@
|
|||
|
||||
#include "containers/containers_defs.h"
|
||||
#include "logger.h"
|
||||
#include "scripts_registry.h"
|
||||
#include "server_defs.h"
|
||||
#include "settings.h"
|
||||
#include "scripts_registry.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#include <configurators/vpn_configurator.h>
|
||||
|
||||
ServerController::ServerController(std::shared_ptr<Settings> settings, QObject *parent) :
|
||||
m_settings(settings)
|
||||
ServerController::ServerController(std::shared_ptr<Settings> settings, QObject *parent) : m_settings(settings)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -42,10 +41,10 @@ ServerController::~ServerController()
|
|||
m_sshClient.disconnectFromHost();
|
||||
}
|
||||
|
||||
|
||||
ErrorCode ServerController::runScript(const ServerCredentials &credentials, QString script,
|
||||
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 &)> &cbReadStdOut,
|
||||
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr)
|
||||
{
|
||||
|
||||
auto error = m_sshClient.connectToHost(credentials);
|
||||
if (error != ErrorCode::NoError) {
|
||||
|
@ -82,7 +81,6 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
|
|||
qDebug().noquote() << "EXEC" << lineToExec;
|
||||
Logger::appendSshLog("Run command:" + lineToExec);
|
||||
|
||||
|
||||
error = m_sshClient.executeCommand(lineToExec, cbReadStdOut, cbReadStdErr);
|
||||
if (error != ErrorCode::NoError) {
|
||||
return error;
|
||||
|
@ -93,36 +91,36 @@ 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,
|
||||
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr)
|
||||
ErrorCode
|
||||
ServerController::runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script,
|
||||
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut,
|
||||
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr)
|
||||
{
|
||||
QString fileName = "/opt/amnezia/" + Utils::getRandomString(16) + ".sh";
|
||||
Logger::appendSshLog("Run container script for " + ContainerProps::containerToString(container) + ":\n" + script);
|
||||
|
||||
ErrorCode e = uploadTextFileToContainer(container, credentials, script, fileName);
|
||||
if (e) return e;
|
||||
if (e)
|
||||
return e;
|
||||
|
||||
QString runner = QString("sudo docker exec -i $CONTAINER_NAME bash %1 ").arg(fileName);
|
||||
e = runScript(credentials,
|
||||
replaceVars(runner, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
|
||||
e = runScript(credentials, replaceVars(runner, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
|
||||
|
||||
QString remover = QString("sudo docker exec -i $CONTAINER_NAME rm %1 ").arg(fileName);
|
||||
runScript(credentials,
|
||||
replaceVars(remover, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
|
||||
runScript(credentials, replaceVars(remover, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
|
||||
const ServerCredentials &credentials, const QString &file, const QString &path,
|
||||
ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container, const ServerCredentials &credentials,
|
||||
const QString &file, const QString &path,
|
||||
libssh::SftpOverwriteMode overwriteMode)
|
||||
{
|
||||
ErrorCode e = ErrorCode::NoError;
|
||||
QString tmpFileName = QString("/tmp/%1.tmp").arg(Utils::getRandomString(16));
|
||||
e = uploadFileToHost(credentials, file.toUtf8(), tmpFileName);
|
||||
if (e) return e;
|
||||
if (e)
|
||||
return e;
|
||||
|
||||
QString stdOut;
|
||||
auto cbReadStd = [&](const QString &data, libssh::Client &) {
|
||||
|
@ -131,61 +129,63 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
|
|||
};
|
||||
|
||||
// mkdir
|
||||
QString mkdir = QString("sudo docker exec -i $CONTAINER_NAME mkdir -p \"$(dirname %1)\"")
|
||||
.arg(path);
|
||||
|
||||
e = runScript(credentials,
|
||||
replaceVars(mkdir, genVarsForScript(credentials, container)));
|
||||
if (e) return e;
|
||||
QString mkdir = QString("sudo docker exec -i $CONTAINER_NAME mkdir -p \"$(dirname %1)\"").arg(path);
|
||||
|
||||
e = runScript(credentials, replaceVars(mkdir, genVarsForScript(credentials, container)));
|
||||
if (e)
|
||||
return e;
|
||||
|
||||
if (overwriteMode == libssh::SftpOverwriteMode::SftpOverwriteExisting) {
|
||||
e = runScript(credentials,
|
||||
replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(path),
|
||||
genVarsForScript(credentials, container)), cbReadStd, cbReadStd);
|
||||
genVarsForScript(credentials, container)),
|
||||
cbReadStd, cbReadStd);
|
||||
|
||||
if (e) return e;
|
||||
}
|
||||
else if (overwriteMode == libssh::SftpOverwriteMode::SftpAppendToExisting) {
|
||||
if (e)
|
||||
return e;
|
||||
} else if (overwriteMode == libssh::SftpOverwriteMode::SftpAppendToExisting) {
|
||||
e = runScript(credentials,
|
||||
replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(tmpFileName),
|
||||
genVarsForScript(credentials, container)), cbReadStd, cbReadStd);
|
||||
genVarsForScript(credentials, container)),
|
||||
cbReadStd, cbReadStd);
|
||||
|
||||
if (e) return e;
|
||||
if (e)
|
||||
return e;
|
||||
|
||||
e = runScript(credentials,
|
||||
replaceVars(QString("sudo docker exec -i $CONTAINER_NAME sh -c \"cat %1 >> %2\"").arg(tmpFileName).arg(path),
|
||||
genVarsForScript(credentials, container)), cbReadStd, cbReadStd);
|
||||
|
||||
if (e) return e;
|
||||
}
|
||||
else return ErrorCode::NotImplementedError;
|
||||
e = runScript(
|
||||
credentials,
|
||||
replaceVars(
|
||||
QString("sudo docker exec -i $CONTAINER_NAME sh -c \"cat %1 >> %2\"").arg(tmpFileName).arg(path),
|
||||
genVarsForScript(credentials, container)),
|
||||
cbReadStd, cbReadStd);
|
||||
|
||||
if (e)
|
||||
return e;
|
||||
} else
|
||||
return ErrorCode::NotImplementedError;
|
||||
|
||||
if (stdOut.contains("Error: No such container:")) {
|
||||
return ErrorCode::ServerContainerMissingError;
|
||||
}
|
||||
|
||||
runScript(credentials,
|
||||
replaceVars(QString("sudo shred %1").arg(tmpFileName),
|
||||
genVarsForScript(credentials, container)));
|
||||
replaceVars(QString("sudo shred %1").arg(tmpFileName), genVarsForScript(credentials, container)));
|
||||
|
||||
runScript(credentials,
|
||||
replaceVars(QString("sudo rm %1").arg(tmpFileName),
|
||||
genVarsForScript(credentials, container)));
|
||||
runScript(credentials, replaceVars(QString("sudo rm %1").arg(tmpFileName), genVarsForScript(credentials, container)));
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
QByteArray ServerController::getTextFileFromContainer(DockerContainer container,
|
||||
const ServerCredentials &credentials, const QString &path, ErrorCode *errorCode)
|
||||
QByteArray ServerController::getTextFileFromContainer(DockerContainer container, const ServerCredentials &credentials,
|
||||
const QString &path, ErrorCode *errorCode)
|
||||
{
|
||||
|
||||
if (errorCode) *errorCode = ErrorCode::NoError;
|
||||
|
||||
QString script = QString("sudo docker exec -i %1 sh -c \"xxd -p \'%2\'\"").
|
||||
arg(ContainerProps::containerToString(container)).arg(path);
|
||||
if (errorCode)
|
||||
*errorCode = ErrorCode::NoError;
|
||||
|
||||
QString script = QString("sudo docker exec -i %1 sh -c \"xxd -p \'%2\'\"")
|
||||
.arg(ContainerProps::containerToString(container))
|
||||
.arg(path);
|
||||
|
||||
QString stdOut;
|
||||
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||
|
@ -197,14 +197,13 @@ QByteArray ServerController::getTextFileFromContainer(DockerContainer container,
|
|||
|
||||
qDebug().noquote() << "Copy file from container stdout : \n" << stdOut;
|
||||
|
||||
|
||||
qDebug().noquote() << "Copy file from container END : \n" ;
|
||||
qDebug().noquote() << "Copy file from container END : \n";
|
||||
|
||||
return QByteArray::fromHex(stdOut.toUtf8());
|
||||
}
|
||||
|
||||
ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath,
|
||||
libssh::SftpOverwriteMode overwriteMode)
|
||||
ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data,
|
||||
const QString &remotePath, libssh::SftpOverwriteMode overwriteMode)
|
||||
{
|
||||
auto error = m_sshClient.connectToHost(credentials);
|
||||
if (error != ErrorCode::NoError) {
|
||||
|
@ -218,7 +217,8 @@ ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credential
|
|||
|
||||
qDebug() << "remotePath" << remotePath;
|
||||
|
||||
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName().toStdString(), remotePath.toStdString(), "non_desc");
|
||||
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName().toStdString(), remotePath.toStdString(),
|
||||
"non_desc");
|
||||
if (error != ErrorCode::NoError) {
|
||||
return error;
|
||||
}
|
||||
|
@ -227,8 +227,7 @@ ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credential
|
|||
|
||||
ErrorCode ServerController::removeAllContainers(const ServerCredentials &credentials)
|
||||
{
|
||||
return runScript(credentials,
|
||||
amnezia::scriptData(SharedScriptType::remove_all_containers));
|
||||
return runScript(credentials, amnezia::scriptData(SharedScriptType::remove_all_containers));
|
||||
}
|
||||
|
||||
ErrorCode ServerController::removeContainer(const ServerCredentials &credentials, DockerContainer container)
|
||||
|
@ -242,26 +241,31 @@ ErrorCode ServerController::setupContainer(const ServerCredentials &credentials,
|
|||
QJsonObject &config, bool isUpdate)
|
||||
{
|
||||
qDebug().noquote() << "ServerController::setupContainer" << ContainerProps::containerToString(container);
|
||||
//qDebug().noquote() << QJsonDocument(config).toJson();
|
||||
// qDebug().noquote() << QJsonDocument(config).toJson();
|
||||
ErrorCode e = ErrorCode::NoError;
|
||||
|
||||
e = isUserInSudo(credentials, container);
|
||||
if (e) return e;
|
||||
if (e)
|
||||
return e;
|
||||
|
||||
if (!isUpdate) {
|
||||
e = isServerPortBusy(credentials, container, config);
|
||||
if (e) return e;
|
||||
if (e)
|
||||
return e;
|
||||
}
|
||||
|
||||
e = isServerDpkgBusy(credentials, container);
|
||||
if (e) return e;
|
||||
if (e)
|
||||
return e;
|
||||
|
||||
e = installDockerWorker(credentials, container);
|
||||
if (e) return e;
|
||||
if (e)
|
||||
return e;
|
||||
qDebug().noquote() << "ServerController::setupContainer installDockerWorker finished";
|
||||
|
||||
e = prepareHostWorker(credentials, container, config);
|
||||
if (e) return e;
|
||||
if (e)
|
||||
return e;
|
||||
qDebug().noquote() << "ServerController::setupContainer prepareHostWorker finished";
|
||||
|
||||
removeContainer(credentials, container);
|
||||
|
@ -269,15 +273,18 @@ ErrorCode ServerController::setupContainer(const ServerCredentials &credentials,
|
|||
|
||||
qDebug().noquote() << "buildContainerWorker start";
|
||||
e = buildContainerWorker(credentials, container, config);
|
||||
if (e) return e;
|
||||
if (e)
|
||||
return e;
|
||||
qDebug().noquote() << "ServerController::setupContainer buildContainerWorker finished";
|
||||
|
||||
e = runContainerWorker(credentials, container, config);
|
||||
if (e) return e;
|
||||
if (e)
|
||||
return e;
|
||||
qDebug().noquote() << "ServerController::setupContainer runContainerWorker finished";
|
||||
|
||||
e = configureContainerWorker(credentials, container, config);
|
||||
if (e) return e;
|
||||
if (e)
|
||||
return e;
|
||||
qDebug().noquote() << "ServerController::setupContainer configureContainerWorker finished";
|
||||
|
||||
setupServerFirewall(credentials);
|
||||
|
@ -290,43 +297,22 @@ ErrorCode ServerController::updateContainer(const ServerCredentials &credentials
|
|||
const QJsonObject &oldConfig, QJsonObject &newConfig)
|
||||
{
|
||||
bool reinstallRequired = isReinstallContainerRequired(container, oldConfig, newConfig);
|
||||
qDebug() << "ServerController::updateContainer for container" << container << "reinstall required is" << reinstallRequired;
|
||||
qDebug() << "ServerController::updateContainer for container" << container << "reinstall required is"
|
||||
<< reinstallRequired;
|
||||
|
||||
if (reinstallRequired) {
|
||||
return setupContainer(credentials, container, newConfig, true);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ErrorCode e = configureContainerWorker(credentials, container, newConfig);
|
||||
if (e) return e;
|
||||
if (e)
|
||||
return e;
|
||||
|
||||
return startupContainerWorker(credentials, container, newConfig);
|
||||
}
|
||||
}
|
||||
|
||||
QJsonObject ServerController::createContainerInitialConfig(DockerContainer container, int port, TransportProto tp)
|
||||
{
|
||||
Proto mainProto = ContainerProps::defaultProtocol(container);
|
||||
|
||||
QJsonObject config {
|
||||
{ config_key::container, ContainerProps::containerToString(container) }
|
||||
};
|
||||
|
||||
QJsonObject protoConfig;
|
||||
protoConfig.insert(config_key::port, QString::number(port));
|
||||
protoConfig.insert(config_key::transport_proto, ProtocolProps::transportProtoToString(tp, mainProto));
|
||||
|
||||
|
||||
if (container == DockerContainer::Sftp) {
|
||||
protoConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
|
||||
protoConfig.insert(config_key::password, Utils::getRandomString(10));
|
||||
}
|
||||
|
||||
config.insert(ProtocolProps::protoToString(mainProto), protoConfig);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
bool ServerController::isReinstallContainerRequired(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig)
|
||||
bool ServerController::isReinstallContainerRequired(DockerContainer container, const QJsonObject &oldConfig,
|
||||
const QJsonObject &newConfig)
|
||||
{
|
||||
Proto mainProto = ContainerProps::defaultProtocol(container);
|
||||
|
||||
|
@ -334,24 +320,24 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
|
|||
const QJsonObject &newProtoConfig = newConfig.value(ProtocolProps::protoToString(mainProto)).toObject();
|
||||
|
||||
if (container == DockerContainer::OpenVpn) {
|
||||
if (oldProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto) !=
|
||||
newProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto))
|
||||
if (oldProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto)
|
||||
!= newProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto))
|
||||
return true;
|
||||
|
||||
if (oldProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort) !=
|
||||
newProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort))
|
||||
if (oldProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort)
|
||||
!= newProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (container == DockerContainer::Cloak) {
|
||||
if (oldProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort) !=
|
||||
newProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort))
|
||||
if (oldProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort)
|
||||
!= newProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (container == DockerContainer::ShadowSocks) {
|
||||
if (oldProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort) !=
|
||||
newProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort))
|
||||
if (oldProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort)
|
||||
!= newProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -374,48 +360,56 @@ ErrorCode ServerController::installDockerWorker(const ServerCredentials &credent
|
|||
return ErrorCode::NoError;
|
||||
};
|
||||
|
||||
ErrorCode error = runScript(credentials,
|
||||
replaceVars(amnezia::scriptData(SharedScriptType::install_docker),
|
||||
genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
|
||||
ErrorCode error =
|
||||
runScript(credentials,
|
||||
replaceVars(amnezia::scriptData(SharedScriptType::install_docker), genVarsForScript(credentials)),
|
||||
cbReadStdOut, cbReadStdErr);
|
||||
|
||||
if (stdOut.contains("command not found")) return ErrorCode::ServerDockerFailedError;
|
||||
if (stdOut.contains("command not found"))
|
||||
return ErrorCode::ServerDockerFailedError;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
ErrorCode ServerController::prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
|
||||
ErrorCode ServerController::prepareHostWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &config)
|
||||
{
|
||||
// create folder on host
|
||||
return runScript(credentials,
|
||||
replaceVars(amnezia::scriptData(SharedScriptType::prepare_host),
|
||||
genVarsForScript(credentials, container)));
|
||||
return runScript(
|
||||
credentials,
|
||||
replaceVars(amnezia::scriptData(SharedScriptType::prepare_host), genVarsForScript(credentials, container)));
|
||||
}
|
||||
|
||||
ErrorCode ServerController::buildContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
|
||||
ErrorCode ServerController::buildContainerWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &config)
|
||||
{
|
||||
ErrorCode e = uploadFileToHost(credentials, amnezia::scriptData(ProtocolScriptType::dockerfile, container).toUtf8(),
|
||||
amnezia::server::getDockerfileFolder(container) + "/Dockerfile");
|
||||
|
||||
if (e) return e;
|
||||
if (e)
|
||||
return e;
|
||||
|
||||
QString stdOut;
|
||||
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||
stdOut += data + "\n";
|
||||
return ErrorCode::NoError;
|
||||
};
|
||||
// auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
|
||||
// stdOut += data + "\n";
|
||||
// };
|
||||
// auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
|
||||
// stdOut += data + "\n";
|
||||
// };
|
||||
|
||||
e = runScript(credentials,
|
||||
replaceVars(amnezia::scriptData(SharedScriptType::build_container),
|
||||
genVarsForScript(credentials, container, config)), cbReadStdOut);
|
||||
if (e) return e;
|
||||
genVarsForScript(credentials, container, config)),
|
||||
cbReadStdOut);
|
||||
if (e)
|
||||
return e;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
ErrorCode ServerController::runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config)
|
||||
ErrorCode ServerController::runContainerWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||
QJsonObject &config)
|
||||
{
|
||||
QString stdOut;
|
||||
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||
|
@ -428,21 +422,26 @@ ErrorCode ServerController::runContainerWorker(const ServerCredentials &credenti
|
|||
|
||||
ErrorCode e = runScript(credentials,
|
||||
replaceVars(amnezia::scriptData(ProtocolScriptType::run_container, container),
|
||||
genVarsForScript(credentials, container, config)), cbReadStdOut);
|
||||
genVarsForScript(credentials, container, config)),
|
||||
cbReadStdOut);
|
||||
|
||||
qDebug() << "cbReadStdOut: " << stdOut;
|
||||
|
||||
if (stdOut.contains("docker: Error response from daemon"))
|
||||
return ErrorCode::ServerDockerFailedError;
|
||||
|
||||
if (stdOut.contains("docker: Error response from daemon")) return ErrorCode::ServerDockerFailedError;
|
||||
|
||||
if (stdOut.contains("address already in use")) return ErrorCode::ServerPortAlreadyAllocatedError;
|
||||
if (stdOut.contains("is already in use by container")) return ErrorCode::ServerPortAlreadyAllocatedError;
|
||||
if (stdOut.contains("invalid publish")) return ErrorCode::ServerDockerFailedError;
|
||||
if (stdOut.contains("address already in use"))
|
||||
return ErrorCode::ServerPortAlreadyAllocatedError;
|
||||
if (stdOut.contains("is already in use by container"))
|
||||
return ErrorCode::ServerPortAlreadyAllocatedError;
|
||||
if (stdOut.contains("invalid publish"))
|
||||
return ErrorCode::ServerDockerFailedError;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
ErrorCode ServerController::configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config)
|
||||
ErrorCode ServerController::configureContainerWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||
QJsonObject &config)
|
||||
{
|
||||
QString stdOut;
|
||||
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||
|
@ -454,19 +453,18 @@ ErrorCode ServerController::configureContainerWorker(const ServerCredentials &cr
|
|||
return ErrorCode::NoError;
|
||||
};
|
||||
|
||||
|
||||
ErrorCode e = runContainerScript(credentials, container,
|
||||
replaceVars(amnezia::scriptData(ProtocolScriptType::configure_container, container),
|
||||
genVarsForScript(credentials, container, config)),
|
||||
cbReadStdOut, cbReadStdErr);
|
||||
|
||||
|
||||
m_configurator->updateContainerConfigAfterInstallation(container, config, stdOut);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
ErrorCode ServerController::startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
|
||||
ErrorCode ServerController::startupContainerWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &config)
|
||||
{
|
||||
QString script = amnezia::scriptData(ProtocolScriptType::container_startup, container);
|
||||
|
||||
|
@ -477,14 +475,17 @@ ErrorCode ServerController::startupContainerWorker(const ServerCredentials &cred
|
|||
ErrorCode e = uploadTextFileToContainer(container, credentials,
|
||||
replaceVars(script, genVarsForScript(credentials, container, config)),
|
||||
"/opt/amnezia/start.sh");
|
||||
if (e) return e;
|
||||
if (e)
|
||||
return e;
|
||||
|
||||
return runScript(credentials,
|
||||
replaceVars("sudo docker exec -d $CONTAINER_NAME sh -c \"chmod a+x /opt/amnezia/start.sh && /opt/amnezia/start.sh\"",
|
||||
replaceVars("sudo docker exec -d $CONTAINER_NAME sh -c \"chmod a+x /opt/amnezia/start.sh && "
|
||||
"/opt/amnezia/start.sh\"",
|
||||
genVarsForScript(credentials, container, config)));
|
||||
}
|
||||
|
||||
ServerController::Vars ServerController::genVarsForScript(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
|
||||
ServerController::Vars ServerController::genVarsForScript(const ServerCredentials &credentials,
|
||||
DockerContainer container, const QJsonObject &config)
|
||||
{
|
||||
const QJsonObject &openvpnConfig = config.value(ProtocolProps::protoToString(Proto::OpenVpn)).toObject();
|
||||
const QJsonObject &cloakConfig = config.value(ProtocolProps::protoToString(Proto::Cloak)).toObject();
|
||||
|
@ -495,85 +496,102 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
|
|||
|
||||
Vars vars;
|
||||
|
||||
vars.append({{"$REMOTE_HOST", credentials.hostName}});
|
||||
vars.append({ { "$REMOTE_HOST", credentials.hostName } });
|
||||
|
||||
// OpenVPN vars
|
||||
vars.append({{"$OPENVPN_SUBNET_IP", openvpnConfig.value(config_key::subnet_address).toString(protocols::openvpn::defaultSubnetAddress) }});
|
||||
vars.append({{"$OPENVPN_SUBNET_CIDR", openvpnConfig.value(config_key::subnet_cidr).toString(protocols::openvpn::defaultSubnetCidr) }});
|
||||
vars.append({{"$OPENVPN_SUBNET_MASK", openvpnConfig.value(config_key::subnet_mask).toString(protocols::openvpn::defaultSubnetMask) }});
|
||||
vars.append(
|
||||
{ { "$OPENVPN_SUBNET_IP",
|
||||
openvpnConfig.value(config_key::subnet_address).toString(protocols::openvpn::defaultSubnetAddress) } });
|
||||
vars.append({ { "$OPENVPN_SUBNET_CIDR",
|
||||
openvpnConfig.value(config_key::subnet_cidr).toString(protocols::openvpn::defaultSubnetCidr) } });
|
||||
vars.append({ { "$OPENVPN_SUBNET_MASK",
|
||||
openvpnConfig.value(config_key::subnet_mask).toString(protocols::openvpn::defaultSubnetMask) } });
|
||||
|
||||
vars.append({{"$OPENVPN_PORT", openvpnConfig.value(config_key::port).toString(protocols::openvpn::defaultPort) }});
|
||||
vars.append({{"$OPENVPN_TRANSPORT_PROTO", openvpnConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto) }});
|
||||
vars.append({ { "$OPENVPN_PORT", openvpnConfig.value(config_key::port).toString(protocols::openvpn::defaultPort) } });
|
||||
vars.append(
|
||||
{ { "$OPENVPN_TRANSPORT_PROTO",
|
||||
openvpnConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto) } });
|
||||
|
||||
bool isNcpDisabled = openvpnConfig.value(config_key::ncp_disable).toBool(protocols::openvpn::defaultNcpDisable);
|
||||
vars.append({{"$OPENVPN_NCP_DISABLE", isNcpDisabled ? protocols::openvpn::ncpDisableString : "" }});
|
||||
vars.append({ { "$OPENVPN_NCP_DISABLE", isNcpDisabled ? protocols::openvpn::ncpDisableString : "" } });
|
||||
|
||||
vars.append({{"$OPENVPN_CIPHER", openvpnConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher) }});
|
||||
vars.append({{"$OPENVPN_HASH", openvpnConfig.value(config_key::hash).toString(protocols::openvpn::defaultHash) }});
|
||||
vars.append({ { "$OPENVPN_CIPHER",
|
||||
openvpnConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher) } });
|
||||
vars.append({ { "$OPENVPN_HASH", openvpnConfig.value(config_key::hash).toString(protocols::openvpn::defaultHash) } });
|
||||
|
||||
bool isTlsAuth = openvpnConfig.value(config_key::tls_auth).toBool(protocols::openvpn::defaultTlsAuth);
|
||||
vars.append({{"$OPENVPN_TLS_AUTH", isTlsAuth ? protocols::openvpn::tlsAuthString : "" }});
|
||||
vars.append({ { "$OPENVPN_TLS_AUTH", isTlsAuth ? protocols::openvpn::tlsAuthString : "" } });
|
||||
if (!isTlsAuth) {
|
||||
// erase $OPENVPN_TA_KEY, so it will not set in OpenVpnConfigurator::genOpenVpnConfig
|
||||
vars.append({{"$OPENVPN_TA_KEY", "" }});
|
||||
vars.append({ { "$OPENVPN_TA_KEY", "" } });
|
||||
}
|
||||
|
||||
vars.append({{"$OPENVPN_ADDITIONAL_CLIENT_CONFIG", openvpnConfig.value(config_key::additional_client_config).
|
||||
toString(protocols::openvpn::defaultAdditionalClientConfig) }});
|
||||
vars.append({{"$OPENVPN_ADDITIONAL_SERVER_CONFIG", openvpnConfig.value(config_key::additional_server_config).
|
||||
toString(protocols::openvpn::defaultAdditionalServerConfig) }});
|
||||
vars.append({ { "$OPENVPN_ADDITIONAL_CLIENT_CONFIG",
|
||||
openvpnConfig.value(config_key::additional_client_config)
|
||||
.toString(protocols::openvpn::defaultAdditionalClientConfig) } });
|
||||
vars.append({ { "$OPENVPN_ADDITIONAL_SERVER_CONFIG",
|
||||
openvpnConfig.value(config_key::additional_server_config)
|
||||
.toString(protocols::openvpn::defaultAdditionalServerConfig) } });
|
||||
|
||||
// ShadowSocks vars
|
||||
vars.append({{"$SHADOWSOCKS_SERVER_PORT", ssConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort) }});
|
||||
vars.append({{"$SHADOWSOCKS_LOCAL_PORT", ssConfig.value(config_key::local_port).toString(protocols::shadowsocks::defaultLocalProxyPort) }});
|
||||
vars.append({{"$SHADOWSOCKS_CIPHER", ssConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher) }});
|
||||
vars.append({ { "$SHADOWSOCKS_SERVER_PORT",
|
||||
ssConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort) } });
|
||||
vars.append({ { "$SHADOWSOCKS_LOCAL_PORT",
|
||||
ssConfig.value(config_key::local_port).toString(protocols::shadowsocks::defaultLocalProxyPort) } });
|
||||
vars.append({ { "$SHADOWSOCKS_CIPHER",
|
||||
ssConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher) } });
|
||||
|
||||
vars.append({{"$CONTAINER_NAME", ContainerProps::containerToString(container)}});
|
||||
vars.append({{"$DOCKERFILE_FOLDER", "/opt/amnezia/" + ContainerProps::containerToString(container)}});
|
||||
vars.append({ { "$CONTAINER_NAME", ContainerProps::containerToString(container) } });
|
||||
vars.append({ { "$DOCKERFILE_FOLDER", "/opt/amnezia/" + ContainerProps::containerToString(container) } });
|
||||
|
||||
// Cloak vars
|
||||
vars.append({{"$CLOAK_SERVER_PORT", cloakConfig.value(config_key::port).toString(protocols::cloak::defaultPort) }});
|
||||
vars.append({{"$FAKE_WEB_SITE_ADDRESS", cloakConfig.value(config_key::site).toString(protocols::cloak::defaultRedirSite) }});
|
||||
vars.append({ { "$CLOAK_SERVER_PORT", cloakConfig.value(config_key::port).toString(protocols::cloak::defaultPort) } });
|
||||
vars.append({ { "$FAKE_WEB_SITE_ADDRESS",
|
||||
cloakConfig.value(config_key::site).toString(protocols::cloak::defaultRedirSite) } });
|
||||
|
||||
// Wireguard vars
|
||||
vars.append({{"$WIREGUARD_SUBNET_IP", wireguarConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress) }});
|
||||
vars.append({{"$WIREGUARD_SUBNET_CIDR", wireguarConfig.value(config_key::subnet_cidr).toString(protocols::wireguard::defaultSubnetCidr) }});
|
||||
vars.append({{"$WIREGUARD_SUBNET_MASK", wireguarConfig.value(config_key::subnet_mask).toString(protocols::wireguard::defaultSubnetMask) }});
|
||||
vars.append(
|
||||
{ { "$WIREGUARD_SUBNET_IP",
|
||||
wireguarConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress) } });
|
||||
vars.append({ { "$WIREGUARD_SUBNET_CIDR",
|
||||
wireguarConfig.value(config_key::subnet_cidr).toString(protocols::wireguard::defaultSubnetCidr) } });
|
||||
vars.append({ { "$WIREGUARD_SUBNET_MASK",
|
||||
wireguarConfig.value(config_key::subnet_mask).toString(protocols::wireguard::defaultSubnetMask) } });
|
||||
|
||||
vars.append({{"$WIREGUARD_SERVER_PORT", wireguarConfig.value(config_key::port).toString(protocols::wireguard::defaultPort) }});
|
||||
vars.append({ { "$WIREGUARD_SERVER_PORT",
|
||||
wireguarConfig.value(config_key::port).toString(protocols::wireguard::defaultPort) } });
|
||||
|
||||
// IPsec vars
|
||||
vars.append({{"$IPSEC_VPN_L2TP_NET", "192.168.42.0/24"}});
|
||||
vars.append({{"$IPSEC_VPN_L2TP_POOL", "192.168.42.10-192.168.42.250"}});
|
||||
vars.append({{"$IPSEC_VPN_L2TP_LOCAL", "192.168.42.1"}});
|
||||
vars.append({ { "$IPSEC_VPN_L2TP_NET", "192.168.42.0/24" } });
|
||||
vars.append({ { "$IPSEC_VPN_L2TP_POOL", "192.168.42.10-192.168.42.250" } });
|
||||
vars.append({ { "$IPSEC_VPN_L2TP_LOCAL", "192.168.42.1" } });
|
||||
|
||||
vars.append({{"$IPSEC_VPN_XAUTH_NET", "192.168.43.0/24"}});
|
||||
vars.append({{"$IPSEC_VPN_XAUTH_POOL", "192.168.43.10-192.168.43.250"}});
|
||||
vars.append({ { "$IPSEC_VPN_XAUTH_NET", "192.168.43.0/24" } });
|
||||
vars.append({ { "$IPSEC_VPN_XAUTH_POOL", "192.168.43.10-192.168.43.250" } });
|
||||
|
||||
vars.append({{"$IPSEC_VPN_SHA2_TRUNCBUG", "yes"}});
|
||||
vars.append({ { "$IPSEC_VPN_SHA2_TRUNCBUG", "yes" } });
|
||||
|
||||
vars.append({{"$IPSEC_VPN_VPN_ANDROID_MTU_FIX", "yes"}});
|
||||
vars.append({{"$IPSEC_VPN_DISABLE_IKEV2", "no"}});
|
||||
vars.append({{"$IPSEC_VPN_DISABLE_L2TP", "no"}});
|
||||
vars.append({{"$IPSEC_VPN_DISABLE_XAUTH", "no"}});
|
||||
vars.append({ { "$IPSEC_VPN_VPN_ANDROID_MTU_FIX", "yes" } });
|
||||
vars.append({ { "$IPSEC_VPN_DISABLE_IKEV2", "no" } });
|
||||
vars.append({ { "$IPSEC_VPN_DISABLE_L2TP", "no" } });
|
||||
vars.append({ { "$IPSEC_VPN_DISABLE_XAUTH", "no" } });
|
||||
|
||||
vars.append({{"$IPSEC_VPN_C2C_TRAFFIC", "no"}});
|
||||
|
||||
vars.append({{"$PRIMARY_SERVER_DNS", m_settings->primaryDns()}});
|
||||
vars.append({{"$SECONDARY_SERVER_DNS", m_settings->secondaryDns()}});
|
||||
vars.append({ { "$IPSEC_VPN_C2C_TRAFFIC", "no" } });
|
||||
|
||||
vars.append({ { "$PRIMARY_SERVER_DNS", m_settings->primaryDns() } });
|
||||
vars.append({ { "$SECONDARY_SERVER_DNS", m_settings->secondaryDns() } });
|
||||
|
||||
// Sftp vars
|
||||
vars.append({{"$SFTP_PORT", sftpConfig.value(config_key::port).toString(QString::number(ProtocolProps::defaultPort(Proto::Sftp))) }});
|
||||
vars.append({{"$SFTP_USER", sftpConfig.value(config_key::userName).toString() }});
|
||||
vars.append({{"$SFTP_PASSWORD", sftpConfig.value(config_key::password).toString() }});
|
||||
|
||||
vars.append(
|
||||
{ { "$SFTP_PORT",
|
||||
sftpConfig.value(config_key::port).toString(QString::number(ProtocolProps::defaultPort(Proto::Sftp))) } });
|
||||
vars.append({ { "$SFTP_USER", sftpConfig.value(config_key::userName).toString() } });
|
||||
vars.append({ { "$SFTP_PASSWORD", sftpConfig.value(config_key::password).toString() } });
|
||||
|
||||
QString serverIp = Utils::getIPAddress(credentials.hostName);
|
||||
if (!serverIp.isEmpty()) {
|
||||
vars.append({{"$SERVER_IP_ADDRESS", serverIp}});
|
||||
}
|
||||
else {
|
||||
vars.append({ { "$SERVER_IP_ADDRESS", serverIp } });
|
||||
} else {
|
||||
qWarning() << "ServerController::genVarsForScript unable to resolve address for credentials.hostName";
|
||||
}
|
||||
|
||||
|
@ -592,10 +610,11 @@ QString ServerController::checkSshConnection(const ServerCredentials &credential
|
|||
return ErrorCode::NoError;
|
||||
};
|
||||
|
||||
ErrorCode e = runScript(credentials,
|
||||
amnezia::scriptData(SharedScriptType::check_connection), cbReadStdOut, cbReadStdErr);
|
||||
ErrorCode e =
|
||||
runScript(credentials, amnezia::scriptData(SharedScriptType::check_connection), cbReadStdOut, cbReadStdErr);
|
||||
|
||||
if (errorCode) *errorCode = e;
|
||||
if (errorCode)
|
||||
*errorCode = e;
|
||||
|
||||
return stdOut;
|
||||
}
|
||||
|
@ -607,23 +626,24 @@ void ServerController::setCancelInstallation(const bool cancel)
|
|||
|
||||
ErrorCode ServerController::setupServerFirewall(const ServerCredentials &credentials)
|
||||
{
|
||||
return runScript(credentials,
|
||||
replaceVars(amnezia::scriptData(SharedScriptType::setup_host_firewall),
|
||||
genVarsForScript(credentials)));
|
||||
return runScript(
|
||||
credentials,
|
||||
replaceVars(amnezia::scriptData(SharedScriptType::setup_host_firewall), genVarsForScript(credentials)));
|
||||
}
|
||||
|
||||
QString ServerController::replaceVars(const QString &script, const Vars &vars)
|
||||
{
|
||||
QString s = script;
|
||||
for (const QPair<QString, QString> &var : vars) {
|
||||
//qDebug() << "Replacing" << var.first << var.second;
|
||||
// qDebug() << "Replacing" << var.first << var.second;
|
||||
s.replace(var.first, var.second);
|
||||
}
|
||||
//qDebug().noquote() << script;
|
||||
// qDebug().noquote() << script;
|
||||
return s;
|
||||
}
|
||||
|
||||
ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
|
||||
ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &config)
|
||||
{
|
||||
if (container == DockerContainer::Dns) {
|
||||
return ErrorCode::NoError;
|
||||
|
@ -646,8 +666,10 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential
|
|||
QStringList fixedPorts = ContainerProps::fixedPortsForContainer(container);
|
||||
|
||||
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 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);
|
||||
|
@ -660,8 +682,8 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential
|
|||
script = script.append(" | grep LISTEN");
|
||||
}
|
||||
|
||||
ErrorCode errorCode = runScript(credentials,
|
||||
replaceVars(script, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
|
||||
ErrorCode errorCode = runScript(credentials, replaceVars(script, genVarsForScript(credentials, container)),
|
||||
cbReadStdOut, cbReadStdErr);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
return errorCode;
|
||||
}
|
||||
|
@ -689,9 +711,11 @@ ErrorCode ServerController::isUserInSudo(const ServerCredentials &credentials, D
|
|||
};
|
||||
|
||||
const QString scriptData = amnezia::scriptData(SharedScriptType::check_user_in_sudo);
|
||||
ErrorCode error = runScript(credentials, replaceVars(scriptData, genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
|
||||
ErrorCode error =
|
||||
runScript(credentials, replaceVars(scriptData, genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
|
||||
|
||||
if (!stdOut.contains("sudo")) return ErrorCode::ServerUserNotInSudo;
|
||||
if (!stdOut.contains("sudo"))
|
||||
return ErrorCode::ServerUserNotInSudo;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -718,7 +742,8 @@ ErrorCode ServerController::isServerDpkgBusy(const ServerCredentials &credential
|
|||
stdOut.clear();
|
||||
runScript(credentials,
|
||||
replaceVars(amnezia::scriptData(SharedScriptType::check_server_is_busy),
|
||||
genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
|
||||
genVarsForScript(credentials)),
|
||||
cbReadStdOut, cbReadStdErr);
|
||||
if (!stdOut.isEmpty() || stdOut.contains("Unable to acquire the dpkg frontend lock")) {
|
||||
emit serverIsBusy(true);
|
||||
QThread::msleep(1000);
|
||||
|
@ -738,7 +763,8 @@ ErrorCode ServerController::isServerDpkgBusy(const ServerCredentials &credential
|
|||
return future.result();
|
||||
}
|
||||
|
||||
ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap<DockerContainer, QJsonObject> &installedContainers)
|
||||
ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredentials &credentials,
|
||||
QMap<DockerContainer, QJsonObject> &installedContainers)
|
||||
{
|
||||
QString stdOut;
|
||||
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||
|
@ -770,13 +796,10 @@ ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredential
|
|||
QString transportProto = containerAndPortMatch.captured(3);
|
||||
DockerContainer container = ContainerProps::containerFromString(name);
|
||||
Proto mainProto = ContainerProps::defaultProtocol(container);
|
||||
QJsonObject config {
|
||||
{ config_key::container, name },
|
||||
{ ProtocolProps::protoToString(mainProto), QJsonObject {
|
||||
{ config_key::port, port },
|
||||
{ config_key::transport_proto, transportProto }}
|
||||
}
|
||||
};
|
||||
QJsonObject config { { config_key::container, name },
|
||||
{ ProtocolProps::protoToString(mainProto),
|
||||
QJsonObject { { config_key::port, port },
|
||||
{ config_key::transport_proto, transportProto } } } };
|
||||
installedContainers.insert(container, config);
|
||||
}
|
||||
}
|
||||
|
@ -784,7 +807,8 @@ ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredential
|
|||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
ErrorCode ServerController::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &callback)
|
||||
ErrorCode ServerController::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey,
|
||||
const std::function<QString()> &callback)
|
||||
{
|
||||
auto error = m_sshClient.getDecryptedPrivateKey(credentials, decryptedPrivateKey, callback);
|
||||
return error;
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
#include <QJsonObject>
|
||||
#include <QObject>
|
||||
|
||||
#include "defs.h"
|
||||
#include "containers/containers_defs.h"
|
||||
#include "defs.h"
|
||||
#include "sshclient.h"
|
||||
|
||||
class Settings;
|
||||
|
@ -24,52 +24,61 @@ public:
|
|||
|
||||
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 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);
|
||||
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials,
|
||||
QMap<DockerContainer, QJsonObject> &installedContainers);
|
||||
|
||||
// create initial config - generate passwords, etc
|
||||
QJsonObject createContainerInitialConfig(DockerContainer container, int port, TransportProto tp);
|
||||
ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
|
||||
ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &config = QJsonObject());
|
||||
|
||||
ErrorCode uploadTextFileToContainer(DockerContainer container, const ServerCredentials &credentials,
|
||||
const QString &file, const QString &path,
|
||||
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);
|
||||
|
||||
QString replaceVars(const QString &script, const Vars &vars);
|
||||
Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None, const QJsonObject &config = QJsonObject());
|
||||
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,
|
||||
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
|
||||
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
|
||||
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
|
||||
|
||||
ErrorCode runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script,
|
||||
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
|
||||
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
|
||||
ErrorCode
|
||||
runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script,
|
||||
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
|
||||
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
|
||||
|
||||
QString checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr);
|
||||
|
||||
void setCancelInstallation(const bool cancel);
|
||||
|
||||
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &callback);
|
||||
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());
|
||||
ErrorCode buildContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
|
||||
ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &config = QJsonObject());
|
||||
ErrorCode buildContainerWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &config = QJsonObject());
|
||||
ErrorCode runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
|
||||
ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
|
||||
ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container,
|
||||
QJsonObject &config);
|
||||
|
||||
ErrorCode isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config);
|
||||
bool isReinstallContainerRequired(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig);
|
||||
ErrorCode isServerPortBusy(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &config);
|
||||
bool isReinstallContainerRequired(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 uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath,
|
||||
libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting);
|
||||
|
||||
ErrorCode setupServerFirewall(const ServerCredentials &credentials);
|
||||
|
||||
|
|
|
@ -274,5 +274,6 @@
|
|||
<file>ui/qml/Pages2/PageProtocolShadowSocksSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageProtocolCloakSettings.qml</file>
|
||||
<file>ui/qml/Pages2/PageProtocolRaw.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsLogging.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -1,30 +1,28 @@
|
|||
#include "secure_qsettings.h"
|
||||
#include "platforms/ios/MobileUtils.h"
|
||||
|
||||
#include "QAead.h"
|
||||
#include "QBlockCipher.h"
|
||||
#include "utilities.h"
|
||||
#include <QDataStream>
|
||||
#include <QDebug>
|
||||
#include <QEventLoop>
|
||||
#include <QIODevice>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QRandomGenerator>
|
||||
#include <QSharedPointer>
|
||||
#include <QTimer>
|
||||
#include "utilities.h"
|
||||
#include <QRandomGenerator>
|
||||
#include "QAead.h"
|
||||
#include "QBlockCipher.h"
|
||||
|
||||
using namespace QKeychain;
|
||||
|
||||
SecureQSettings::SecureQSettings(const QString &organization, const QString &application, QObject *parent)
|
||||
: QObject{parent},
|
||||
m_settings(organization, application, parent),
|
||||
encryptedKeys({"Servers/serversList"})
|
||||
: QObject { parent }, m_settings(organization, application, parent), encryptedKeys({ "Servers/serversList" })
|
||||
{
|
||||
bool encrypted = m_settings.value("Conf/encrypted").toBool();
|
||||
|
||||
// convert settings to encrypted for if updated to >= 2.1.0
|
||||
if (encryptionRequired() && ! encrypted) {
|
||||
if (encryptionRequired() && !encrypted) {
|
||||
for (const QString &key : m_settings.allKeys()) {
|
||||
if (encryptedKeys.contains(key)) {
|
||||
const QVariant &val = value(key);
|
||||
|
@ -44,15 +42,15 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue
|
|||
return m_cache.value(key);
|
||||
}
|
||||
|
||||
if (!m_settings.contains(key)) return defaultValue;
|
||||
if (!m_settings.contains(key))
|
||||
return defaultValue;
|
||||
|
||||
QVariant retVal;
|
||||
|
||||
// check if value is not encrypted, v. < 2.0.x
|
||||
retVal = m_settings.value(key);
|
||||
if (retVal.isValid()) {
|
||||
if (retVal.userType() == QVariant::ByteArray &&
|
||||
retVal.toByteArray().mid(0, magicString.size()) == magicString) {
|
||||
if (retVal.userType() == QVariant::ByteArray && retVal.toByteArray().mid(0, magicString.size()) == magicString) {
|
||||
|
||||
if (getEncKey().isEmpty() || getEncIv().isEmpty()) {
|
||||
qCritical() << "SecureQSettings::setValue Decryption requested, but key is empty";
|
||||
|
@ -71,8 +69,7 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue
|
|||
retVal = QVariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
qWarning() << "SecureQSettings::value invalid QVariant value";
|
||||
retVal = QVariant();
|
||||
}
|
||||
|
@ -95,14 +92,12 @@ void SecureQSettings::setValue(const QString &key, const QVariant &value)
|
|||
|
||||
QByteArray encryptedValue = encryptText(decryptedValue);
|
||||
m_settings.setValue(key, magicString + encryptedValue);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
qCritical() << "SecureQSettings::setValue Encryption required, but key is empty";
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
m_settings.setValue(key, value);
|
||||
}
|
||||
|
||||
|
@ -139,7 +134,8 @@ QByteArray SecureQSettings::backupAppConfig() const
|
|||
bool SecureQSettings::restoreAppConfig(const QByteArray &json)
|
||||
{
|
||||
QJsonObject cfg = QJsonDocument::fromJson(json).object();
|
||||
if (cfg.isEmpty()) return false;
|
||||
if (cfg.isEmpty())
|
||||
return false;
|
||||
|
||||
for (const QString &key : cfg.keys()) {
|
||||
setValue(key, cfg.value(key).toVariant());
|
||||
|
@ -149,14 +145,13 @@ bool SecureQSettings::restoreAppConfig(const QByteArray &json)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
QByteArray SecureQSettings::encryptText(const QByteArray& value) const
|
||||
QByteArray SecureQSettings::encryptText(const QByteArray &value) const
|
||||
{
|
||||
QSimpleCrypto::QBlockCipher cipher;
|
||||
return cipher.encryptAesBlockCipher(value, getEncKey(), getEncIv());
|
||||
}
|
||||
|
||||
QByteArray SecureQSettings::decryptText(const QByteArray& ba) const
|
||||
QByteArray SecureQSettings::decryptText(const QByteArray &ba) const
|
||||
{
|
||||
QSimpleCrypto::QBlockCipher cipher;
|
||||
return cipher.decryptAesBlockCipher(ba, getEncKey(), getEncIv());
|
||||
|
@ -228,13 +223,11 @@ QByteArray SecureQSettings::getSecTag(const QString &tag)
|
|||
job->setAutoDelete(false);
|
||||
job->setKey(tag);
|
||||
QEventLoop loop;
|
||||
job->connect(job.data(), &ReadPasswordJob::finished, job.data(), [&loop](){
|
||||
loop.quit();
|
||||
});
|
||||
job->connect(job.data(), &ReadPasswordJob::finished, job.data(), [&loop]() { loop.quit(); });
|
||||
job->start();
|
||||
loop.exec();
|
||||
|
||||
if ( job->error() ) {
|
||||
if (job->error()) {
|
||||
qCritical() << "SecureQSettings::getSecTag Error:" << job->errorString();
|
||||
}
|
||||
|
||||
|
@ -249,9 +242,7 @@ void SecureQSettings::setSecTag(const QString &tag, const QByteArray &data)
|
|||
job->setBinaryData(data);
|
||||
QEventLoop loop;
|
||||
QTimer::singleShot(1000, &loop, SLOT(quit()));
|
||||
job->connect(job.data(), &WritePasswordJob::finished, job.data(), [&loop](){
|
||||
loop.quit();
|
||||
});
|
||||
job->connect(job.data(), &WritePasswordJob::finished, job.data(), [&loop]() { loop.quit(); });
|
||||
job->start();
|
||||
loop.exec();
|
||||
|
||||
|
@ -260,4 +251,10 @@ void SecureQSettings::setSecTag(const QString &tag, const QByteArray &data)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void SecureQSettings::clearSettings()
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
m_settings.clear();
|
||||
m_cache.clear();
|
||||
sync();
|
||||
}
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
#ifndef SECUREQSETTINGS_H
|
||||
#define SECUREQSETTINGS_H
|
||||
|
||||
#include <QSettings>
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include <QObject>
|
||||
#include <QSettings>
|
||||
|
||||
#include "keychain.h"
|
||||
|
||||
|
||||
constexpr const char* settingsKeyTag = "settingsKeyTag";
|
||||
constexpr const char* settingsIvTag = "settingsIvTag";
|
||||
constexpr const char* keyChainName = "AmneziaVPN-Keychain";
|
||||
|
||||
constexpr const char *settingsKeyTag = "settingsKeyTag";
|
||||
constexpr const char *settingsIvTag = "settingsIvTag";
|
||||
constexpr const char *keyChainName = "AmneziaVPN-Keychain";
|
||||
|
||||
class SecureQSettings : public QObject
|
||||
{
|
||||
public:
|
||||
explicit SecureQSettings(const QString &organization, const QString &application = QString(), QObject *parent = nullptr);
|
||||
explicit SecureQSettings(const QString &organization, const QString &application = QString(),
|
||||
QObject *parent = nullptr);
|
||||
|
||||
QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
|
||||
void setValue(const QString &key, const QVariant &value);
|
||||
|
@ -28,7 +27,7 @@ public:
|
|||
bool restoreAppConfig(const QByteArray &json);
|
||||
|
||||
QByteArray encryptText(const QByteArray &value) const;
|
||||
QByteArray decryptText(const QByteArray& ba) const;
|
||||
QByteArray decryptText(const QByteArray &ba) const;
|
||||
|
||||
bool encryptionRequired() const;
|
||||
|
||||
|
@ -38,6 +37,8 @@ public:
|
|||
static QByteArray getSecTag(const QString &tag);
|
||||
static void setSecTag(const QString &tag, const QByteArray &data);
|
||||
|
||||
void clearSettings();
|
||||
|
||||
private:
|
||||
QSettings m_settings;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "version.h"
|
||||
#include "settings.h"
|
||||
#include "utilities.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "containers/containers_defs.h"
|
||||
#include "logger.h"
|
||||
|
@ -8,10 +8,7 @@
|
|||
const char Settings::cloudFlareNs1[] = "1.1.1.1";
|
||||
const char Settings::cloudFlareNs2[] = "1.0.0.1";
|
||||
|
||||
|
||||
Settings::Settings(QObject* parent) :
|
||||
QObject(parent),
|
||||
m_settings(ORGANIZATION_NAME, APPLICATION_NAME, this)
|
||||
Settings::Settings(QObject *parent) : QObject(parent), m_settings(ORGANIZATION_NAME, APPLICATION_NAME, this)
|
||||
{
|
||||
// Import old settings
|
||||
if (serversCount() == 0) {
|
||||
|
@ -20,7 +17,7 @@ Settings::Settings(QObject* parent) :
|
|||
QString serverName = m_settings.value("Server/serverName").toString();
|
||||
int port = m_settings.value("Server/serverPort").toInt();
|
||||
|
||||
if (!user.isEmpty() && !password.isEmpty() && !serverName.isEmpty()){
|
||||
if (!user.isEmpty() && !password.isEmpty() && !serverName.isEmpty()) {
|
||||
QJsonObject server;
|
||||
server.insert(config_key::userName, user);
|
||||
server.insert(config_key::password, password);
|
||||
|
@ -46,7 +43,8 @@ int Settings::serversCount() const
|
|||
QJsonObject Settings::server(int index) const
|
||||
{
|
||||
const QJsonArray &servers = serversArray();
|
||||
if (index >= servers.size()) return QJsonObject();
|
||||
if (index >= servers.size())
|
||||
return QJsonObject();
|
||||
|
||||
return servers.at(index).toObject();
|
||||
}
|
||||
|
@ -61,7 +59,8 @@ void Settings::addServer(const QJsonObject &server)
|
|||
void Settings::removeServer(int index)
|
||||
{
|
||||
QJsonArray servers = serversArray();
|
||||
if (index >= servers.size()) return;
|
||||
if (index >= servers.size())
|
||||
return;
|
||||
|
||||
servers.removeAt(index);
|
||||
setServersArray(servers);
|
||||
|
@ -70,7 +69,8 @@ void Settings::removeServer(int index)
|
|||
bool Settings::editServer(int index, const QJsonObject &server)
|
||||
{
|
||||
QJsonArray servers = serversArray();
|
||||
if (index >= servers.size()) return false;
|
||||
if (index >= servers.size())
|
||||
return false;
|
||||
|
||||
servers.replace(index, server);
|
||||
setServersArray(servers);
|
||||
|
@ -94,8 +94,8 @@ QString Settings::defaultContainerName(int serverIndex) const
|
|||
QString name = server(serverIndex).value(config_key::defaultContainer).toString();
|
||||
if (name.isEmpty()) {
|
||||
return ContainerProps::containerToString(DockerContainer::None);
|
||||
}
|
||||
else return name;
|
||||
} else
|
||||
return name;
|
||||
}
|
||||
|
||||
QMap<DockerContainer, QJsonObject> Settings::containers(int serverIndex) const
|
||||
|
@ -104,7 +104,8 @@ QMap<DockerContainer, QJsonObject> Settings::containers(int serverIndex) const
|
|||
|
||||
QMap<DockerContainer, QJsonObject> containersMap;
|
||||
for (const QJsonValue &val : containers) {
|
||||
containersMap.insert(ContainerProps::containerFromString(val.toObject().value(config_key::container).toString()), val.toObject());
|
||||
containersMap.insert(ContainerProps::containerFromString(val.toObject().value(config_key::container).toString()),
|
||||
val.toObject());
|
||||
}
|
||||
|
||||
return containersMap;
|
||||
|
@ -114,17 +115,17 @@ void Settings::setContainers(int serverIndex, const QMap<DockerContainer, QJsonO
|
|||
{
|
||||
QJsonObject s = server(serverIndex);
|
||||
QJsonArray c;
|
||||
for (const QJsonObject &o: containers) {
|
||||
for (const QJsonObject &o : containers) {
|
||||
c.append(o);
|
||||
}
|
||||
s.insert(config_key::containers, c);
|
||||
editServer(serverIndex, s);
|
||||
}
|
||||
|
||||
|
||||
QJsonObject Settings::containerConfig(int serverIndex, DockerContainer container)
|
||||
{
|
||||
if (container == DockerContainer::None) return QJsonObject();
|
||||
if (container == DockerContainer::None)
|
||||
return QJsonObject();
|
||||
return containers(serverIndex).value(container);
|
||||
}
|
||||
|
||||
|
@ -170,7 +171,7 @@ void Settings::clearLastConnectionConfig(int serverIndex, DockerContainer contai
|
|||
{
|
||||
// recursively remove
|
||||
if (proto == Proto::Any) {
|
||||
for (Proto p: ContainerProps::protocolsForContainer(container)) {
|
||||
for (Proto p : ContainerProps::protocolsForContainer(container)) {
|
||||
clearLastConnectionConfig(serverIndex, container, p);
|
||||
}
|
||||
return;
|
||||
|
@ -183,7 +184,8 @@ void Settings::clearLastConnectionConfig(int serverIndex, DockerContainer contai
|
|||
|
||||
bool Settings::haveAuthData(int serverIndex) const
|
||||
{
|
||||
if (serverIndex < 0) return false;
|
||||
if (serverIndex < 0)
|
||||
return false;
|
||||
ServerCredentials cred = serverCredentials(serverIndex);
|
||||
return (!cred.hostName.isEmpty() && !cred.userName.isEmpty() && !cred.secretData.isEmpty());
|
||||
}
|
||||
|
@ -196,7 +198,7 @@ QString Settings::nextAvailableServerName() const
|
|||
do {
|
||||
i++;
|
||||
nameExist = false;
|
||||
for (const QJsonValue &server: serversArray()) {
|
||||
for (const QJsonValue &server : serversArray()) {
|
||||
if (server.toObject().value(config_key::description).toString() == tr("Server") + " " + QString::number(i)) {
|
||||
nameExist = true;
|
||||
break;
|
||||
|
@ -223,19 +225,17 @@ void Settings::setSaveLogs(bool enabled)
|
|||
QString Settings::routeModeString(RouteMode mode) const
|
||||
{
|
||||
switch (mode) {
|
||||
case VpnAllSites:
|
||||
return "AllSites";
|
||||
case VpnOnlyForwardSites:
|
||||
return "ForwardSites";
|
||||
case VpnAllExceptSites:
|
||||
return "ExceptSites";
|
||||
case VpnAllSites: return "AllSites";
|
||||
case VpnOnlyForwardSites: return "ForwardSites";
|
||||
case VpnAllExceptSites: return "ExceptSites";
|
||||
}
|
||||
}
|
||||
|
||||
void Settings::addVpnSite(RouteMode mode, const QString &site, const QString &ip)
|
||||
{
|
||||
QVariantMap sites = vpnSites(mode);
|
||||
if (sites.contains(site) && ip.isEmpty()) return;
|
||||
if (sites.contains(site) && ip.isEmpty())
|
||||
return;
|
||||
|
||||
sites.insert(site, ip);
|
||||
setVpnSites(mode, sites);
|
||||
|
@ -248,7 +248,8 @@ void Settings::addVpnSites(RouteMode mode, const QMap<QString, QString> &sites)
|
|||
const QString &site = i.key();
|
||||
const QString &ip = i.value();
|
||||
|
||||
if (allSites.contains(site) && allSites.value(site) == ip) continue;
|
||||
if (allSites.contains(site) && allSites.value(site) == ip)
|
||||
continue;
|
||||
|
||||
allSites.insert(site, ip);
|
||||
}
|
||||
|
@ -263,8 +264,7 @@ QStringList Settings::getVpnIps(RouteMode mode) const
|
|||
for (auto i = m.constBegin(); i != m.constEnd(); ++i) {
|
||||
if (Utils::checkIpSubnetFormat(i.key())) {
|
||||
ips.append(i.key());
|
||||
}
|
||||
else if (Utils::checkIpSubnetFormat(i.value().toString())) {
|
||||
} else if (Utils::checkIpSubnetFormat(i.value().toString())) {
|
||||
ips.append(i.value().toString());
|
||||
}
|
||||
}
|
||||
|
@ -275,7 +275,8 @@ QStringList Settings::getVpnIps(RouteMode mode) const
|
|||
void Settings::removeVpnSite(RouteMode mode, const QString &site)
|
||||
{
|
||||
QVariantMap sites = vpnSites(mode);
|
||||
if (!sites.contains(site)) return;
|
||||
if (!sites.contains(site))
|
||||
return;
|
||||
|
||||
sites.remove(site);
|
||||
setVpnSites(mode, sites);
|
||||
|
@ -285,7 +286,8 @@ void Settings::addVpnIps(RouteMode mode, const QStringList &ips)
|
|||
{
|
||||
QVariantMap sites = vpnSites(mode);
|
||||
for (const QString &ip : ips) {
|
||||
if (ip.isEmpty()) continue;
|
||||
if (ip.isEmpty())
|
||||
continue;
|
||||
|
||||
sites.insert(ip, "");
|
||||
}
|
||||
|
@ -297,7 +299,8 @@ void Settings::removeVpnSites(RouteMode mode, const QStringList &sites)
|
|||
{
|
||||
QVariantMap sitesMap = vpnSites(mode);
|
||||
for (const QString &site : sites) {
|
||||
if (site.isEmpty()) continue;
|
||||
if (site.isEmpty())
|
||||
continue;
|
||||
|
||||
sitesMap.remove(site);
|
||||
}
|
||||
|
@ -305,9 +308,20 @@ void Settings::removeVpnSites(RouteMode mode, const QStringList &sites)
|
|||
setVpnSites(mode, sitesMap);
|
||||
}
|
||||
|
||||
QString Settings::primaryDns() const { return m_settings.value("Conf/primaryDns", cloudFlareNs1).toString(); }
|
||||
QString Settings::primaryDns() const
|
||||
{
|
||||
return m_settings.value("Conf/primaryDns", cloudFlareNs1).toString();
|
||||
}
|
||||
|
||||
QString Settings::secondaryDns() const { return m_settings.value("Conf/secondaryDns", cloudFlareNs2).toString(); }
|
||||
QString Settings::secondaryDns() const
|
||||
{
|
||||
return m_settings.value("Conf/secondaryDns", cloudFlareNs2).toString();
|
||||
}
|
||||
|
||||
void Settings::clearSettings()
|
||||
{
|
||||
m_settings.clearSettings();
|
||||
}
|
||||
|
||||
ServerCredentials Settings::defaultServerCredentials() const
|
||||
{
|
||||
|
|
|
@ -183,6 +183,8 @@ public:
|
|||
m_settings.setValue("Conf/appLanguage", locale);
|
||||
};
|
||||
|
||||
void clearSettings();
|
||||
|
||||
signals:
|
||||
void saveLogsChanged();
|
||||
|
||||
|
|
|
@ -16,12 +16,19 @@ InstallController::InstallController(const QSharedPointer<ServersModel> &servers
|
|||
void InstallController::install(DockerContainer container, int port, TransportProto transportProto)
|
||||
{
|
||||
Proto mainProto = ContainerProps::defaultProtocol(container);
|
||||
QJsonObject containerConfig;
|
||||
|
||||
QJsonObject containerConfig { { config_key::port, QString::number(port) },
|
||||
{ config_key::transport_proto,
|
||||
ProtocolProps::transportProtoToString(transportProto, mainProto) } };
|
||||
QJsonObject config { { config_key::container, ContainerProps::containerToString(container) },
|
||||
{ ProtocolProps::protoToString(mainProto), containerConfig } };
|
||||
containerConfig.insert(config_key::port, QString::number(port));
|
||||
containerConfig.insert(config_key::transport_proto, ProtocolProps::transportProtoToString(transportProto, mainProto));
|
||||
|
||||
if (container == DockerContainer::Sftp) {
|
||||
containerConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
|
||||
containerConfig.insert(config_key::password, Utils::getRandomString(10));
|
||||
}
|
||||
|
||||
QJsonObject config;
|
||||
config.insert(config_key::container, ContainerProps::containerToString(container));
|
||||
config.insert(ProtocolProps::protoToString(mainProto), containerConfig);
|
||||
|
||||
if (m_shouldCreateServer) {
|
||||
if (isServerAlreadyExists()) {
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace PageLoader
|
|||
PageSettingsApplication,
|
||||
PageSettingsBackup,
|
||||
PageSettingsAbout,
|
||||
PageSettingsLogging,
|
||||
|
||||
PageSetupWizardStart,
|
||||
PageSetupWizardCredentials,
|
||||
|
|
|
@ -46,14 +46,15 @@ void SettingsController::setSecondaryDns(const QString &dns)
|
|||
emit secondaryDnsChanged();
|
||||
}
|
||||
|
||||
bool SettingsController::isSaveLogsEnabled()
|
||||
bool SettingsController::isLoggingEnable()
|
||||
{
|
||||
return m_settings->isSaveLogs();
|
||||
}
|
||||
|
||||
void SettingsController::setSaveLogs(bool enable)
|
||||
void SettingsController::toggleLogging(bool enable)
|
||||
{
|
||||
m_settings->setSaveLogs(enable);
|
||||
emit loggingStateChanged();
|
||||
}
|
||||
|
||||
void SettingsController::openLogsFolder()
|
||||
|
@ -101,3 +102,8 @@ QString SettingsController::getAppVersion()
|
|||
{
|
||||
return m_appVersion;
|
||||
}
|
||||
|
||||
void SettingsController::clearSettings()
|
||||
{
|
||||
m_settings->clearSettings();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ public:
|
|||
|
||||
Q_PROPERTY(QString primaryDns READ getPrimaryDns WRITE setPrimaryDns NOTIFY primaryDnsChanged)
|
||||
Q_PROPERTY(QString secondaryDns READ getSecondaryDns WRITE setSecondaryDns NOTIFY secondaryDnsChanged)
|
||||
Q_PROPERTY(bool isLoggingEnable READ isLoggingEnable WRITE toggleLogging NOTIFY loggingStateChanged)
|
||||
|
||||
public slots:
|
||||
void setAmneziaDns(bool enable);
|
||||
|
@ -27,8 +28,8 @@ public slots:
|
|||
QString getSecondaryDns();
|
||||
void setSecondaryDns(const QString &dns);
|
||||
|
||||
bool isSaveLogsEnabled();
|
||||
void setSaveLogs(bool enable);
|
||||
bool isLoggingEnable();
|
||||
void toggleLogging(bool enable);
|
||||
|
||||
void openLogsFolder();
|
||||
void exportLogsFile();
|
||||
|
@ -39,9 +40,12 @@ public slots:
|
|||
|
||||
QString getAppVersion();
|
||||
|
||||
void clearSettings();
|
||||
|
||||
signals:
|
||||
void primaryDnsChanged();
|
||||
void secondaryDnsChanged();
|
||||
void loggingStateChanged();
|
||||
|
||||
private:
|
||||
QSharedPointer<ServersModel> m_serversModel;
|
||||
|
|
|
@ -54,3 +54,8 @@ int LanguageModel::getCurrentLanguageIndex()
|
|||
default: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::English); break;
|
||||
}
|
||||
}
|
||||
|
||||
QString LanguageModel::getCurrentLanuageName()
|
||||
{
|
||||
return m_availableLanguages[getCurrentLanguageIndex()].name;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ public:
|
|||
public slots:
|
||||
void changeLanguage(const LanguageSettings::AvailableLanguageEnum language);
|
||||
int getCurrentLanguageIndex();
|
||||
QString getCurrentLanuageName();
|
||||
|
||||
signals:
|
||||
void updateTranslations(const QLocale &locale);
|
||||
|
|
|
@ -89,7 +89,7 @@ void ServerContainersLogic::onPushButtonRemoveClicked(DockerContainer container)
|
|||
void ServerContainersLogic::onPushButtonContinueClicked(DockerContainer c, int port, TransportProto tp)
|
||||
{
|
||||
ServerController serverController(m_settings);
|
||||
QJsonObject config = serverController.createContainerInitialConfig(c, port, tp);
|
||||
QJsonObject config; // = serverController.createContainerInitialConfig(c, port, tp);
|
||||
|
||||
emit uiLogic()->goToPage(Page::ServerConfiguringProgress);
|
||||
qApp->processEvents();
|
||||
|
|
|
@ -17,14 +17,16 @@ Item {
|
|||
|
||||
property string textColor: "#d7d8db"
|
||||
|
||||
implicitWidth: content.implicitWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin
|
||||
implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin
|
||||
|
||||
RowLayout {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
anchors.topMargin: 16
|
||||
anchors.bottomMargin: 16
|
||||
|
||||
Rectangle {
|
||||
id: leftImageBackground
|
||||
|
@ -56,8 +58,6 @@ Item {
|
|||
color: root.textColor
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.bottomMargin: description.visible ? 0 : 16
|
||||
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
@ -72,7 +72,6 @@ Item {
|
|||
visible: root.descriptionText !== ""
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
|
|
@ -48,6 +48,7 @@ PageType {
|
|||
Layout.topMargin: 16
|
||||
|
||||
text: qsTr("Language")
|
||||
descriptionText: LanguageModel.getCurrentLanuageName()
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
|
@ -60,6 +61,22 @@ PageType {
|
|||
}
|
||||
|
||||
|
||||
DividerType {}
|
||||
|
||||
LabelWithButtonType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Logging")
|
||||
descriptionText: SettingsController.isLoggingEnable ? qsTr("Enabled") : qsTr("Disabled")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
goToPage(PageEnum.PageSettingsLogging)
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
LabelWithButtonType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
|
@ -67,10 +84,27 @@ PageType {
|
|||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
questionDrawer.headerText = qsTr("Reset settings and remove all data from the application?")
|
||||
questionDrawer.descriptionText = qsTr("All settings will be reset to default. All installed AmneziaVPN services will still remain on the server.")
|
||||
questionDrawer.yesButtonText = qsTr("Continue")
|
||||
questionDrawer.noButtonText = qsTr("Cancel")
|
||||
|
||||
questionDrawer.yesButtonFunction = function() {
|
||||
questionDrawer.visible = false
|
||||
SettingsController.clearSettings()
|
||||
}
|
||||
questionDrawer.noButtonFunction = function() {
|
||||
questionDrawer.visible = false
|
||||
}
|
||||
questionDrawer.visible = true
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
QuestionDrawer {
|
||||
id: questionDrawer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,96 +44,6 @@ PageType {
|
|||
headerText: qsTr("Backup")
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
text: qsTr("Save logs")
|
||||
|
||||
checked: SettingsController.isSaveLogsEnabled()
|
||||
onCheckedChanged: {
|
||||
if (checked !== SettingsController.isSaveLogsEnabled()) {
|
||||
SettingsController.setSaveLogs(checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignBaseline
|
||||
Layout.preferredWidth: root.width / 3
|
||||
|
||||
ImageButtonType {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
implicitWidth: 56
|
||||
implicitHeight: 56
|
||||
|
||||
image: "qrc:/images/controls/folder-open.svg"
|
||||
|
||||
onClicked: SettingsController.openLogsFolder()
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Open folder with logs")
|
||||
color: "#D7D8DB"
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignBaseline
|
||||
Layout.preferredWidth: root.width / 3
|
||||
|
||||
ImageButtonType {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
implicitWidth: 56
|
||||
implicitHeight: 56
|
||||
|
||||
image: "qrc:/images/controls/save.svg"
|
||||
|
||||
onClicked: SettingsController.exportLogsFile()
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Save logs to file")
|
||||
color: "#D7D8DB"
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignBaseline
|
||||
Layout.preferredWidth: root.width / 3
|
||||
|
||||
ImageButtonType {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
implicitWidth: 56
|
||||
implicitHeight: 56
|
||||
|
||||
image: "qrc:/images/controls/delete.svg"
|
||||
|
||||
onClicked: SettingsController.clearLogs()
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Clear logs")
|
||||
color: "#D7D8DB"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListItemTitleType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 10
|
||||
|
|
138
client/ui/qml/Pages2/PageSettingsLogging.qml
Normal file
138
client/ui/qml/Pages2/PageSettingsLogging.qml
Normal file
|
@ -0,0 +1,138 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import PageEnum 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Config"
|
||||
import "../Controls2/TextTypes"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.height
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
|
||||
spacing: 16
|
||||
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("Logging")
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
text: qsTr("Save logs")
|
||||
|
||||
checked: SettingsController.isLoggingEnable
|
||||
onCheckedChanged: {
|
||||
if (checked !== SettingsController.isLoggingEnable) {
|
||||
SettingsController.isLoggingEnable = checked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignBaseline
|
||||
Layout.preferredWidth: root.width / 3
|
||||
|
||||
ImageButtonType {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
implicitWidth: 56
|
||||
implicitHeight: 56
|
||||
|
||||
image: "qrc:/images/controls/folder-open.svg"
|
||||
|
||||
onClicked: SettingsController.openLogsFolder()
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Open folder with logs")
|
||||
color: "#D7D8DB"
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignBaseline
|
||||
Layout.preferredWidth: root.width / 3
|
||||
|
||||
ImageButtonType {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
implicitWidth: 56
|
||||
implicitHeight: 56
|
||||
|
||||
image: "qrc:/images/controls/save.svg"
|
||||
|
||||
onClicked: SettingsController.exportLogsFile()
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Save logs to file")
|
||||
color: "#D7D8DB"
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignBaseline
|
||||
Layout.preferredWidth: root.width / 3
|
||||
|
||||
ImageButtonType {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
implicitWidth: 56
|
||||
implicitHeight: 56
|
||||
|
||||
image: "qrc:/images/controls/delete.svg"
|
||||
|
||||
onClicked: SettingsController.clearLogs()
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Clear logs")
|
||||
color: "#D7D8DB"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue